Enabled reading of multiple sectors.
[reactos.git] / reactos / drivers / storage / scsiport / scsiport.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2001, 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: scsiport.c,v 1.9 2002/03/04 22:31:51 ekohl Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/scsiport/scsiport.c
24 * PURPOSE: SCSI port driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include "../include/srb.h"
32 #include "../include/scsi.h"
33 #include "../include/ntddscsi.h"
34
35 #define NDEBUG
36 #include <debug.h>
37
38
39 #define VERSION "0.0.1"
40
41
42 /* TYPES *********************************************************************/
43
44
45 typedef enum _SCSI_PORT_TIMER_STATES
46 {
47 IDETimerIdle,
48 IDETimerCmdWait,
49 IDETimerResetWaitForBusyNegate,
50 IDETimerResetWaitForDrdyAssert
51 } SCSI_PORT_TIMER_STATES;
52
53
54 /*
55 * SCSI_PORT_DEVICE_EXTENSION
56 *
57 * DESCRIPTION
58 * First part of the port objects device extension. The second
59 * part is the miniport-specific device extension.
60 */
61
62 typedef struct _SCSI_PORT_DEVICE_EXTENSION
63 {
64 ULONG Length;
65 ULONG MiniPortExtensionSize;
66 PORT_CONFIGURATION_INFORMATION PortConfig;
67
68 KSPIN_LOCK SpinLock;
69 PKINTERRUPT Interrupt;
70 PIRP CurrentIrp;
71 ULONG IrpFlags;
72
73 SCSI_PORT_TIMER_STATES TimerState;
74 LONG TimerCount;
75
76 BOOLEAN Initializing;
77
78 ULONG PortBusInfoSize;
79 PSCSI_ADAPTER_BUS_INFO PortBusInfo;
80
81 PDEVICE_OBJECT DeviceObject;
82 PCONTROLLER_OBJECT ControllerObject;
83
84 PHW_STARTIO HwStartIo;
85 PHW_INTERRUPT HwInterrupt;
86
87 UCHAR MiniPortDeviceExtension[1]; /* must be the last entry */
88 } SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION;
89
90
91 /*
92 * SCSI_PORT_TIMER_STATES
93 *
94 * DESCRIPTION
95 * An enumeration containing the states in the timer DFA
96 */
97
98
99
100 #define IRP_FLAG_COMPLETE 0x00000001
101 #define IRP_FLAG_NEXT 0x00000002
102
103 /* GLOBALS *******************************************************************/
104
105
106 static NTSTATUS STDCALL
107 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
108 IN PIRP Irp);
109
110 static NTSTATUS STDCALL
111 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
112 IN PIRP Irp);
113
114 static NTSTATUS STDCALL
115 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
116 IN PIRP Irp);
117
118 static NTSTATUS STDCALL
119 ScsiPortReadWrite(IN PDEVICE_OBJECT DeviceObject,
120 IN PIRP Irp);
121
122 static VOID STDCALL
123 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
124 IN PIRP Irp);
125
126 static IO_ALLOCATION_ACTION STDCALL
127 ScsiPortAllocateController(IN PDEVICE_OBJECT DeviceObject,
128 IN PIRP Irp,
129 IN PVOID MapRegisterBase,
130 IN PVOID Context);
131
132 static BOOLEAN STDCALL
133 ScsiPortStartController(IN OUT PVOID Context);
134
135 static NTSTATUS
136 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
137 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
138 IN ULONG PortCount);
139
140 static VOID
141 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
142
143 static BOOLEAN STDCALL
144 ScsiPortIsr(IN PKINTERRUPT Interrupt,
145 IN PVOID ServiceContext);
146
147 static VOID STDCALL
148 ScsiPortDpcForIsr(IN PKDPC Dpc,
149 IN PDEVICE_OBJECT DpcDeviceObject,
150 IN PIRP DpcIrp,
151 IN PVOID DpcContext);
152
153 static VOID STDCALL
154 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
155 PVOID Context);
156
157
158 /* FUNCTIONS *****************************************************************/
159
160 /**********************************************************************
161 * NAME EXPORTED
162 * DriverEntry
163 *
164 * DESCRIPTION
165 * This function initializes the driver.
166 *
167 * RUN LEVEL
168 * PASSIVE_LEVEL
169 *
170 * ARGUMENTS
171 * DriverObject
172 * System allocated Driver Object for this driver.
173 *
174 * RegistryPath
175 * Name of registry driver service key.
176 *
177 * RETURN VALUE
178 * Status.
179 */
180
181 NTSTATUS STDCALL
182 DriverEntry(IN PDRIVER_OBJECT DriverObject,
183 IN PUNICODE_STRING RegistryPath)
184 {
185 DbgPrint("ScsiPort Driver %s\n", VERSION);
186 return(STATUS_SUCCESS);
187 }
188
189
190 /**********************************************************************
191 * NAME EXPORTED
192 * ScsiDebugPrint
193 *
194 * DESCRIPTION
195 * Prints debugging messages.
196 *
197 * RUN LEVEL
198 * PASSIVE_LEVEL
199 *
200 * ARGUMENTS
201 * DebugPrintLevel
202 * Debug level of the given message.
203 *
204 * DebugMessage
205 * Pointer to printf()-compatible format string.
206 *
207 * ...
208 Additional output data (see printf()).
209 *
210 * RETURN VALUE
211 * None.
212 */
213
214 VOID
215 ScsiDebugPrint(IN ULONG DebugPrintLevel,
216 IN PCHAR DebugMessage,
217 ...)
218 {
219 char Buffer[256];
220 va_list ap;
221
222 #if 0
223 if (DebugPrintLevel > InternalDebugLevel)
224 return;
225 #endif
226
227 va_start(ap, DebugMessage);
228 vsprintf(Buffer, DebugMessage, ap);
229 va_end(ap);
230
231 DbgPrint(Buffer);
232 }
233
234
235 VOID STDCALL
236 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
237 IN UCHAR PathId,
238 IN UCHAR TargetId,
239 IN UCHAR Lun,
240 IN UCHAR SrbStatus)
241 {
242 UNIMPLEMENTED;
243 }
244
245
246 ULONG STDCALL
247 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
248 {
249 return Address.u.LowPart;
250 }
251
252
253 VOID STDCALL
254 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
255 {
256 UNIMPLEMENTED;
257 }
258
259
260 VOID STDCALL
261 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
262 IN PVOID MappedAddress)
263 {
264 UNIMPLEMENTED;
265 }
266
267
268 ULONG STDCALL
269 ScsiPortGetBusData(IN PVOID DeviceExtension,
270 IN ULONG BusDataType,
271 IN ULONG SystemIoBusNumber,
272 IN ULONG SlotNumber,
273 IN PVOID Buffer,
274 IN ULONG Length)
275 {
276 return(HalGetBusData(BusDataType,
277 SystemIoBusNumber,
278 SlotNumber,
279 Buffer,
280 Length));
281 }
282
283
284 PVOID STDCALL
285 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
286 IN INTERFACE_TYPE BusType,
287 IN ULONG SystemIoBusNumber,
288 IN SCSI_PHYSICAL_ADDRESS IoAddress,
289 IN ULONG NumberOfBytes,
290 IN BOOLEAN InIoSpace)
291 {
292 ULONG AddressSpace;
293 PHYSICAL_ADDRESS TranslatedAddress;
294 PVOID VirtualAddress;
295 PVOID Buffer;
296 BOOLEAN rc;
297
298 AddressSpace = (ULONG)InIoSpace;
299
300 if (!HalTranslateBusAddress(BusType,
301 SystemIoBusNumber,
302 IoAddress,
303 &AddressSpace,
304 &TranslatedAddress))
305 return NULL;
306
307 /* i/o space */
308 if (AddressSpace != 0)
309 return (PVOID)TranslatedAddress.u.LowPart;
310
311 VirtualAddress = MmMapIoSpace(TranslatedAddress,
312 NumberOfBytes,
313 FALSE);
314
315 Buffer = ExAllocatePool(NonPagedPool,0x20);
316 if (Buffer == NULL)
317 return VirtualAddress;
318
319 return NULL; /* ?? */
320 }
321
322
323 PVOID STDCALL
324 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
325 IN UCHAR PathId,
326 IN UCHAR TargetId,
327 IN UCHAR Lun)
328 {
329 UNIMPLEMENTED;
330 }
331
332
333 SCSI_PHYSICAL_ADDRESS STDCALL
334 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
335 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
336 IN PVOID VirtualAddress,
337 OUT ULONG *Length)
338 {
339 UNIMPLEMENTED;
340 }
341
342
343 PSCSI_REQUEST_BLOCK STDCALL
344 ScsiPortGetSrb(IN PVOID DeviceExtension,
345 IN UCHAR PathId,
346 IN UCHAR TargetId,
347 IN UCHAR Lun,
348 IN LONG QueueTag)
349 {
350 UNIMPLEMENTED;
351 }
352
353
354 PVOID STDCALL
355 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
356 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
357 IN ULONG NumberOfBytes)
358 {
359 UNIMPLEMENTED;
360 }
361
362
363 PVOID STDCALL
364 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
365 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
366 {
367 UNIMPLEMENTED;
368 }
369
370
371 /**********************************************************************
372 * NAME EXPORTED
373 * ScsiPortInitialize
374 *
375 * DESCRIPTION
376 * Initializes SCSI port driver specific data.
377 *
378 * RUN LEVEL
379 * PASSIVE_LEVEL
380 *
381 * ARGUMENTS
382 * Argument1
383 * Pointer to the miniport driver's driver object.
384 *
385 * Argument2
386 * Pointer to the miniport driver's registry path.
387 *
388 * HwInitializationData
389 * Pointer to port driver specific configuration data.
390 *
391 * HwContext
392 Miniport driver specific context.
393 *
394 * RETURN VALUE
395 * Status.
396 */
397
398 ULONG STDCALL
399 ScsiPortInitialize(IN PVOID Argument1,
400 IN PVOID Argument2,
401 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
402 IN PVOID HwContext)
403 {
404 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
405 PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
406 PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension;
407 PCONFIGURATION_INFORMATION SystemConfig;
408 PPORT_CONFIGURATION_INFORMATION PortConfig;
409 BOOLEAN Again;
410 ULONG i;
411 ULONG Result;
412 NTSTATUS Status;
413 ULONG MaxBus;
414 PACCESS_RANGE AccessRanges;
415 ULONG ExtensionSize;
416
417 DPRINT1("ScsiPortInitialize() called!\n");
418
419 if ((HwInitializationData->HwInitialize == NULL) ||
420 (HwInitializationData->HwStartIo == NULL) ||
421 (HwInitializationData->HwInterrupt == NULL) ||
422 (HwInitializationData->HwFindAdapter == NULL) ||
423 (HwInitializationData->HwResetBus == NULL))
424 return(STATUS_INVALID_PARAMETER);
425
426 DriverObject->DriverStartIo = ScsiPortStartIo;
427 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
428 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
429 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
430 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
431 // DriverObject->MajorFunction[IRP_MJ_READ] = ScsiPortReadWrite;
432 // DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiPortReadWrite;
433
434 // DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = IDEDispatchQueryInformation;
435 // DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = IDEDispatchSetInformation;
436
437
438
439
440 SystemConfig = IoGetConfigurationInformation();
441
442 ExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
443 HwInitializationData->DeviceExtensionSize;
444 PseudoDeviceExtension = ExAllocatePool(PagedPool,
445 ExtensionSize);
446 RtlZeroMemory(PseudoDeviceExtension,
447 ExtensionSize);
448 PseudoDeviceExtension->Length = ExtensionSize;
449 PseudoDeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
450 PseudoDeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
451 PseudoDeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
452
453 PortConfig = &PseudoDeviceExtension->PortConfig;
454
455 PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
456 PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
457 PortConfig->InterruptMode =
458 (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
459 PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
460 PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
461 PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
462
463 PortConfig->AccessRanges =
464 ExAllocatePool(PagedPool,
465 sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
466
467
468 PortConfig->SystemIoBusNumber = 0;
469 PortConfig->SlotNumber = 0;
470
471 MaxBus = (PortConfig->AdapterInterfaceType == PCIBus) ? 8 : 1;
472
473 DPRINT("MaxBus: %lu\n", MaxBus);
474
475 while (TRUE)
476 {
477 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
478
479 // RtlZeroMemory(AccessRanges,
480 // sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
481
482 /* Note: HwFindAdapter is called once for each bus */
483 Result = (HwInitializationData->HwFindAdapter)(&PseudoDeviceExtension->MiniPortDeviceExtension,
484 HwContext,
485 NULL, /* BusInformation */
486 NULL, /* ArgumentString */
487 &PseudoDeviceExtension->PortConfig,
488 &Again);
489 DPRINT("HwFindAdapter() result: %lu\n", Result);
490
491 if (Result == SP_RETURN_FOUND)
492 {
493 DPRINT("ScsiPortInitialize(): Found HBA!\n");
494
495 Status = ScsiPortCreatePortDevice(DriverObject,
496 PseudoDeviceExtension,
497 SystemConfig->ScsiPortCount);
498
499 if (!NT_SUCCESS(Status))
500 {
501 DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status);
502
503 ExFreePool(PortConfig->AccessRanges);
504 ExFreePool(PseudoDeviceExtension);
505
506 return(Status);
507 }
508
509 /* Update the configuration info */
510 SystemConfig->AtDiskPrimaryAddressClaimed = PortConfig->AtdiskPrimaryClaimed;
511 SystemConfig->AtDiskSecondaryAddressClaimed = PortConfig->AtdiskSecondaryClaimed;
512 SystemConfig->ScsiPortCount++;
513 }
514
515 if (Again == FALSE)
516 {
517 PortConfig->SystemIoBusNumber++;
518 PortConfig->SlotNumber = 0;
519 }
520
521 DPRINT("Bus: %lu MaxBus: %lu\n", PortConfig->SystemIoBusNumber, MaxBus);
522 if (PortConfig->SystemIoBusNumber >= MaxBus)
523 {
524 DPRINT1("Scanned all buses!\n");
525 break;
526 }
527 }
528
529 ExFreePool(PortConfig->AccessRanges);
530 ExFreePool(PseudoDeviceExtension);
531
532 DPRINT1("ScsiPortInitialize() done!\n");
533
534 return(STATUS_SUCCESS);
535 }
536
537
538 VOID STDCALL
539 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
540 IN PSCSI_REQUEST_BLOCK Srb,
541 IN ULONG LogicalAddress,
542 IN ULONG Length)
543 {
544 UNIMPLEMENTED;
545 }
546
547
548 VOID STDCALL
549 ScsiPortLogError(IN PVOID HwDeviceExtension,
550 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
551 IN UCHAR PathId,
552 IN UCHAR TargetId,
553 IN UCHAR Lun,
554 IN ULONG ErrorCode,
555 IN ULONG UniqueId)
556 {
557 UNIMPLEMENTED;
558 }
559
560
561 VOID STDCALL
562 ScsiPortMoveMemory(OUT PVOID Destination,
563 IN PVOID Source,
564 IN ULONG Length)
565 {
566 RtlMoveMemory(Destination,
567 Source,
568 Length);
569 }
570
571
572 VOID
573 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
574 IN PVOID HwDeviceExtension,
575 ...)
576 {
577 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
578
579 DPRINT1("ScsiPortNotification() called\n");
580
581 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
582 SCSI_PORT_DEVICE_EXTENSION,
583 MiniPortDeviceExtension);
584
585 DPRINT1("DeviceExtension %p\n", DeviceExtension);
586
587 DPRINT1("Initializing = %s\n", (DeviceExtension->Initializing)?"TRUE":"FALSE");
588
589 if (DeviceExtension->Initializing == TRUE)
590 return;
591
592 switch (NotificationType)
593 {
594 case RequestComplete:
595 DPRINT1("Notify: RequestComplete\n");
596 DeviceExtension->IrpFlags |= IRP_FLAG_COMPLETE;
597 break;
598
599 case NextRequest:
600 DPRINT1("Notify: NextRequest\n");
601 DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
602 break;
603
604 default:
605 break;
606 }
607 }
608
609
610 ULONG STDCALL
611 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
612 IN ULONG BusDataType,
613 IN ULONG SystemIoBusNumber,
614 IN ULONG SlotNumber,
615 IN PVOID Buffer,
616 IN ULONG Offset,
617 IN ULONG Length)
618 {
619 return(HalSetBusDataByOffset(BusDataType,
620 SystemIoBusNumber,
621 SlotNumber,
622 Buffer,
623 Offset,
624 Length));
625 }
626
627
628 BOOLEAN STDCALL
629 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
630 IN INTERFACE_TYPE BusType,
631 IN ULONG SystemIoBusNumber,
632 IN SCSI_PHYSICAL_ADDRESS IoAddress,
633 IN ULONG NumberOfBytes,
634 IN BOOLEAN InIoSpace)
635 {
636 return(TRUE);
637 }
638
639
640 /* INTERNAL FUNCTIONS ********************************************************/
641
642 /**********************************************************************
643 * NAME INTERNAL
644 * ScsiPortCreateClose
645 *
646 * DESCRIPTION
647 * Answer requests for Create/Close calls: a null operation.
648 *
649 * RUN LEVEL
650 * PASSIVE_LEVEL
651 *
652 * ARGUMENTS
653 * DeviceObject
654 * Pointer to a device object.
655 *
656 * Irp
657 * Pointer to an IRP.
658 *
659 * ...
660 Additional output data (see printf()).
661 *
662 * RETURN VALUE
663 * Status.
664 */
665
666 static NTSTATUS STDCALL
667 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
668 IN PIRP Irp)
669 {
670 DPRINT("ScsiPortCreateClose()\n");
671
672 Irp->IoStatus.Status = STATUS_SUCCESS;
673 Irp->IoStatus.Information = FILE_OPENED;
674
675 IoCompleteRequest(Irp, IO_NO_INCREMENT);
676
677 return(STATUS_SUCCESS);
678 }
679
680
681 /**********************************************************************
682 * NAME INTERNAL
683 * ScsiPortDispatchScsi
684 *
685 * DESCRIPTION
686 * Answer requests for SCSI calls
687 *
688 * RUN LEVEL
689 * PASSIVE_LEVEL
690 *
691 * ARGUMENTS
692 * Standard dispatch arguments
693 *
694 * RETURNS
695 * NTSTATUS
696 */
697
698 static NTSTATUS STDCALL
699 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
700 IN PIRP Irp)
701 {
702 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
703 PIO_STACK_LOCATION Stack;
704 PSCSI_REQUEST_BLOCK Srb;
705 NTSTATUS Status = STATUS_SUCCESS;
706 ULONG DataSize = 0;
707
708
709 DPRINT1("ScsiPortDispatchScsi()\n");
710
711 DeviceExtension = DeviceObject->DeviceExtension;
712 Stack = IoGetCurrentIrpStackLocation(Irp);
713
714 DeviceExtension->IrpFlags = 0;
715
716 switch(Stack->Parameters.DeviceIoControl.IoControlCode)
717 {
718 case IOCTL_SCSI_EXECUTE_IN:
719 {
720 DPRINT(" IOCTL_SCSI_EXECUTE_IN\n");
721 }
722 break;
723
724 case IOCTL_SCSI_EXECUTE_OUT:
725 {
726 DPRINT(" IOCTL_SCSI_EXECUTE_OUT\n");
727 }
728 break;
729
730 case IOCTL_SCSI_EXECUTE_NONE:
731 {
732 DPRINT(" IOCTL_SCSI_EXECUTE_NONE\n");
733 }
734 break;
735 }
736
737 Srb = Stack->Parameters.Scsi.Srb;
738 if (Srb == NULL)
739 {
740
741 Status = STATUS_UNSUCCESSFUL;
742
743
744 Irp->IoStatus.Status = Status;
745 Irp->IoStatus.Information = 0;
746
747 IoCompleteRequest(Irp, IO_NO_INCREMENT);
748
749 return(Status);
750 }
751
752 DPRINT("Srb: %p\n", Srb);
753 DPRINT("Srb->Function: %lu\n", Srb->Function);
754
755 switch (Srb->Function)
756 {
757 case SRB_FUNCTION_EXECUTE_SCSI:
758 DPRINT1(" SRB_FUNCTION_EXECUTE_SCSI\n");
759 IoStartPacket(DeviceObject, Irp, NULL, NULL);
760 DPRINT1("Returning STATUS_PENDING\n");
761 return(STATUS_PENDING);
762
763 case SRB_FUNCTION_CLAIM_DEVICE:
764 {
765 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
766 PSCSI_INQUIRY_DATA UnitInfo;
767 PINQUIRYDATA InquiryData;
768
769 DPRINT(" SRB_FUNCTION_CLAIM_DEVICE\n");
770
771 if (DeviceExtension->PortBusInfo != NULL)
772 {
773 AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
774
775 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
776 AdapterInfo->BusData[Srb->PathId].InquiryDataOffset);
777
778 while (AdapterInfo->BusData[Srb->PathId].InquiryDataOffset)
779 {
780 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
781
782 if ((UnitInfo->TargetId == Srb->TargetId) &&
783 (UnitInfo->Lun == Srb->Lun) &&
784 (UnitInfo->DeviceClaimed == FALSE))
785 {
786 UnitInfo->DeviceClaimed = TRUE;
787 DPRINT("Claimed device!\n");
788 break;
789 }
790
791 if (UnitInfo->NextInquiryDataOffset == 0)
792 break;
793
794 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo + UnitInfo->NextInquiryDataOffset);
795 }
796 }
797
798 /* FIXME: Hack!!!!! */
799 Srb->DataBuffer = DeviceObject;
800 }
801 break;
802
803 case SRB_FUNCTION_RELEASE_DEVICE:
804 {
805 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
806 PSCSI_INQUIRY_DATA UnitInfo;
807 PINQUIRYDATA InquiryData;
808
809 DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n");
810
811 if (DeviceExtension->PortBusInfo != NULL)
812 {
813 AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
814
815 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
816 AdapterInfo->BusData[Srb->PathId].InquiryDataOffset);
817
818
819 while (AdapterInfo->BusData[Srb->PathId].InquiryDataOffset)
820 {
821 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
822
823 if ((UnitInfo->TargetId == Srb->TargetId) &&
824 (UnitInfo->Lun == Srb->Lun) &&
825 (UnitInfo->DeviceClaimed == TRUE))
826 {
827 UnitInfo->DeviceClaimed = FALSE;
828 DPRINT("Released device!\n");
829 break;
830 }
831
832 if (UnitInfo->NextInquiryDataOffset == 0)
833 break;
834
835 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo + UnitInfo->NextInquiryDataOffset);
836 }
837 }
838 }
839 break;
840 }
841
842 Irp->IoStatus.Status = Status;
843 Irp->IoStatus.Information = DataSize;
844
845 IoCompleteRequest(Irp, IO_NO_INCREMENT);
846
847 return(Status);
848 }
849
850
851 /**********************************************************************
852 * NAME INTERNAL
853 * ScsiPortDeviceControl
854 *
855 * DESCRIPTION
856 * Answer requests for device control calls
857 *
858 * RUN LEVEL
859 * PASSIVE_LEVEL
860 *
861 * ARGUMENTS
862 * Standard dispatch arguments
863 *
864 * RETURNS
865 * NTSTATUS
866 */
867
868 static NTSTATUS STDCALL
869 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
870 IN PIRP Irp)
871 {
872 PIO_STACK_LOCATION Stack;
873 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
874
875 DPRINT1("ScsiPortDeviceControl()\n");
876
877 Irp->IoStatus.Status = STATUS_SUCCESS;
878 Irp->IoStatus.Information = 0;
879
880
881 Stack = IoGetCurrentIrpStackLocation(Irp);
882 DeviceExtension = DeviceObject->DeviceExtension;
883
884 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
885 {
886
887 case IOCTL_SCSI_GET_CAPABILITIES:
888 {
889 PIO_SCSI_CAPABILITIES Capabilities;
890
891 DPRINT1(" IOCTL_SCSI_GET_CAPABILITIES\n");
892
893 Capabilities = (PIO_SCSI_CAPABILITIES)Irp->AssociatedIrp.SystemBuffer;
894 Capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
895 Capabilities->MaximumTransferLength =
896 DeviceExtension->PortConfig.MaximumTransferLength;
897 Capabilities->MaximumPhysicalPages = 1;
898 Capabilities->SupportedAsynchronousEvents = 0;
899 Capabilities->AlignmentMask =
900 DeviceExtension->PortConfig.AlignmentMask;
901 Capabilities->TaggedQueuing =
902 DeviceExtension->PortConfig.TaggedQueuing;
903 Capabilities->AdapterScansDown =
904 DeviceExtension->PortConfig.AdapterScansDown;
905 Capabilities->AdapterUsesPio = TRUE;
906
907 Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
908 }
909 break;
910
911 case IOCTL_SCSI_GET_INQUIRY_DATA:
912 {
913 DPRINT1(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
914
915 /* Copy inquiry data to the port device extension */
916 memcpy(Irp->AssociatedIrp.SystemBuffer,
917 DeviceExtension->PortBusInfo,
918 DeviceExtension->PortBusInfoSize);
919
920 DPRINT1("BufferSize: %lu\n", DeviceExtension->PortBusInfoSize);
921 Irp->IoStatus.Information = DeviceExtension->PortBusInfoSize;
922 }
923 break;
924
925 default:
926 DPRINT1(" unknown ioctl code: 0x%lX\n",
927 Stack->Parameters.DeviceIoControl.IoControlCode);
928 break;
929 }
930
931 IoCompleteRequest(Irp, IO_NO_INCREMENT);
932
933 return(STATUS_SUCCESS);
934 }
935
936
937 static NTSTATUS STDCALL
938 ScsiPortReadWrite(IN PDEVICE_OBJECT DeviceObject,
939 IN PIRP Irp)
940 {
941 NTSTATUS Status;
942
943 DPRINT("ScsiPortReadWrite() called!\n");
944
945 Status = STATUS_SUCCESS;
946
947 Irp->IoStatus.Status = Status;
948 Irp->IoStatus.Information = 0;
949
950 IoCompleteRequest(Irp, IO_NO_INCREMENT);
951
952 return(Status);
953 }
954
955
956
957
958 static VOID STDCALL
959 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
960 IN PIRP Irp)
961 {
962 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
963 PIO_STACK_LOCATION IrpStack;
964 KIRQL OldIrql;
965
966 DPRINT1("ScsiPortStartIo() called!\n");
967
968 DeviceExtension = DeviceObject->DeviceExtension;
969 IrpStack = IoGetCurrentIrpStackLocation(Irp);
970
971 // FIXME: implement the supported functions
972
973 switch (IrpStack->MajorFunction)
974 {
975 case IRP_MJ_SCSI:
976 {
977 BOOLEAN Result;
978 PSCSI_REQUEST_BLOCK Srb;
979
980 DPRINT("IRP_MJ_SCSI\n");
981
982 Srb = IrpStack->Parameters.Scsi.Srb;
983
984 DPRINT("DeviceExtension %p\n", DeviceExtension);
985
986 Irp->IoStatus.Status = STATUS_SUCCESS;
987 Irp->IoStatus.Information = Srb->DataTransferLength;
988
989 DeviceExtension->CurrentIrp = Irp;
990
991 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
992 ScsiPortStartController,
993 DeviceExtension))
994 {
995 DPRINT1("Synchronization failed!\n");
996
997 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
998 Irp->IoStatus.Information = 0;
999 IoCompleteRequest(Irp,
1000 IO_NO_INCREMENT);
1001 IoStartNextPacket(DeviceObject,
1002 FALSE);
1003 }
1004 if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1005 {
1006 DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1007 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1008 }
1009
1010 if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1011 {
1012 DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1013 IoStartNextPacket(DeviceObject, FALSE);
1014 }
1015 }
1016 break;
1017
1018 default:
1019 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1020 Irp->IoStatus.Information = 0;
1021 IoCompleteRequest(Irp,
1022 IO_NO_INCREMENT);
1023 IoStartNextPacket(DeviceObject,
1024 FALSE);
1025 break;
1026 }
1027 DPRINT1("ScsiPortStartIo() done\n");
1028 }
1029
1030
1031 static BOOLEAN STDCALL
1032 ScsiPortStartController(IN OUT PVOID Context)
1033 {
1034 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1035 PIO_STACK_LOCATION IrpStack;
1036 PSCSI_REQUEST_BLOCK Srb;
1037
1038 DPRINT1("ScsiPortStartController() called\n");
1039
1040 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context;
1041
1042 IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1043 Srb = IrpStack->Parameters.Scsi.Srb;
1044
1045 return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1046 Srb));
1047 }
1048
1049
1050 /**********************************************************************
1051 * NAME INTERNAL
1052 * ScsiPortCreatePortDevice
1053 *
1054 * DESCRIPTION
1055 * Creates and initializes a SCSI port device object.
1056 *
1057 * RUN LEVEL
1058 * PASSIVE_LEVEL
1059 *
1060 * ARGUMENTS
1061 * DriverObject
1062 * ...
1063 *
1064 * PseudoDeviceExtension
1065 * ...
1066 *
1067 * PortNumber
1068 * ...
1069 *
1070 * RETURNS
1071 * NTSTATUS
1072 */
1073
1074 static NTSTATUS
1075 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
1076 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
1077 IN ULONG PortNumber)
1078 {
1079 PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension;
1080 PDEVICE_OBJECT PortDeviceObject;
1081 WCHAR NameBuffer[80];
1082 UNICODE_STRING DeviceName;
1083 WCHAR DosNameBuffer[80];
1084 UNICODE_STRING DosDeviceName;
1085 NTSTATUS Status;
1086 ULONG AccessRangeSize;
1087
1088 #if 0
1089 ULONG MappedIrq;
1090 KIRQL Dirql;
1091 KAFFINITY Affinity;
1092 #endif
1093
1094 DPRINT1("ScsiPortCreatePortDevice() called\n");
1095
1096 #if 0
1097 MappedIrq = HalGetInterruptVector(PseudoDeviceExtension->PortConfig.AdapterInterfaceType,
1098 PseudoDeviceExtension->PortConfig.SystemIoBusNumber,
1099 0,
1100 PseudoDeviceExtension->PortConfig.BusInterruptLevel,
1101 &Dirql,
1102 &Affinity);
1103 #endif
1104
1105 /* Create a unicode device name */
1106 swprintf(NameBuffer,
1107 L"\\Device\\ScsiPort%lu",
1108 PortNumber);
1109 RtlInitUnicodeString(&DeviceName,
1110 NameBuffer);
1111
1112 DPRINT("Creating device: %wZ\n", &DeviceName);
1113
1114 /* Create the port device */
1115 Status = IoCreateDevice(DriverObject,
1116 PseudoDeviceExtension->Length,
1117 &DeviceName,
1118 FILE_DEVICE_CONTROLLER,
1119 0,
1120 FALSE,
1121 &PortDeviceObject);
1122 if (!NT_SUCCESS(Status))
1123 {
1124 DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
1125 return(Status);
1126 }
1127
1128 DPRINT("Created device: %wZ\n", &DeviceName);
1129
1130 /* Set the buffering strategy here... */
1131 PortDeviceObject->Flags |= DO_DIRECT_IO;
1132 PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
1133
1134 PortDeviceExtension = PortDeviceObject->DeviceExtension;
1135
1136 /* Copy pseudo device extension into the real device extension */
1137 memcpy(PortDeviceExtension,
1138 PseudoDeviceExtension,
1139 PseudoDeviceExtension->Length);
1140
1141 /* Copy access ranges */
1142 AccessRangeSize =
1143 sizeof(ACCESS_RANGE) * PseudoDeviceExtension->PortConfig.NumberOfAccessRanges;
1144 PortDeviceExtension->PortConfig.AccessRanges = ExAllocatePool(NonPagedPool,
1145 AccessRangeSize);
1146 memcpy(PortDeviceExtension->PortConfig.AccessRanges,
1147 PseudoDeviceExtension->PortConfig.AccessRanges,
1148 AccessRangeSize);
1149
1150 PortDeviceExtension->DeviceObject = PortDeviceObject;
1151
1152
1153 /* Initialize the spin lock in the controller extension */
1154 KeInitializeSpinLock(&PortDeviceExtension->SpinLock);
1155
1156 /* Register an interrupt handler for this device */
1157 Status = IoConnectInterrupt(&PortDeviceExtension->Interrupt,
1158 ScsiPortIsr,
1159 PortDeviceExtension,
1160 &PortDeviceExtension->SpinLock,
1161 PortDeviceExtension->PortConfig.BusInterruptVector, // MappedIrq,
1162 PortDeviceExtension->PortConfig.BusInterruptLevel, // Dirql,
1163 15, //Dirql,
1164 PortDeviceExtension->PortConfig.InterruptMode,
1165 FALSE,
1166 0xFFFF, //Affinity,
1167 FALSE);
1168 if (!NT_SUCCESS(Status))
1169 {
1170 DbgPrint("Could not Connect Interrupt %d\n",
1171 PortDeviceExtension->PortConfig.BusInterruptVector);
1172 return(Status);
1173 }
1174
1175 /* Initialize the DPC object here */
1176 IoInitializeDpcRequest(PortDeviceExtension->DeviceObject,
1177 ScsiPortDpcForIsr);
1178
1179 /*
1180 * Initialize the controller timer here
1181 * (since it has to be tied to a device)
1182 */
1183 PortDeviceExtension->TimerState = IDETimerIdle;
1184 PortDeviceExtension->TimerCount = 0;
1185 IoInitializeTimer(PortDeviceExtension->DeviceObject,
1186 ScsiPortIoTimer,
1187 PortDeviceExtension);
1188
1189 /* Initialize inquiry data */
1190 PortDeviceExtension->PortBusInfoSize = 0;
1191 PortDeviceExtension->PortBusInfo = NULL;
1192
1193 DPRINT1("DeviceExtension %p\n", PortDeviceExtension);
1194 ScsiPortInquire(PortDeviceExtension);
1195
1196
1197 /* FIXME: Copy more configuration data? */
1198
1199 /* Create the dos device */
1200 swprintf(DosNameBuffer,
1201 L"\\??\\Scsi%lu:",
1202 PortNumber);
1203 RtlInitUnicodeString(&DosDeviceName,
1204 DosNameBuffer);
1205
1206 IoCreateSymbolicLink(&DosDeviceName,
1207 &DeviceName);
1208
1209 return(STATUS_SUCCESS);
1210 }
1211
1212
1213 static VOID
1214 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1215 {
1216 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
1217 PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
1218 SCSI_REQUEST_BLOCK Srb;
1219 ULONG Bus;
1220 ULONG Target;
1221 ULONG UnitCount;
1222 ULONG DataSize;
1223 BOOLEAN Result;
1224
1225 DPRINT1("ScsiPortInquire() called\n");
1226
1227 DeviceExtension->Initializing = TRUE;
1228
1229 /* Copy inquiry data to the port device extension */
1230 AdapterInfo =(PSCSI_ADAPTER_BUS_INFO)ExAllocatePool(NonPagedPool, 4096);
1231 AdapterInfo->NumberOfBuses = DeviceExtension->PortConfig.NumberOfBuses;
1232
1233 UnitInfo = (PSCSI_INQUIRY_DATA)
1234 ((PUCHAR)AdapterInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
1235 (sizeof(SCSI_BUS_DATA) * (AdapterInfo->NumberOfBuses - 1)));
1236
1237 Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
1238 RtlZeroMemory(&Srb,
1239 sizeof(SCSI_REQUEST_BLOCK));
1240 Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
1241 Srb.DataTransferLength = 256;
1242 Srb.Cdb[0] = SCSIOP_INQUIRY;
1243
1244 for (Bus = 0; Bus < AdapterInfo->NumberOfBuses; Bus++)
1245 {
1246 Srb.PathId = Bus;
1247
1248 AdapterInfo->BusData[Bus].InitiatorBusId = 0; /* ? */
1249 AdapterInfo->BusData[Bus].InquiryDataOffset =
1250 (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterInfo);
1251
1252 PrevUnit = NULL;
1253 UnitCount = 0;
1254
1255 for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
1256 {
1257 Srb.TargetId = Target;
1258 Srb.Lun = 0;
1259
1260 Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1261 &Srb);
1262 if (Result == TRUE)
1263 {
1264 UnitInfo->PathId = Bus;
1265 UnitInfo->TargetId = Target;
1266 UnitInfo->Lun = 0;
1267 UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
1268 memcpy(&UnitInfo->InquiryData,
1269 Srb.DataBuffer,
1270 INQUIRYDATABUFFERSIZE);
1271 if (PrevUnit != NULL)
1272 PrevUnit->NextInquiryDataOffset = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
1273 PrevUnit = UnitInfo;
1274 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
1275 UnitCount++;
1276 }
1277 }
1278 AdapterInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
1279 }
1280 DataSize = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
1281
1282 ExFreePool(Srb.DataBuffer);
1283
1284 DeviceExtension->Initializing = FALSE;
1285
1286 /* copy inquiry data to the port driver's device extension */
1287 DeviceExtension->PortBusInfoSize = DataSize;
1288 DeviceExtension->PortBusInfo = ExAllocatePool(NonPagedPool,
1289 DataSize);
1290 memcpy(DeviceExtension->PortBusInfo,
1291 AdapterInfo,
1292 DataSize);
1293
1294 ExFreePool(AdapterInfo);
1295 }
1296
1297
1298 static BOOLEAN STDCALL
1299 ScsiPortIsr(IN PKINTERRUPT Interrupt,
1300 IN PVOID ServiceContext)
1301 {
1302 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1303 BOOLEAN Result;
1304
1305 DPRINT("ScsiPortIsr() called!\n");
1306
1307 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
1308
1309 Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
1310 if (Result == FALSE)
1311 {
1312 return(FALSE);
1313 }
1314
1315 if (DeviceExtension->IrpFlags)
1316 {
1317 IoRequestDpc(DeviceExtension->DeviceObject,
1318 DeviceExtension->CurrentIrp,
1319 DeviceExtension);
1320 }
1321
1322 return(TRUE);
1323 }
1324
1325
1326 // ScsiPortDpcForIsr
1327 // DESCRIPTION:
1328 //
1329 // RUN LEVEL:
1330 //
1331 // ARGUMENTS:
1332 // IN PKDPC Dpc
1333 // IN PDEVICE_OBJECT DpcDeviceObject
1334 // IN PIRP DpcIrp
1335 // IN PVOID DpcContext
1336 //
1337 static VOID STDCALL
1338 ScsiPortDpcForIsr(IN PKDPC Dpc,
1339 IN PDEVICE_OBJECT DpcDeviceObject,
1340 IN PIRP DpcIrp,
1341 IN PVOID DpcContext)
1342 {
1343 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1344
1345 DPRINT1("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
1346 Dpc, DpcDeviceObject, DpcIrp, DpcContext);
1347
1348 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
1349
1350 DeviceExtension->CurrentIrp = NULL;
1351
1352 // DpcIrp->IoStatus.Information = 0;
1353 // DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1354
1355 if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1356 {
1357 DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1358 IoCompleteRequest(DpcIrp, IO_NO_INCREMENT);
1359 }
1360
1361 if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1362 {
1363 DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1364 IoStartNextPacket(DpcDeviceObject, FALSE);
1365 }
1366
1367 DPRINT1("ScsiPortDpcForIsr() done\n");
1368 }
1369
1370
1371 // ScsiPortIoTimer
1372 // DESCRIPTION:
1373 // This function handles timeouts and other time delayed processing
1374 //
1375 // RUN LEVEL:
1376 //
1377 // ARGUMENTS:
1378 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1379 // IN PVOID Context the Controller extension for the
1380 // controller the device is on
1381 //
1382 static VOID STDCALL
1383 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
1384 PVOID Context)
1385 {
1386 DPRINT1("ScsiPortIoTimer()\n");
1387 }
1388
1389 /* EOF */