3 * Copyright (C) 2001, 2002 ReactOS Team
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.
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.
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.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS Storage Stack
23 * FILE: drivers/storage/scsiport/scsiport.c
24 * PURPOSE: SCSI port driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
26 * Aleksey Bragin (aleksey reactos org)
29 /* INCLUDES *****************************************************************/
45 #include "scsiport_int.h"
52 ULONG InternalDebugLevel
= 0x00;
54 /* TYPES *********************************************************************/
56 /* GLOBALS *******************************************************************/
59 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
60 IN PDEVICE_OBJECT DeviceObject
,
61 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
62 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
63 IN PUNICODE_STRING RegistryPath
,
65 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
);
67 static NTSTATUS STDCALL
68 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
71 static NTSTATUS STDCALL
72 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
75 static NTSTATUS STDCALL
76 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
80 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
83 static BOOLEAN STDCALL
84 ScsiPortStartPacket(IN OUT PVOID Context
);
87 static PSCSI_PORT_LUN_EXTENSION
88 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
90 static PSCSI_PORT_LUN_EXTENSION
91 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
97 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
98 IN PSCSI_LUN_INFO LunInfo
);
101 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
104 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
107 static PSCSI_REQUEST_BLOCK_INFO
108 SpiGetSrbData(IN PVOID DeviceExtension
,
114 static BOOLEAN STDCALL
115 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
116 IN PVOID ServiceContext
);
119 ScsiPortDpcForIsr(IN PKDPC Dpc
,
120 IN PDEVICE_OBJECT DpcDeviceObject
,
122 IN PVOID DpcContext
);
125 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
129 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
130 PUNICODE_STRING RegistryPath
);
133 SpiStatusSrbToNt(UCHAR SrbStatus
);
136 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
137 IN PSCSI_REQUEST_BLOCK Srb
);
140 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
146 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
147 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
148 OUT PBOOLEAN NeedToCallStartIo
);
151 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
152 IN PSCSI_PORT_LUN_EXTENSION LunExtension
);
155 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
156 IN PVOID DeviceObject
,
157 IN PVOID SystemArgument1
,
158 IN PVOID SystemArgument2
);
161 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
162 PHW_INITIALIZATION_DATA HwInitData
,
163 PCONFIGURATION_INFO InternalConfigInfo
,
164 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
168 SpQueryDeviceCallout(IN PVOID Context
,
169 IN PUNICODE_STRING PathName
,
170 IN INTERFACE_TYPE BusType
,
172 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
173 IN CONFIGURATION_TYPE ControllerType
,
174 IN ULONG ControllerNumber
,
175 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
176 IN CONFIGURATION_TYPE PeripheralType
,
177 IN ULONG PeripheralNumber
,
178 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
);
181 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
183 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
184 IN PCONFIGURATION_INFO InternalConfigInfo
,
188 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
189 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
190 IN PPORT_CONFIGURATION_INFORMATION PortConfig
);
192 static PCM_RESOURCE_LIST
193 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
194 PPORT_CONFIGURATION_INFORMATION PortConfig
);
197 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
200 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
204 /* FUNCTIONS *****************************************************************/
206 /**********************************************************************
211 * This function initializes the driver.
218 * System allocated Driver Object for this driver.
221 * Name of registry driver service key.
228 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
229 IN PUNICODE_STRING RegistryPath
)
231 DPRINT("ScsiPort Driver %s\n", VERSION
);
232 return(STATUS_SUCCESS
);
236 /**********************************************************************
241 * Prints debugging messages.
248 * Debug level of the given message.
251 * Pointer to printf()-compatible format string.
254 Additional output data (see printf()).
263 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
264 IN PCHAR DebugMessage
,
270 if (DebugPrintLevel
> InternalDebugLevel
)
273 va_start(ap
, DebugMessage
);
274 vsprintf(Buffer
, DebugMessage
, ap
);
285 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
291 DPRINT("ScsiPortCompleteRequest()\n");
299 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
301 DPRINT("ScsiPortFlushDma()\n");
310 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
311 IN PVOID MappedAddress
)
313 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
314 PMAPPED_ADDRESS NextMa
, LastMa
;
316 //DPRINT("ScsiPortFreeDeviceBase() called\n");
318 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
319 SCSI_PORT_DEVICE_EXTENSION
,
320 MiniPortDeviceExtension
);
323 /* Initialize our pointers */
324 NextMa
= DeviceExtension
->MappedAddressList
;
329 if (NextMa
->MappedAddress
== MappedAddress
)
332 MmUnmapIoSpace(MappedAddress
, NextMa
->NumberOfBytes
);
334 /* Remove it from the list */
335 if (NextMa
== DeviceExtension
->MappedAddressList
)
337 /* Remove the first entry */
338 DeviceExtension
->MappedAddressList
= NextMa
->NextMappedAddress
;
342 LastMa
->NextMappedAddress
= NextMa
->NextMappedAddress
;
345 /* Free the resources and quit */
353 NextMa
= NextMa
->NextMappedAddress
;
363 ScsiPortGetBusData(IN PVOID DeviceExtension
,
364 IN ULONG BusDataType
,
365 IN ULONG SystemIoBusNumber
,
370 return(HalGetBusData(BusDataType
,
382 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
383 IN INTERFACE_TYPE BusType
,
384 IN ULONG SystemIoBusNumber
,
385 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
386 IN ULONG NumberOfBytes
,
387 IN BOOLEAN InIoSpace
)
389 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
390 PHYSICAL_ADDRESS TranslatedAddress
;
391 PMAPPED_ADDRESS DeviceBase
;
395 //DPRINT ("ScsiPortGetDeviceBase() called\n");
397 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
398 SCSI_PORT_DEVICE_EXTENSION
,
399 MiniPortDeviceExtension
);
401 AddressSpace
= (ULONG
)InIoSpace
;
402 if (HalTranslateBusAddress(BusType
,
406 &TranslatedAddress
) == FALSE
)
412 if (AddressSpace
!= 0)
413 return((PVOID
)TranslatedAddress
.u
.LowPart
);
415 MappedAddress
= MmMapIoSpace(TranslatedAddress
,
419 DeviceBase
= ExAllocatePool(NonPagedPool
,
420 sizeof(MAPPED_ADDRESS
));
422 if (DeviceBase
== NULL
)
423 return MappedAddress
;
425 DeviceBase
->MappedAddress
= MappedAddress
;
426 DeviceBase
->NumberOfBytes
= NumberOfBytes
;
427 DeviceBase
->IoAddress
= IoAddress
;
428 DeviceBase
->BusNumber
= SystemIoBusNumber
;
430 /* Link it to the Device Extension list */
431 DeviceBase
->NextMappedAddress
= DeviceExtension
->MappedAddressList
;
432 DeviceExtension
->MappedAddressList
= DeviceBase
;
434 return MappedAddress
;
441 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
448 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
449 PSCSI_PORT_LUN_EXTENSION LunExtension
;
452 DPRINT("ScsiPortGetLogicalUnit() called\n");
454 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
455 SCSI_PORT_DEVICE_EXTENSION
,
456 MiniPortDeviceExtension
);
457 if (IsListEmpty(&DeviceExtension
->LunExtensionListHead
))
460 Entry
= DeviceExtension
->LunExtensionListHead
.Flink
;
461 while (Entry
!= &DeviceExtension
->LunExtensionListHead
)
463 LunExtension
= CONTAINING_RECORD(Entry
,
464 SCSI_PORT_LUN_EXTENSION
,
466 if (LunExtension
->PathId
== PathId
&&
467 LunExtension
->TargetId
== TargetId
&&
468 LunExtension
->Lun
== Lun
)
470 return (PVOID
)&LunExtension
->MiniportLunExtension
;
473 Entry
= Entry
->Flink
;
483 SCSI_PHYSICAL_ADDRESS STDCALL
484 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
485 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
486 IN PVOID VirtualAddress
,
489 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
490 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
491 SCSI_PHYSICAL_ADDRESS NextPhysicalAddress
;
492 ULONG BufferLength
= 0;
496 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
497 HwDeviceExtension
, Srb
, VirtualAddress
, Length
);
499 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
500 SCSI_PORT_DEVICE_EXTENSION
,
501 MiniPortDeviceExtension
);
507 if ((ULONG_PTR
)DeviceExtension
->VirtualAddress
> (ULONG_PTR
)VirtualAddress
)
509 PhysicalAddress
.QuadPart
= 0ULL;
510 return PhysicalAddress
;
513 Offset
= (ULONG_PTR
)VirtualAddress
- (ULONG_PTR
)DeviceExtension
->VirtualAddress
;
514 if (Offset
>= DeviceExtension
->CommonBufferLength
)
516 PhysicalAddress
.QuadPart
= 0ULL;
517 return PhysicalAddress
;
520 PhysicalAddress
.QuadPart
=
521 DeviceExtension
->PhysicalAddress
.QuadPart
+ (ULONGLONG
)Offset
;
522 BufferLength
= DeviceExtension
->CommonBufferLength
- Offset
;
526 EndAddress
= (PVOID
)((ULONG_PTR
)Srb
->DataBuffer
+ Srb
->DataTransferLength
);
527 if (VirtualAddress
== NULL
)
529 VirtualAddress
= Srb
->DataBuffer
;
531 else if (VirtualAddress
< Srb
->DataBuffer
|| VirtualAddress
>= EndAddress
)
533 PhysicalAddress
.QuadPart
= 0LL;
534 return PhysicalAddress
;
537 PhysicalAddress
= MmGetPhysicalAddress(VirtualAddress
);
538 if (PhysicalAddress
.QuadPart
== 0LL)
540 return PhysicalAddress
;
543 Offset
= (ULONG_PTR
)VirtualAddress
& (PAGE_SIZE
- 1);
547 * MmGetPhysicalAddress doesn't return the offset within the page.
548 * We must set the correct offset.
550 PhysicalAddress
.u
.LowPart
= (PhysicalAddress
.u
.LowPart
& ~(PAGE_SIZE
- 1)) + Offset
;
552 BufferLength
+= PAGE_SIZE
- Offset
;
553 while ((ULONG_PTR
)VirtualAddress
+ BufferLength
< (ULONG_PTR
)EndAddress
)
555 NextPhysicalAddress
= MmGetPhysicalAddress((PVOID
)((ULONG_PTR
)VirtualAddress
+ BufferLength
));
556 if (PhysicalAddress
.QuadPart
+ (ULONGLONG
)BufferLength
!= NextPhysicalAddress
.QuadPart
)
560 BufferLength
+= PAGE_SIZE
;
562 if ((ULONG_PTR
)VirtualAddress
+ BufferLength
>= (ULONG_PTR
)EndAddress
)
564 BufferLength
= (ULONG_PTR
)EndAddress
- (ULONG_PTR
)VirtualAddress
;
568 *Length
= BufferLength
;
570 return PhysicalAddress
;
577 PSCSI_REQUEST_BLOCK STDCALL
578 ScsiPortGetSrb(IN PVOID DeviceExtension
,
584 DPRINT1("ScsiPortGetSrb() unimplemented\n");
594 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
595 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
596 IN ULONG NumberOfBytes
)
598 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
599 DEVICE_DESCRIPTION DeviceDescription
;
601 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
602 HwDeviceExtension
, ConfigInfo
, NumberOfBytes
);
604 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
605 SCSI_PORT_DEVICE_EXTENSION
,
606 MiniPortDeviceExtension
);
608 /* Check for allocated common DMA buffer */
609 if (DeviceExtension
->VirtualAddress
!= NULL
)
611 DPRINT1("The HBA has already got a common DMA buffer!\n");
615 /* Check for DMA adapter object */
616 if (DeviceExtension
->AdapterObject
== NULL
)
618 /* Initialize DMA adapter description */
619 RtlZeroMemory(&DeviceDescription
,
620 sizeof(DEVICE_DESCRIPTION
));
621 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
622 DeviceDescription
.Master
= ConfigInfo
->Master
;
623 DeviceDescription
.ScatterGather
= ConfigInfo
->ScatterGather
;
624 DeviceDescription
.DemandMode
= ConfigInfo
->DemandMode
;
625 DeviceDescription
.Dma32BitAddresses
= ConfigInfo
->Dma32BitAddresses
;
626 DeviceDescription
.BusNumber
= ConfigInfo
->SystemIoBusNumber
;
627 DeviceDescription
.DmaChannel
= ConfigInfo
->DmaChannel
;
628 DeviceDescription
.InterfaceType
= ConfigInfo
->AdapterInterfaceType
;
629 DeviceDescription
.DmaWidth
= ConfigInfo
->DmaWidth
;
630 DeviceDescription
.DmaSpeed
= ConfigInfo
->DmaSpeed
;
631 DeviceDescription
.MaximumLength
= ConfigInfo
->MaximumTransferLength
;
632 DeviceDescription
.DmaPort
= ConfigInfo
->DmaPort
;
634 /* Get a DMA adapter object */
635 DeviceExtension
->AdapterObject
= HalGetAdapter(&DeviceDescription
,
636 &DeviceExtension
->MapRegisterCount
);
637 if (DeviceExtension
->AdapterObject
== NULL
)
639 DPRINT1("HalGetAdapter() failed\n");
644 /* Allocate a common DMA buffer */
645 DeviceExtension
->CommonBufferLength
=
646 NumberOfBytes
+ DeviceExtension
->SrbExtensionSize
;
647 DeviceExtension
->VirtualAddress
=
648 HalAllocateCommonBuffer(DeviceExtension
->AdapterObject
,
649 DeviceExtension
->CommonBufferLength
,
650 &DeviceExtension
->PhysicalAddress
,
652 if (DeviceExtension
->VirtualAddress
== NULL
)
654 DPRINT1("HalAllocateCommonBuffer() failed!\n");
655 DeviceExtension
->CommonBufferLength
= 0;
659 return (PVOID
)((ULONG_PTR
)DeviceExtension
->VirtualAddress
+
660 DeviceExtension
->SrbExtensionSize
);
668 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
669 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
671 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
674 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
675 HwDeviceExtension
, PhysicalAddress
.QuadPart
);
677 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
678 SCSI_PORT_DEVICE_EXTENSION
,
679 MiniPortDeviceExtension
);
681 if (DeviceExtension
->PhysicalAddress
.QuadPart
> PhysicalAddress
.QuadPart
)
684 Offset
= (ULONG
)(PhysicalAddress
.QuadPart
- DeviceExtension
->PhysicalAddress
.QuadPart
);
685 if (Offset
>= DeviceExtension
->CommonBufferLength
)
688 return (PVOID
)((ULONG_PTR
)DeviceExtension
->VirtualAddress
+ Offset
);
692 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo
, PUNICODE_STRING RegistryPath
)
694 OBJECT_ATTRIBUTES ObjectAttributes
;
695 UNICODE_STRING KeyName
;
698 /* Open the service key */
699 InitializeObjectAttributes(&ObjectAttributes
,
701 OBJ_CASE_INSENSITIVE
,
705 Status
= ZwOpenKey(&ConfigInfo
->ServiceKey
,
709 if (!NT_SUCCESS(Status
))
711 DPRINT1("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath
, Status
);
712 ConfigInfo
->ServiceKey
= NULL
;
715 /* If we could open driver's service key, then proceed to the Parameters key */
716 if (ConfigInfo
->ServiceKey
!= NULL
)
718 RtlInitUnicodeString(&KeyName
, L
"Parameters");
719 InitializeObjectAttributes(&ObjectAttributes
,
721 OBJ_CASE_INSENSITIVE
,
722 ConfigInfo
->ServiceKey
,
723 (PSECURITY_DESCRIPTOR
) NULL
);
726 Status
= ZwOpenKey(&ConfigInfo
->DeviceKey
,
730 if (NT_SUCCESS(Status
))
732 /* Yes, Parameters key exist, and it must be used instead of
734 ZwClose(ConfigInfo
->ServiceKey
);
735 ConfigInfo
->ServiceKey
= ConfigInfo
->DeviceKey
;
736 ConfigInfo
->DeviceKey
= NULL
;
740 /* Open the Device key */
741 RtlInitUnicodeString(&KeyName
, L
"Device");
742 InitializeObjectAttributes(&ObjectAttributes
,
744 OBJ_CASE_INSENSITIVE
,
745 ConfigInfo
->ServiceKey
,
748 /* We don't check for failure here - not needed */
749 ZwOpenKey(&ConfigInfo
->DeviceKey
,
755 /**********************************************************************
760 * Initializes SCSI port driver specific data.
767 * Pointer to the miniport driver's driver object.
770 * Pointer to the miniport driver's registry path.
772 * HwInitializationData
773 * Pointer to port driver specific configuration data.
776 Miniport driver specific context.
785 ScsiPortInitialize(IN PVOID Argument1
,
787 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
790 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
791 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
792 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
793 PCONFIGURATION_INFORMATION SystemConfig
;
794 PPORT_CONFIGURATION_INFORMATION PortConfig
;
795 PORT_CONFIGURATION_INFORMATION InitialPortConfig
;
796 CONFIGURATION_INFO ConfigInfo
;
797 ULONG DeviceExtensionSize
;
798 ULONG PortConfigSize
;
800 BOOLEAN DeviceFound
= FALSE
;
801 BOOLEAN FirstConfigCall
= TRUE
;
806 PCI_SLOT_NUMBER SlotNumber
;
808 PDEVICE_OBJECT PortDeviceObject
;
809 WCHAR NameBuffer
[80];
810 UNICODE_STRING DeviceName
;
811 WCHAR DosNameBuffer
[80];
812 UNICODE_STRING DosDeviceName
;
813 PIO_SCSI_CAPABILITIES PortCapabilities
;
818 PCM_RESOURCE_LIST ResourceList
;
822 DPRINT ("ScsiPortInitialize() called!\n");
824 /* Check params for validity */
825 if ((HwInitializationData
->HwInitialize
== NULL
) ||
826 (HwInitializationData
->HwStartIo
== NULL
) ||
827 (HwInitializationData
->HwInterrupt
== NULL
) ||
828 (HwInitializationData
->HwFindAdapter
== NULL
) ||
829 (HwInitializationData
->HwResetBus
== NULL
))
831 return STATUS_INVALID_PARAMETER
;
835 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
836 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
837 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
838 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
839 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
840 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
842 /* Obtain configuration information */
843 SystemConfig
= IoGetConfigurationInformation();
845 /* Zero the internal configuration info structure */
846 RtlZeroMemory(&ConfigInfo
, sizeof(CONFIGURATION_INFO
));
848 /* Allocate space for access ranges */
849 if (HwInitializationData
->NumberOfAccessRanges
)
851 ConfigInfo
.AccessRanges
=
852 ExAllocatePool(PagedPool
,
853 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
856 if (ConfigInfo
.AccessRanges
== NULL
)
857 return STATUS_INSUFFICIENT_RESOURCES
;
860 /* Open registry keys */
861 SpiInitOpenKeys(&ConfigInfo
, (PUNICODE_STRING
)Argument2
);
863 /* Last adapter number = not known */
864 ConfigInfo
.LastAdapterNumber
= SP_UNINITIALIZED_VALUE
;
866 /* Calculate sizes of DeviceExtension and PortConfig */
867 DeviceExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
868 HwInitializationData
->DeviceExtensionSize
;
870 MaxBus
= (HwInitializationData
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
871 DPRINT("MaxBus: %lu\n", MaxBus
);
875 /* Create a unicode device name */
877 L
"\\Device\\ScsiPort%lu",
878 SystemConfig
->ScsiPortCount
);
879 RtlInitUnicodeString(&DeviceName
, NameBuffer
);
881 DPRINT("Creating device: %wZ\n", &DeviceName
);
883 /* Create the port device */
884 Status
= IoCreateDevice(DriverObject
,
887 FILE_DEVICE_CONTROLLER
,
892 if (!NT_SUCCESS(Status
))
894 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
895 PortDeviceObject
= NULL
;
899 DPRINT ("Created device: %wZ (%p)\n", &DeviceName
, PortDeviceObject
);
901 /* Set the buffering strategy here... */
902 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
903 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
; /* FIXME: Is this really needed? */
905 /* Fill Device Extension */
906 DeviceExtension
= PortDeviceObject
->DeviceExtension
;
907 DeviceExtension
->Length
= DeviceExtensionSize
;
908 DeviceExtension
->DeviceObject
= PortDeviceObject
;
909 DeviceExtension
->PortNumber
= SystemConfig
->ScsiPortCount
;
911 /* Driver's routines... */
912 DeviceExtension
->HwInitialize
= HwInitializationData
->HwInitialize
;
913 DeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
914 DeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
915 DeviceExtension
->HwResetBus
= HwInitializationData
->HwResetBus
;
916 DeviceExtension
->HwDmaStarted
= HwInitializationData
->HwDmaStarted
;
918 /* Extensions sizes */
919 DeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
920 DeviceExtension
->LunExtensionSize
= HwInitializationData
->SpecificLuExtensionSize
;
921 DeviceExtension
->SrbExtensionSize
= HwInitializationData
->SrbExtensionSize
;
923 /* Round Srb extension size to the quadword */
924 DeviceExtension
->SrbExtensionSize
=
925 ~(sizeof(LONGLONG
) - 1) & (DeviceExtension
->SrbExtensionSize
+
926 sizeof(LONGLONG
) - 1);
928 /* Fill some numbers (bus count, lun count, etc) */
929 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
930 DeviceExtension
->RequestsNumber
= 16;
932 /* Initialize the spin lock in the controller extension */
933 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
934 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
936 /* Initialize the DPC object */
937 IoInitializeDpcRequest(PortDeviceObject
,
940 /* Initialize the device timer */
941 DeviceExtension
->TimerCount
= -1;
942 IoInitializeTimer(PortDeviceObject
,
946 /* Initialize miniport timer */
947 KeInitializeTimer(&DeviceExtension
->MiniportTimer
);
948 KeInitializeDpc(&DeviceExtension
->MiniportTimerDpc
,
954 Status
= SpiCreatePortConfig(DeviceExtension
,
955 HwInitializationData
,
960 if (!NT_SUCCESS(Status
))
963 /* Allocate and initialize port configuration info */
964 PortConfigSize
= (sizeof(PORT_CONFIGURATION_INFORMATION
) +
965 HwInitializationData
->NumberOfAccessRanges
*
966 sizeof(ACCESS_RANGE
) + 7) & ~7;
967 DeviceExtension
->PortConfig
= ExAllocatePool(NonPagedPool
, PortConfigSize
);
970 if (DeviceExtension
->PortConfig
== NULL
)
972 Status
= STATUS_INSUFFICIENT_RESOURCES
;
976 PortConfig
= DeviceExtension
->PortConfig
;
978 /* Copy information here */
979 RtlCopyMemory(PortConfig
,
981 sizeof(PORT_CONFIGURATION_INFORMATION
));
984 /* Copy extension sizes into the PortConfig */
985 PortConfig
->SpecificLuExtensionSize
= DeviceExtension
->LunExtensionSize
;
986 PortConfig
->SrbExtensionSize
= DeviceExtension
->SrbExtensionSize
;
988 /* Initialize Access ranges */
989 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
991 PortConfig
->AccessRanges
= (PVOID
)(PortConfig
+1);
993 /* Align to LONGLONG */
994 PortConfig
->AccessRanges
= (PVOID
)((ULONG
)(PortConfig
->AccessRanges
) + 7);
995 PortConfig
->AccessRanges
= (PVOID
)((ULONG
)(PortConfig
->AccessRanges
) & ~7);
998 RtlCopyMemory(PortConfig
->AccessRanges
,
999 ConfigInfo
.AccessRanges
,
1000 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
1003 /* Search for matching PCI device */
1004 if ((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1005 (HwInitializationData
->VendorIdLength
> 0) &&
1006 (HwInitializationData
->VendorId
!= NULL
) &&
1007 (HwInitializationData
->DeviceIdLength
> 0) &&
1008 (HwInitializationData
->DeviceId
!= NULL
))
1010 PortConfig
->BusInterruptLevel
= 0;
1012 /* Get PCI device data */
1013 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1014 HwInitializationData
->VendorIdLength
,
1015 HwInitializationData
->VendorId
,
1016 HwInitializationData
->DeviceIdLength
,
1017 HwInitializationData
->DeviceId
);
1019 if (!SpiGetPciConfigData(DriverObject
,
1021 HwInitializationData
,
1027 /* Continue to the next bus, nothing here */
1028 ConfigInfo
.BusNumber
++;
1029 DeviceExtension
->PortConfig
= NULL
;
1030 ExFreePool(PortConfig
);
1032 goto CreatePortConfig
;
1035 if (!PortConfig
->BusInterruptLevel
)
1037 /* Bypass this slot, because no interrupt was assigned */
1038 DeviceExtension
->PortConfig
= NULL
;
1039 ExFreePool(PortConfig
);
1040 goto CreatePortConfig
;
1045 DPRINT("Non-pci bus\n");
1048 /* Note: HwFindAdapter is called once for each bus */
1050 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
1051 Result
= (HwInitializationData
->HwFindAdapter
)(&DeviceExtension
->MiniPortDeviceExtension
,
1053 0, /* BusInformation */
1054 ConfigInfo
.Parameter
, /* ArgumentString */
1058 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1059 Result
, (Again
) ? "True" : "False");
1061 /* Free MapRegisterBase, it's not needed anymore */
1062 if (DeviceExtension
->MapRegisterBase
!= NULL
)
1064 ExFreePool(DeviceExtension
->MapRegisterBase
);
1065 DeviceExtension
->MapRegisterBase
= NULL
;
1068 /* If result is nothing good... */
1069 if (Result
!= SP_RETURN_FOUND
)
1071 DPRINT("HwFindAdapter() Result: %lu\n", Result
);
1073 if (Result
== SP_RETURN_NOT_FOUND
)
1075 /* We can continue on the next bus */
1076 ConfigInfo
.BusNumber
++;
1079 DeviceExtension
->PortConfig
= NULL
;
1080 ExFreePool(PortConfig
);
1081 goto CreatePortConfig
;
1084 /* Otherwise, break */
1085 Status
= STATUS_INTERNAL_ERROR
;
1089 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1090 PortConfig
->BusInterruptVector
, PortConfig
->InitiatorBusId
[0]);
1092 /* If the SRB extension size was updated */
1093 if (!DeviceExtension
->NonCachedExtension
&&
1094 (PortConfig
->SrbExtensionSize
!= DeviceExtension
->SrbExtensionSize
))
1096 /* Set it (rounding to LONGLONG again) */
1097 DeviceExtension
->SrbExtensionSize
=
1098 (PortConfig
->SrbExtensionSize
+
1099 sizeof(LONGLONG
)) & ~(sizeof(LONGLONG
) - 1);
1102 /* The same with LUN extension size */
1103 if (PortConfig
->SpecificLuExtensionSize
!= DeviceExtension
->LunExtensionSize
)
1104 DeviceExtension
->LunExtensionSize
= PortConfig
->SpecificLuExtensionSize
;
1107 if (!((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1108 (HwInitializationData
->VendorIdLength
> 0) &&
1109 (HwInitializationData
->VendorId
!= NULL
) &&
1110 (HwInitializationData
->DeviceIdLength
> 0) &&
1111 (HwInitializationData
->DeviceId
!= NULL
)))
1113 /* Construct a resource list */
1114 ResourceList
= SpiConfigToResource(DeviceExtension
,
1119 UNICODE_STRING UnicodeString
;
1120 RtlInitUnicodeString(&UnicodeString
, L
"ScsiAdapter");
1121 DPRINT("Reporting resources\n");
1122 Status
= IoReportResourceUsage(&UnicodeString
,
1128 FIELD_OFFSET(CM_RESOURCE_LIST
,
1129 List
[0].PartialResourceList
.PartialDescriptors
) +
1130 ResourceList
->List
[0].PartialResourceList
.Count
1131 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
1134 ExFreePool(ResourceList
);
1136 /* In case of a failure or a conflict, break */
1137 if (Conflict
|| (!NT_SUCCESS(Status
)))
1140 Status
= STATUS_CONFLICTING_ADDRESSES
;
1146 /* Reset the Conflict var */
1149 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1150 if (PortConfig
->MaximumNumberOfTargets
> SCSI_MAXIMUM_TARGETS_PER_BUS
)
1151 DeviceExtension
->MaxTargedIds
= SCSI_MAXIMUM_TARGETS_PER_BUS
;
1153 DeviceExtension
->MaxTargedIds
= PortConfig
->MaximumNumberOfTargets
;
1155 DeviceExtension
->BusNum
= PortConfig
->NumberOfBuses
;
1156 DeviceExtension
->CachesData
= PortConfig
->CachesData
;
1157 DeviceExtension
->ReceiveEvent
= PortConfig
->ReceiveEvent
;
1158 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->TaggedQueuing
;
1159 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
;
1161 /* If something was disabled via registry - apply it */
1162 if (ConfigInfo
.DisableMultipleLun
)
1163 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1165 if (ConfigInfo
.DisableTaggedQueueing
)
1166 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1168 /* Check if we need to alloc SRB data */
1169 if (DeviceExtension
->SupportsTaggedQueuing
||
1170 DeviceExtension
->MultipleReqsPerLun
)
1172 DeviceExtension
->NeedSrbDataAlloc
= TRUE
;
1176 DeviceExtension
->NeedSrbDataAlloc
= FALSE
;
1179 /* Get a pointer to the port capabilities */
1180 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1182 /* Copy one field there */
1183 DeviceExtension
->MapBuffers
= PortConfig
->MapBuffers
;
1184 PortCapabilities
->AdapterUsesPio
= PortConfig
->MapBuffers
;
1186 if (DeviceExtension
->AdapterObject
== NULL
&&
1187 (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
|| PortConfig
->Master
))
1189 DPRINT1("DMA is not supported yet\n");
1193 if (DeviceExtension
->SrbExtensionBuffer
== NULL
&&
1194 (DeviceExtension
->SrbExtensionSize
!= 0 ||
1195 PortConfig
->AutoRequestSense
))
1197 DeviceExtension
->SupportsAutoSense
= PortConfig
->AutoRequestSense
;
1198 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
1200 //Status = STATUS_UNSUCCESFUL;
1201 /* TODO: Allocate common buffer */
1204 /* Check for failure */
1205 if (!NT_SUCCESS(Status
))
1209 /* Allocate SrbData, if needed */
1210 if (DeviceExtension
->NeedSrbDataAlloc
)
1213 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1215 if (DeviceExtension
->SrbDataCount
!= 0)
1216 Count
= DeviceExtension
->SrbDataCount
;
1218 Count
= DeviceExtension
->RequestsNumber
* 2;
1220 /* Allocate the data */
1221 SrbData
= ExAllocatePool(NonPagedPool
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
));
1222 if (SrbData
== NULL
)
1223 return STATUS_INSUFFICIENT_RESOURCES
;
1225 RtlZeroMemory(SrbData
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
));
1227 DeviceExtension
->SrbInfo
= SrbData
;
1228 DeviceExtension
->FreeSrbInfo
= SrbData
;
1229 DeviceExtension
->SrbDataCount
= Count
;
1231 /* Link it to the list */
1234 SrbData
->Requests
.Flink
= (PLIST_ENTRY
)(SrbData
+ 1);
1239 /* Mark the last entry of the list */
1241 SrbData
->Requests
.Flink
= NULL
;
1244 /* Initialize port capabilities */
1245 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1246 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1247 PortCapabilities
->MaximumTransferLength
= PortConfig
->MaximumTransferLength
;
1249 if (PortConfig
->ReceiveEvent
)
1250 PortCapabilities
->SupportedAsynchronousEvents
|= SRBEV_SCSI_ASYNC_NOTIFICATION
;
1252 PortCapabilities
->TaggedQueuing
= DeviceExtension
->SupportsTaggedQueuing
;
1253 PortCapabilities
->AdapterScansDown
= PortConfig
->AdapterScansDown
;
1255 if (PortConfig
->AlignmentMask
> PortDeviceObject
->AlignmentRequirement
)
1256 PortDeviceObject
->AlignmentRequirement
= PortConfig
->AlignmentMask
;
1258 PortCapabilities
->AlignmentMask
= PortDeviceObject
->AlignmentRequirement
;
1260 if (PortCapabilities
->MaximumPhysicalPages
== 0)
1262 PortCapabilities
->MaximumPhysicalPages
=
1263 BYTES_TO_PAGES(PortCapabilities
->MaximumTransferLength
);
1265 /* Apply miniport's limits */
1266 if (PortConfig
->NumberOfPhysicalBreaks
< PortCapabilities
->MaximumPhysicalPages
)
1268 PortCapabilities
->MaximumPhysicalPages
= PortConfig
->NumberOfPhysicalBreaks
;
1272 /* Deal with interrupts */
1273 if (DeviceExtension
->HwInterrupt
== NULL
||
1274 (PortConfig
->BusInterruptLevel
== 0 && PortConfig
->BusInterruptVector
== 0))
1277 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1279 /* FIXME: Use synchronization routine */
1280 ASSERT("No interrupts branch requires changes in synchronization\n");
1282 DeviceExtension
->Interrupt
= (PVOID
)DeviceExtension
;
1283 DPRINT("No interrupts\n");
1288 /* Are 2 interrupts needed? */
1289 if (DeviceExtension
->HwInterrupt
!= NULL
&&
1290 (PortConfig
->BusInterruptLevel
!= 0 || PortConfig
->BusInterruptVector
!= 0) &&
1291 (PortConfig
->BusInterruptLevel2
!= 0 || PortConfig
->BusInterruptVector2
!= 0))
1293 DPRINT1("2 interrupts requested! Not yet supported\n");
1298 BOOLEAN InterruptShareable
;
1300 /* No, only 1 interrupt */
1301 DPRINT("1 interrupt, IRQ is %d\n", PortConfig
->BusInterruptLevel
);
1303 DeviceExtension
->InterruptLevel
= PortConfig
->BusInterruptLevel
;
1305 /* Register an interrupt handler for this device */
1306 MappedIrq
= HalGetInterruptVector(PortConfig
->AdapterInterfaceType
,
1307 PortConfig
->SystemIoBusNumber
,
1308 PortConfig
->BusInterruptLevel
,
1309 PortConfig
->BusInterruptVector
,
1313 /* Determing IRQ sharability as usual */
1314 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1315 PortConfig
->InterruptMode
== LevelSensitive
)
1317 InterruptShareable
= TRUE
;
1321 InterruptShareable
= FALSE
;
1324 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
,
1325 (PKSERVICE_ROUTINE
)ScsiPortIsr
,
1331 PortConfig
->InterruptMode
,
1336 if (!(NT_SUCCESS(Status
)))
1338 DPRINT1("Could not connect interrupt %d\n",
1339 PortConfig
->BusInterruptVector
);
1340 DeviceExtension
->Interrupt
= NULL
;
1347 /* Save IoAddress (from access ranges) */
1348 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1350 DeviceExtension
->IoAddress
=
1351 ((*(PortConfig
->AccessRanges
))[0]).RangeStart
.LowPart
;
1353 DPRINT("Io Address %x\n", DeviceExtension
->IoAddress
);
1356 /* Set flag that it's allowed to disconnect during this command */
1357 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
1359 /* Initialize counter of active requests (-1 means there are none) */
1360 DeviceExtension
->ActiveRequestCounter
= -1;
1362 /* Analyze what we have about DMA */
1363 if (DeviceExtension
->AdapterObject
!= NULL
&&
1364 PortConfig
->Master
&&
1365 PortConfig
->NeedPhysicalAddresses
)
1367 DeviceExtension
->MapRegisters
= TRUE
;
1371 DeviceExtension
->MapRegisters
= FALSE
;
1374 /* Call HwInitialize at DISPATCH_LEVEL */
1375 KeRaiseIrql(DISPATCH_LEVEL
, &Dirql
);
1377 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1378 DeviceExtension
->HwInitialize
,
1379 DeviceExtension
->MiniPortDeviceExtension
))
1381 DPRINT1("HwInitialize() failed!\n");
1383 Status
= STATUS_ADAPTER_HARDWARE_ERROR
;
1387 /* Check if a notification is needed */
1388 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
1390 /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1391 ScsiPortDpcForIsr(NULL
,
1392 DeviceExtension
->DeviceObject
,
1397 /* Lower irql back to what it was */
1400 /* Start our timer */
1401 IoStartTimer(PortDeviceObject
);
1403 /* Initialize bus scanning information */
1404 DeviceExtension
->BusesConfig
= ExAllocatePool(PagedPool
,
1405 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1408 if (!DeviceExtension
->BusesConfig
)
1410 DPRINT1("Out of resources!\n");
1411 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1416 RtlZeroMemory(DeviceExtension
->BusesConfig
,
1417 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1420 /* Store number of buses there */
1421 DeviceExtension
->BusesConfig
->NumberOfBuses
= (UCHAR
)DeviceExtension
->BusNum
;
1423 /* Scan the adapter for devices */
1424 SpiScanAdapter(DeviceExtension
);
1426 /* Build the registry device map */
1427 SpiBuildDeviceMap(DeviceExtension
,
1428 (PUNICODE_STRING
)Argument2
);
1430 /* Create the dos device link */
1431 swprintf(DosNameBuffer
,
1433 SystemConfig
->ScsiPortCount
);
1434 RtlInitUnicodeString(&DosDeviceName
, DosNameBuffer
);
1435 IoCreateSymbolicLink(&DosDeviceName
, &DeviceName
);
1437 /* Increase the port count */
1438 SystemConfig
->ScsiPortCount
++;
1439 FirstConfigCall
= FALSE
;
1441 /* Increase adapter number and bus number respectively */
1442 ConfigInfo
.AdapterNumber
++;
1445 ConfigInfo
.BusNumber
++;
1447 DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber
, MaxBus
);
1452 /* Clean up the mess */
1453 SpiCleanupAfterInit(DeviceExtension
);
1455 /* Close registry keys */
1456 if (ConfigInfo
.ServiceKey
!= NULL
)
1457 ZwClose(ConfigInfo
.ServiceKey
);
1459 if (ConfigInfo
.DeviceKey
!= NULL
)
1460 ZwClose(ConfigInfo
.DeviceKey
);
1462 if (ConfigInfo
.BusKey
!= NULL
)
1463 ZwClose(ConfigInfo
.BusKey
);
1465 if (ConfigInfo
.AccessRanges
!= NULL
)
1466 ExFreePool(ConfigInfo
.AccessRanges
);
1468 if (ConfigInfo
.Parameter
!= NULL
)
1469 ExFreePool(ConfigInfo
.Parameter
);
1471 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %b!\n",
1472 Status
, DeviceFound
);
1474 return (DeviceFound
== FALSE
) ? Status
: STATUS_SUCCESS
;
1478 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1480 PSCSI_LUN_INFO LunInfo
;
1484 /* Check if we have something to clean up */
1485 if (DeviceExtension
== NULL
)
1488 /* Stop the timer and disconnect the interrupt */
1489 if (DeviceExtension
->Interrupt
)
1491 IoStopTimer(DeviceExtension
->DeviceObject
);
1492 IoDisconnectInterrupt(DeviceExtension
->Interrupt
);
1495 /* Delete ConfigInfo */
1496 if (DeviceExtension
->BusesConfig
)
1498 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
1500 if (!DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
])
1503 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
1507 /* Free current, but save pointer to the next one */
1508 Ptr
= LunInfo
->Next
;
1509 ExFreePool(LunInfo
);
1513 ExFreePool(DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]);
1516 ExFreePool(DeviceExtension
->BusesConfig
);
1519 /* Free PortConfig */
1520 if (DeviceExtension
->PortConfig
)
1521 ExFreePool(DeviceExtension
->PortConfig
);
1524 for(Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
1526 while (DeviceExtension
->LunExtensionList
[Lun
])
1528 Ptr
= DeviceExtension
->LunExtensionList
[Lun
];
1529 DeviceExtension
->LunExtensionList
[Lun
] = DeviceExtension
->LunExtensionList
[Lun
]->Next
;
1535 /* Free common buffer (if it exists) */
1536 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
&&
1537 DeviceExtension
->CommonBufferSize
!= 0)
1539 if (!DeviceExtension
->AdapterObject
)
1541 ExFreePool(DeviceExtension
->SrbExtensionBuffer
);
1546 HalFreeCommonBuffer(DeviceExtension
->AdapterObject
,
1547 DeviceExtension
->CommonBufferSize
,
1548 DeviceExtension
->PhysicalCommonBuffer
,
1549 DeviceExtension
->SrbExtensionBuffer
,
1556 if (DeviceExtension
->SrbInfo
!= NULL
)
1557 ExFreePool(DeviceExtension
->SrbInfo
);
1559 /* Unmap mapped addresses */
1560 while (DeviceExtension
->MappedAddressList
!= NULL
)
1562 MmUnmapIoSpace(DeviceExtension
->MappedAddressList
->MappedAddress
,
1563 DeviceExtension
->MappedAddressList
->NumberOfBytes
);
1565 Ptr
= DeviceExtension
->MappedAddressList
;
1566 DeviceExtension
->MappedAddressList
= DeviceExtension
->MappedAddressList
->NextMappedAddress
;
1571 /* Finally delete the device object */
1572 DPRINT("Deleting device %p\n", DeviceExtension
->DeviceObject
);
1573 IoDeleteDevice(DeviceExtension
->DeviceObject
);
1582 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
1583 IN PSCSI_REQUEST_BLOCK Srb
,
1584 IN PVOID LogicalAddress
,
1587 DPRINT1("ScsiPortIoMapTransfer()\n");
1596 ScsiPortLogError(IN PVOID HwDeviceExtension
,
1597 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
1604 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1606 DPRINT1("ScsiPortLogError() called\n");
1608 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1609 SCSI_PORT_DEVICE_EXTENSION
,
1610 MiniPortDeviceExtension
);
1613 DPRINT("ScsiPortLogError() done\n");
1621 ScsiPortMoveMemory(OUT PVOID Destination
,
1625 RtlMoveMemory(Destination
,
1635 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
1636 IN PVOID HwDeviceExtension
,
1639 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1642 DPRINT("ScsiPortNotification() called\n");
1644 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1645 SCSI_PORT_DEVICE_EXTENSION
,
1646 MiniPortDeviceExtension
);
1648 DPRINT("DeviceExtension %p\n", DeviceExtension
);
1650 va_start(ap
, HwDeviceExtension
);
1652 switch (NotificationType
)
1654 case RequestComplete
:
1656 PSCSI_REQUEST_BLOCK Srb
;
1657 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1659 Srb
= (PSCSI_REQUEST_BLOCK
) va_arg (ap
, PSCSI_REQUEST_BLOCK
);
1661 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb
);
1663 /* Make sure Srb is allright */
1664 ASSERT(Srb
->SrbStatus
!= SRB_STATUS_PENDING
);
1665 ASSERT(Srb
->Function
!= SRB_FUNCTION_EXECUTE_SCSI
|| Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
|| Srb
->ScsiStatus
== SCSISTAT_GOOD
);
1667 if (!(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
1669 /* It's been already completed */
1674 /* It's not active anymore */
1675 Srb
->SrbFlags
&= ~SRB_FLAGS_IS_ACTIVE
;
1677 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
1679 /* TODO: Treat it specially */
1684 /* Get the SRB data */
1685 SrbData
= SpiGetSrbData(DeviceExtension
,
1691 /* Make sure there are no CompletedRequests and there is a Srb */
1692 ASSERT(SrbData
->CompletedRequests
== NULL
&& SrbData
->Srb
!= NULL
);
1694 /* If it's a read/write request, make sure it has data inside it */
1695 if ((Srb
->SrbStatus
== SRB_STATUS_SUCCESS
) &&
1696 ((Srb
->Cdb
[0] == SCSIOP_READ
) || (Srb
->Cdb
[0] == SCSIOP_WRITE
)))
1698 ASSERT(Srb
->DataTransferLength
);
1701 SrbData
->CompletedRequests
= DeviceExtension
->InterruptData
.CompletedRequests
;
1702 DeviceExtension
->InterruptData
.CompletedRequests
= SrbData
;
1708 DPRINT("Notify: NextRequest\n");
1709 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1718 PathId
= (UCHAR
) va_arg (ap
, int);
1719 TargetId
= (UCHAR
) va_arg (ap
, int);
1720 Lun
= (UCHAR
) va_arg (ap
, int);
1722 DPRINT1 ("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1723 PathId
, TargetId
, Lun
);
1724 /* FIXME: Implement it! */
1727 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
1728 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT_LU;
1731 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
1736 DPRINT1("Notify: ResetDetected\n");
1741 DPRINT1 ("Unsupported notification %lu\n", NotificationType
);
1747 /* Request a DPC after we're done with the interrupt */
1748 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NOTIFICATION_NEEDED
;
1756 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
1757 IN ULONG BusDataType
,
1758 IN ULONG SystemIoBusNumber
,
1759 IN ULONG SlotNumber
,
1764 DPRINT("ScsiPortSetBusDataByOffset()\n");
1765 return(HalSetBusDataByOffset(BusDataType
,
1778 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
1779 IN INTERFACE_TYPE BusType
,
1780 IN ULONG SystemIoBusNumber
,
1781 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
1782 IN ULONG NumberOfBytes
,
1783 IN BOOLEAN InIoSpace
)
1785 DPRINT("ScsiPortValidateRange()\n");
1790 /* INTERNAL FUNCTIONS ********************************************************/
1793 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
1794 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
1795 IN PPORT_CONFIGURATION_INFORMATION PortConfig
)
1797 PACCESS_RANGE AccessRange
;
1798 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData
;
1804 /* Loop through all entries */
1805 for (Index
= 0; Index
< ResourceDescriptor
->PartialResourceList
.Count
; Index
++)
1807 PartialData
= &ResourceDescriptor
->PartialResourceList
.PartialDescriptors
[Index
];
1809 switch (PartialData
->Type
)
1811 case CmResourceTypePort
:
1812 /* Copy access ranges */
1813 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
1815 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
1817 AccessRange
->RangeStart
= PartialData
->u
.Port
.Start
;
1818 AccessRange
->RangeLength
= PartialData
->u
.Port
.Length
;
1820 AccessRange
->RangeInMemory
= FALSE
;
1825 case CmResourceTypeMemory
:
1826 /* Copy access ranges */
1827 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
1829 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
1831 AccessRange
->RangeStart
= PartialData
->u
.Memory
.Start
;
1832 AccessRange
->RangeLength
= PartialData
->u
.Memory
.Length
;
1834 AccessRange
->RangeInMemory
= TRUE
;
1839 case CmResourceTypeInterrupt
:
1840 /* Copy interrupt data */
1841 PortConfig
->BusInterruptLevel
= PartialData
->u
.Interrupt
.Level
;
1842 PortConfig
->BusInterruptVector
= PartialData
->u
.Interrupt
.Vector
;
1844 /* Set interrupt mode accordingly to the resource */
1845 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
1847 PortConfig
->InterruptMode
= Latched
;
1849 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
1851 PortConfig
->InterruptMode
= LevelSensitive
;
1855 case CmResourceTypeDma
:
1856 PortConfig
->DmaChannel
= PartialData
->u
.Dma
.Channel
;
1857 PortConfig
->DmaPort
= PartialData
->u
.Dma
.Port
;
1863 static PCM_RESOURCE_LIST
1864 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1865 PPORT_CONFIGURATION_INFORMATION PortConfig
)
1867 PCONFIGURATION_INFORMATION ConfigInfo
;
1868 PCM_RESOURCE_LIST ResourceList
;
1869 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
1870 PACCESS_RANGE AccessRange
;
1872 ULONG ListLength
= 0, i
, FullSize
;
1875 /* Get current Atdisk usage from the system */
1876 ConfigInfo
= IoGetConfigurationInformation();
1878 if (PortConfig
->AtdiskPrimaryClaimed
)
1879 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
1881 if (PortConfig
->AtdiskSecondaryClaimed
)
1882 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
1884 /* Do we use DMA? */
1885 if (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
||
1886 PortConfig
->DmaPort
!= SP_UNINITIALIZED_VALUE
)
1896 /* How many interrupts to we have? */
1897 if (DeviceExtension
->HwInterrupt
== NULL
||
1898 (PortConfig
->BusInterruptLevel
== 0 &&
1899 PortConfig
->BusInterruptVector
== 0))
1909 if (DeviceExtension
->HwInterrupt
!= NULL
&&
1910 (PortConfig
->BusInterruptLevel2
!= 0 ||
1911 PortConfig
->BusInterruptVector2
!= 0))
1917 /* How many access ranges do we use? */
1918 AccessRange
= &((*(PortConfig
->AccessRanges
))[0]);
1919 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
1921 if (AccessRange
->RangeLength
!= 0)
1927 /* Allocate the resource list, since we know its size now */
1928 FullSize
= sizeof(CM_RESOURCE_LIST
) + (ListLength
- 1) *
1929 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1931 ResourceList
= (PCM_RESOURCE_LIST
)ExAllocatePool(PagedPool
, FullSize
);
1937 RtlZeroMemory(ResourceList
, FullSize
);
1940 ResourceList
->Count
= 1;
1941 ResourceList
->List
[0].InterfaceType
= PortConfig
->AdapterInterfaceType
;
1942 ResourceList
->List
[0].BusNumber
= PortConfig
->SystemIoBusNumber
;
1943 ResourceList
->List
[0].PartialResourceList
.Count
= ListLength
;
1944 ResourceDescriptor
= ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
;
1946 /* Copy access ranges array over */
1947 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
1949 AccessRange
= &((*(PortConfig
->AccessRanges
))[i
]);
1951 /* If the range is empty - skip it */
1952 if (AccessRange
->RangeLength
== 0)
1955 if (AccessRange
->RangeInMemory
)
1957 ResourceDescriptor
->Type
= CmResourceTypeMemory
;
1958 ResourceDescriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
;
1962 ResourceDescriptor
->Type
= CmResourceTypePort
;
1963 ResourceDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
1966 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
1968 ResourceDescriptor
->u
.Memory
.Start
= AccessRange
->RangeStart
;
1969 ResourceDescriptor
->u
.Memory
.Length
= AccessRange
->RangeLength
;
1971 ResourceDescriptor
++;
1974 /* If we use interrupt(s), copy them */
1977 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
1979 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1980 PortConfig
->InterruptMode
== LevelSensitive
)
1982 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
1983 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
1987 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
1988 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
1991 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
1992 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
1993 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
1995 ResourceDescriptor
++;
1999 /* Copy 2nd interrupt
2000 FIXME: Stupid code duplication, remove */
2003 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2005 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2006 PortConfig
->InterruptMode
== LevelSensitive
)
2008 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2009 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2013 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2014 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2017 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
2018 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
2019 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2021 ResourceDescriptor
++;
2027 ResourceDescriptor
->Type
= CmResourceTypeDma
;
2028 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2029 ResourceDescriptor
->u
.Dma
.Channel
= PortConfig
->DmaChannel
;
2030 ResourceDescriptor
->u
.Dma
.Port
= PortConfig
->DmaPort
;
2031 ResourceDescriptor
->Flags
= 0;
2033 if (PortConfig
->DmaChannel
== SP_UNINITIALIZED_VALUE
)
2034 ResourceDescriptor
->u
.Dma
.Channel
= 0;
2036 if (PortConfig
->DmaPort
== SP_UNINITIALIZED_VALUE
)
2037 ResourceDescriptor
->u
.Dma
.Port
= 0;
2040 return ResourceList
;
2045 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
2046 IN PDEVICE_OBJECT DeviceObject
,
2047 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
2048 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
2049 IN PUNICODE_STRING RegistryPath
,
2051 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
)
2053 PCI_COMMON_CONFIG PciConfig
;
2054 PCI_SLOT_NUMBER SlotNumber
;
2057 ULONG FunctionNumber
;
2058 CHAR VendorIdString
[8];
2059 CHAR DeviceIdString
[8];
2060 UNICODE_STRING UnicodeStr
;
2061 PCM_RESOURCE_LIST ResourceList
;
2064 DPRINT ("SpiGetPciConfiguration() called\n");
2066 SlotNumber
.u
.AsULONG
= 0;
2068 /* Loop through all devices */
2069 for (DeviceNumber
= NextSlotNumber
->u
.bits
.DeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
2071 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
2073 /* Loop through all functions */
2074 for (FunctionNumber
= NextSlotNumber
->u
.bits
.FunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
2076 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
2078 /* Get PCI config bytes */
2079 DataSize
= HalGetBusData(PCIConfiguration
,
2081 SlotNumber
.u
.AsULONG
,
2085 /* There is nothing there */
2086 if (DataSize
< sizeof(ULONG
))
2089 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
2092 sprintf (VendorIdString
, "%04hx", PciConfig
.VendorID
);
2093 sprintf (DeviceIdString
, "%04hx", PciConfig
.DeviceID
);
2095 if (_strnicmp(VendorIdString
, HwInitializationData
->VendorId
, HwInitializationData
->VendorIdLength
) ||
2096 _strnicmp(DeviceIdString
, HwInitializationData
->DeviceId
, HwInitializationData
->DeviceIdLength
))
2098 /* It is not our device */
2102 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2106 SlotNumber
.u
.bits
.DeviceNumber
,
2107 SlotNumber
.u
.bits
.FunctionNumber
);
2110 RtlInitUnicodeString(&UnicodeStr
, L
"ScsiAdapter");
2111 Status
= HalAssignSlotResources(RegistryPath
,
2117 SlotNumber
.u
.AsULONG
,
2120 if (!NT_SUCCESS(Status
))
2123 /* Create configuration information */
2124 SpiResourceToConfig(HwInitializationData
,
2128 /* Free the resource list */
2129 ExFreePool(ResourceList
);
2131 /* Set dev & fn numbers */
2132 NextSlotNumber
->u
.bits
.DeviceNumber
= DeviceNumber
;
2133 NextSlotNumber
->u
.bits
.FunctionNumber
= FunctionNumber
+ 1;
2135 /* Save the slot number */
2136 PortConfig
->SlotNumber
= SlotNumber
.u
.AsULONG
;
2140 NextSlotNumber
->u
.bits
.FunctionNumber
= 0;
2143 NextSlotNumber
->u
.bits
.DeviceNumber
= 0;
2144 DPRINT ("No device found\n");
2151 /**********************************************************************
2153 * ScsiPortCreateClose
2156 * Answer requests for Create/Close calls: a null operation.
2163 * Pointer to a device object.
2166 * Pointer to an IRP.
2172 static NTSTATUS STDCALL
2173 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
2176 DPRINT("ScsiPortCreateClose()\n");
2178 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2179 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2181 return STATUS_SUCCESS
;
2185 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2188 PSCSI_LUN_INFO LunInfo
;
2189 PIO_STACK_LOCATION IrpStack
;
2190 PDEVICE_OBJECT DeviceObject
;
2191 PSCSI_REQUEST_BLOCK Srb
;
2194 /* Get pointer to the SRB */
2195 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2196 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
2198 /* Check if PathId matches number of buses */
2199 if (DeviceExtension
->BusesConfig
== NULL
||
2200 DeviceExtension
->BusesConfig
->NumberOfBuses
<= Srb
->PathId
)
2202 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2203 return STATUS_DEVICE_DOES_NOT_EXIST
;
2206 /* Get pointer to LunInfo */
2207 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Srb
->PathId
]->LunInfo
;
2209 /* Find matching LunInfo */
2212 if (LunInfo
->PathId
== Srb
->PathId
&&
2213 LunInfo
->TargetId
== Srb
->TargetId
&&
2214 LunInfo
->Lun
== Srb
->Lun
)
2219 LunInfo
= LunInfo
->Next
;
2222 /* If we couldn't find it - exit */
2223 if (LunInfo
== NULL
)
2224 return STATUS_DEVICE_DOES_NOT_EXIST
;
2228 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2230 /* Release, if asked */
2231 if (Srb
->Function
== SRB_FUNCTION_RELEASE_DEVICE
)
2233 LunInfo
->DeviceClaimed
= FALSE
;
2234 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2235 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2237 return STATUS_SUCCESS
;
2240 /* Attach, if not already claimed */
2241 if (LunInfo
->DeviceClaimed
)
2243 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2244 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
2246 return STATUS_DEVICE_BUSY
;
2249 /* Save the device object */
2250 DeviceObject
= LunInfo
->DeviceObject
;
2252 if (Srb
->Function
== SRB_FUNCTION_CLAIM_DEVICE
)
2253 LunInfo
->DeviceClaimed
= TRUE
;
2255 if (Srb
->Function
== SRB_FUNCTION_ATTACH_DEVICE
)
2256 LunInfo
->DeviceObject
= Srb
->DataBuffer
;
2258 Srb
->DataBuffer
= DeviceObject
;
2260 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2261 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2263 return STATUS_SUCCESS
;
2267 /**********************************************************************
2269 * ScsiPortDispatchScsi
2272 * Answer requests for SCSI calls
2278 * Standard dispatch arguments
2284 static NTSTATUS STDCALL
2285 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
2288 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2289 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2290 PIO_STACK_LOCATION Stack
;
2291 PSCSI_REQUEST_BLOCK Srb
;
2293 NTSTATUS Status
= STATUS_SUCCESS
;
2294 PIRP NextIrp
, IrpList
;
2295 PKDEVICE_QUEUE_ENTRY Entry
;
2297 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2300 DeviceExtension
= DeviceObject
->DeviceExtension
;
2301 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2303 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2306 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2307 Status
= STATUS_UNSUCCESSFUL
;
2309 Irp
->IoStatus
.Status
= Status
;
2310 Irp
->IoStatus
.Information
= 0;
2312 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2317 DPRINT("Srb: %p\n", Srb
);
2318 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
2319 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
2321 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2325 if (LunExtension
== NULL
)
2327 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2328 Status
= STATUS_NO_SUCH_DEVICE
;
2330 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2331 Irp
->IoStatus
.Status
= Status
;
2332 Irp
->IoStatus
.Information
= 0;
2334 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2339 switch (Srb
->Function
)
2341 case SRB_FUNCTION_SHUTDOWN
:
2342 case SRB_FUNCTION_FLUSH
:
2343 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2344 if (DeviceExtension
->CachesData
== FALSE
)
2346 /* All success here */
2347 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2348 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2349 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2350 return STATUS_SUCCESS
;
2352 /* Fall through to a usual execute operation */
2354 case SRB_FUNCTION_EXECUTE_SCSI
:
2355 case SRB_FUNCTION_IO_CONTROL
:
2356 /* Mark IRP as pending in all cases */
2357 IoMarkIrpPending(Irp
);
2359 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2361 /* Start IO directly */
2362 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2368 /* We need to be at DISPATCH_LEVEL */
2369 KeRaiseIrql (DISPATCH_LEVEL
, &oldIrql
);
2371 /* Insert IRP into the queue */
2372 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
2373 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
2376 /* It means the queue is empty, and we just start this request */
2377 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2380 /* Back to the old IRQL */
2381 KeLowerIrql (oldIrql
);
2383 return STATUS_PENDING
;
2385 case SRB_FUNCTION_CLAIM_DEVICE
:
2386 case SRB_FUNCTION_ATTACH_DEVICE
:
2387 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2389 /* Reference device object and keep the device object */
2390 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2393 case SRB_FUNCTION_RELEASE_DEVICE
:
2394 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2396 /* Dereference device object and clear the device object */
2397 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2400 case SRB_FUNCTION_RELEASE_QUEUE
:
2401 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2403 /* Guard with the spinlock */
2404 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2406 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2408 DPRINT("Queue is not frozen really\n");
2410 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2411 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2412 Status
= STATUS_SUCCESS
;
2417 /* Unfreeze the queue */
2418 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2420 if (LunExtension
->SrbInfo
.Srb
== NULL
)
2422 /* Get next logical unit request */
2423 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
2425 /* SpiGetNextRequestFromLun() releases the spinlock */
2430 DPRINT("The queue has active request\n");
2431 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2435 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2436 Status
= STATUS_SUCCESS
;
2439 case SRB_FUNCTION_FLUSH_QUEUE
:
2440 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2442 /* Guard with the spinlock */
2443 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2445 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2447 DPRINT("Queue is not frozen really\n");
2449 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2450 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2454 /* Make sure there is no active request */
2455 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
2457 /* Compile a list from the device queue */
2459 while ((Entry
= KeRemoveDeviceQueue(&LunExtension
->DeviceQueue
)) != NULL
)
2461 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
2464 Stack
= IoGetCurrentIrpStackLocation(NextIrp
);
2465 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2468 Srb
->SrbStatus
= SRB_STATUS_REQUEST_FLUSHED
;
2469 NextIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2471 /* Add then to the list */
2472 NextIrp
->Tail
.Overlay
.ListEntry
.Flink
= (PLIST_ENTRY
)IrpList
;
2476 /* Unfreeze the queue */
2477 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2479 /* Release the spinlock */
2480 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2482 /* Complete those requests */
2486 IrpList
= (PIRP
)NextIrp
->Tail
.Overlay
.ListEntry
.Flink
;
2488 IoCompleteRequest(NextIrp
, 0);
2491 Status
= STATUS_SUCCESS
;
2495 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
2496 Status
= STATUS_NOT_IMPLEMENTED
;
2500 Irp
->IoStatus
.Status
= Status
;
2502 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2508 /**********************************************************************
2510 * ScsiPortDeviceControl
2513 * Answer requests for device control calls
2519 * Standard dispatch arguments
2525 static NTSTATUS STDCALL
2526 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
2529 PIO_STACK_LOCATION Stack
;
2530 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2531 NTSTATUS Status
= STATUS_SUCCESS
;;
2533 DPRINT("ScsiPortDeviceControl()\n");
2535 Irp
->IoStatus
.Information
= 0;
2537 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2538 DeviceExtension
= DeviceObject
->DeviceExtension
;
2540 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
2542 case IOCTL_SCSI_GET_DUMP_POINTERS
:
2544 PDUMP_POINTERS DumpPointers
;
2545 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2546 DumpPointers
= (PDUMP_POINTERS
)Irp
->AssociatedIrp
.SystemBuffer
;
2547 DumpPointers
->DeviceObject
= DeviceObject
;
2549 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2553 case IOCTL_SCSI_GET_CAPABILITIES
:
2554 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2555 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
== sizeof(PVOID
))
2557 *((PVOID
*)Irp
->AssociatedIrp
.SystemBuffer
) = &DeviceExtension
->PortCapabilities
;
2559 Irp
->IoStatus
.Information
= sizeof(PVOID
);
2560 Status
= STATUS_SUCCESS
;
2564 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(IO_SCSI_CAPABILITIES
))
2566 Status
= STATUS_BUFFER_TOO_SMALL
;
2570 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2571 &DeviceExtension
->PortCapabilities
,
2572 sizeof(IO_SCSI_CAPABILITIES
));
2574 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
2575 Status
= STATUS_SUCCESS
;
2578 case IOCTL_SCSI_GET_INQUIRY_DATA
:
2579 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2581 /* Copy inquiry data to the port device extension */
2582 Status
= SpiGetInquiryData(DeviceExtension
, Irp
);
2586 DPRINT1(" unknown ioctl code: 0x%lX\n",
2587 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2591 /* Complete the request with the given status */
2592 Irp
->IoStatus
.Status
= Status
;
2593 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2600 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
2603 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2604 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2605 PIO_STACK_LOCATION IrpStack
;
2606 PSCSI_REQUEST_BLOCK Srb
;
2607 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2610 DPRINT("ScsiPortStartIo() called!\n");
2612 DeviceExtension
= DeviceObject
->DeviceExtension
;
2613 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2615 DPRINT("DeviceExtension %p\n", DeviceExtension
);
2617 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2619 /* Apply "default" flags */
2620 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
2622 /* Get LUN extension */
2623 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2628 if (DeviceExtension
->NeedSrbDataAlloc
||
2629 DeviceExtension
->NeedSrbExtensionAlloc
)
2631 /* TODO: Implement */
2637 /* No allocations are needed */
2638 SrbInfo
= &LunExtension
->SrbInfo
;
2639 Srb
->SrbExtension
= NULL
;
2640 Srb
->QueueTag
= SP_UNTAGGED
;
2643 /* Increase sequence number of SRB */
2644 if (!SrbInfo
->SequenceNumber
)
2646 /* Increase global sequence number */
2647 DeviceExtension
->SequenceNumber
++;
2650 SrbInfo
->SequenceNumber
= DeviceExtension
->SequenceNumber
;
2653 /* Check some special SRBs */
2654 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2656 /* Some special handling */
2657 DPRINT1("Abort command! Unimplemented now\n");
2664 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
)
2666 // Store the MDL virtual address in SrbInfo structure
2667 SrbInfo
->DataOffset
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2669 if (DeviceExtension
->MapBuffers
&& Irp
->MdlAddress
)
2671 /* Calculate offset within DataBuffer */
2672 SrbInfo
->DataOffset
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
2673 Srb
->DataBuffer
= SrbInfo
->DataOffset
+
2674 (ULONG
)((PUCHAR
)Srb
->DataBuffer
-
2675 (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2678 if (DeviceExtension
->AdapterObject
)
2681 KeFlushIoBuffers(Irp
->MdlAddress
,
2682 Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? TRUE
: FALSE
,
2686 if (DeviceExtension
->MapRegisters
)
2689 /* Calculate number of needed map registers */
2690 SrbInfo
->NumberOfMapRegisters
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
2692 Srb
->DataTransferLength
);
2694 /* Allocate adapter channel */
2695 Status
= IoAllocateAdapterChannel(DeviceExtension
->AdapterObject
,
2696 DeviceExtension
->DeviceObject
,
2697 SrbInfo
->NumberOfMapRegisters
,
2701 if (!NT_SUCCESS(Status
))
2703 DPRINT1("IoAllocateAdapterChannel() failed!\n");
2705 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
2706 ScsiPortNotification(RequestComplete
,
2707 DeviceExtension
+ 1,
2710 ScsiPortNotification(NextRequest
,
2711 DeviceExtension
+ 1);
2713 /* Request DPC for that work */
2714 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2717 /* Control goes to SpiAdapterControl */
2725 /* Increase active request counter */
2726 CounterResult
= InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
2728 if (CounterResult
== 0 &&
2729 DeviceExtension
->AdapterObject
!= NULL
&&
2730 !DeviceExtension
->MapRegisters
)
2733 IoAllocateAdapterChannel(
2734 DeviceExtension
->AdapterObject
,
2736 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
,
2737 ScsiPortAllocationRoutine
,
2743 /* TODO: DMA is not implemented yet */
2749 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
2751 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
2752 ScsiPortStartPacket
,
2755 DPRINT("Synchronization failed!\n");
2757 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2758 Irp
->IoStatus
.Information
= 0;
2759 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
2761 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2764 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
2766 DPRINT("ScsiPortStartIo() done\n");
2770 static BOOLEAN STDCALL
2771 ScsiPortStartPacket(IN OUT PVOID Context
)
2773 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2774 PIO_STACK_LOCATION IrpStack
;
2775 PSCSI_REQUEST_BLOCK Srb
;
2776 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)Context
;
2777 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2781 DPRINT("ScsiPortStartPacket() called\n");
2783 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
2785 IrpStack
= IoGetCurrentIrpStackLocation(DeviceObject
->CurrentIrp
);
2786 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2788 /* Get LUN extension */
2789 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2794 /* Check if we are in a reset state */
2795 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
2797 /* Mark the we've got requests while being in the reset state */
2798 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET_REQUEST
;
2802 /* Set the time out value */
2803 DeviceExtension
->TimerCount
= Srb
->TimeOutValue
;
2806 DeviceExtension
->Flags
|= SCSI_PORT_DEVICE_BUSY
;
2808 if (LunExtension
->RequestTimeout
!= -1)
2810 /* Timer already active */
2815 /* It hasn't been initialized yet */
2816 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
2820 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2822 /* Handle bypass-requests */
2824 /* Is this an abort request? */
2825 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2827 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2829 /* Get pointer to SRB info structure */
2830 SrbInfo
= SpiGetSrbData(DeviceExtension
,
2836 /* Check if the request is still "active" */
2837 if (SrbInfo
== NULL
||
2838 SrbInfo
->Srb
== NULL
||
2839 !(SrbInfo
->Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
2841 /* It's not, mark it as active then */
2842 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
2845 LunExtension
->RequestTimeout
= -1;
2847 DPRINT("Request has been already completed, but abort request came\n");
2848 Srb
->SrbStatus
= SRB_STATUS_ABORT_FAILED
;
2850 /* Notify about request complete */
2851 ScsiPortNotification(RequestComplete
,
2852 DeviceExtension
->MiniPortDeviceExtension
,
2855 /* and about readiness for the next request */
2856 ScsiPortNotification(NextRequest
,
2857 DeviceExtension
->MiniPortDeviceExtension
);
2859 /* They might ask for some work, so queue the DPC for them */
2860 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2862 /* We're done in this branch */
2868 /* Add number of queued requests */
2869 LunExtension
->QueueCount
++;
2872 /* Bypass requests don't need request sense */
2873 LunExtension
->Flags
&= ~LUNEX_NEED_REQUEST_SENSE
;
2875 /* Is disconnect disabled for this request? */
2876 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
2878 /* Set the corresponding flag */
2879 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
2882 /* Transfer timeout value from Srb to Lun */
2883 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
2887 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
2889 /* It's a disconnect, so no more requests can go */
2890 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
2893 LunExtension
->Flags
|= SCSI_PORT_LU_ACTIVE
;
2895 /* Increment queue count */
2896 LunExtension
->QueueCount
++;
2898 /* If it's tagged - special thing */
2899 if (Srb
->QueueTag
!= SP_UNTAGGED
)
2901 /* TODO: Support tagged requests */
2906 /* Mark this Srb active */
2907 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
2909 /* Call HwStartIo routine */
2910 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
2913 /* If notification is needed, then request a DPC */
2914 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
2915 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2920 static PSCSI_PORT_LUN_EXTENSION
2921 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
2923 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2924 ULONG LunExtensionSize
;
2926 DPRINT("SpiAllocateLunExtension (%p)\n",
2929 /* Round LunExtensionSize first to the sizeof LONGLONG */
2930 LunExtensionSize
= (DeviceExtension
->LunExtensionSize
+
2931 sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
2933 LunExtensionSize
+= sizeof(SCSI_PORT_LUN_EXTENSION
);
2934 DPRINT("LunExtensionSize %lu\n", LunExtensionSize
);
2936 LunExtension
= ExAllocatePool(NonPagedPool
, LunExtensionSize
);
2937 if (LunExtension
== NULL
)
2939 DPRINT1("Out of resources!\n");
2943 /* Zero everything */
2944 RtlZeroMemory(LunExtension
, LunExtensionSize
);
2946 /* Initialize a list of requests */
2947 InitializeListHead(&LunExtension
->SrbInfo
.Requests
);
2949 /* Initialize timeout counter */
2950 LunExtension
->RequestTimeout
= -1;
2952 /* Set maximum queue size */
2953 LunExtension
->MaxQueueCount
= 256;
2955 /* Initialize request queue */
2956 KeInitializeDeviceQueue (&LunExtension
->DeviceQueue
);
2958 return LunExtension
;
2961 static PSCSI_PORT_LUN_EXTENSION
2962 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2967 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2969 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
2970 DeviceExtension
, PathId
, TargetId
, Lun
);
2972 /* Get appropriate list */
2973 LunExtension
= DeviceExtension
->LunExtensionList
[(TargetId
+ Lun
) % LUS_NUMBER
];
2975 /* Iterate it until we find what we need */
2976 while (LunExtension
)
2978 if (LunExtension
->TargetId
== TargetId
&&
2979 LunExtension
->Lun
== Lun
&&
2980 LunExtension
->PathId
== PathId
)
2982 /* All matches, return */
2983 return LunExtension
;
2986 /* Advance to the next item */
2987 LunExtension
= LunExtension
->Next
;
2990 /* We did not find anything */
2991 DPRINT("Nothing found\n");
2997 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
2998 IN PSCSI_LUN_INFO LunInfo
)
3000 IO_STATUS_BLOCK IoStatusBlock
;
3001 PIO_STACK_LOCATION IrpStack
;
3006 PINQUIRYDATA InquiryBuffer
;
3007 PSENSE_DATA SenseBuffer
;
3008 BOOLEAN KeepTrying
= TRUE
;
3009 ULONG RetryCount
= 0;
3010 SCSI_REQUEST_BLOCK Srb
;
3012 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3013 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3015 DPRINT ("SpiSendInquiry() called\n");
3017 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3019 InquiryBuffer
= ExAllocatePool (NonPagedPool
, INQUIRYDATABUFFERSIZE
);
3020 if (InquiryBuffer
== NULL
)
3021 return STATUS_INSUFFICIENT_RESOURCES
;
3023 SenseBuffer
= ExAllocatePool (NonPagedPool
, SENSE_BUFFER_SIZE
);
3024 if (SenseBuffer
== NULL
)
3025 return STATUS_INSUFFICIENT_RESOURCES
;
3029 /* Initialize event for waiting */
3030 KeInitializeEvent(&Event
,
3035 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN
,
3040 INQUIRYDATABUFFERSIZE
,
3046 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3047 return STATUS_INSUFFICIENT_RESOURCES
;
3051 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3053 Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
3054 Srb
.OriginalRequest
= Irp
;
3055 Srb
.PathId
= LunInfo
->PathId
;
3056 Srb
.TargetId
= LunInfo
->TargetId
;
3057 Srb
.Lun
= LunInfo
->Lun
;
3058 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3059 Srb
.SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3060 Srb
.TimeOutValue
= 4;
3063 Srb
.SenseInfoBuffer
= SenseBuffer
;
3064 Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3066 Srb
.DataBuffer
= InquiryBuffer
;
3067 Srb
.DataTransferLength
= INQUIRYDATABUFFERSIZE
;
3069 /* Attach Srb to the Irp */
3070 IrpStack
= IoGetNextIrpStackLocation (Irp
);
3071 IrpStack
->Parameters
.Scsi
.Srb
= &Srb
;
3074 Cdb
= (PCDB
)Srb
.Cdb
;
3075 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_INQUIRY
;
3076 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= LunInfo
->Lun
;
3077 Cdb
->CDB6INQUIRY
.AllocationLength
= INQUIRYDATABUFFERSIZE
;
3079 /* Call the driver */
3080 Status
= IoCallDriver(DeviceObject
, Irp
);
3082 /* Wait for it to complete */
3083 if (Status
== STATUS_PENDING
)
3085 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3086 KeWaitForSingleObject(&Event
,
3091 Status
= IoStatusBlock
.Status
;
3094 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status
);
3096 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_SUCCESS
)
3098 /* All fine, copy data over */
3099 RtlCopyMemory(LunInfo
->InquiryData
,
3101 INQUIRYDATABUFFERSIZE
);
3103 Status
= STATUS_SUCCESS
;
3108 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb
.SrbStatus
);
3109 /* Check if the queue is frozen */
3110 if (Srb
.SrbStatus
& SRB_STATUS_QUEUE_FROZEN
)
3112 /* Something weird happened, deal with it (unfreeze the queue) */
3115 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb
.TargetId
);
3117 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3122 /* Clear frozen flag */
3123 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
3125 /* Acquire the spinlock */
3126 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
3128 /* Process the request */
3129 SpiGetNextRequestFromLun(DeviceObject
->DeviceExtension
, LunExtension
);
3131 /* SpiGetNextRequestFromLun() releases the spinlock,
3132 so we just lower irql back to what it was before */
3136 /* Check if data overrun happened */
3137 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
3139 DPRINT("Data overrun at TargetId %d\n", LunInfo
->TargetId
);
3140 /* Nothing dramatic, just copy data, but limiting the size */
3141 RtlCopyMemory(LunInfo
->InquiryData
,
3143 (Srb
.DataTransferLength
> INQUIRYDATABUFFERSIZE
) ?
3144 INQUIRYDATABUFFERSIZE
: Srb
.DataTransferLength
);
3146 Status
= STATUS_SUCCESS
;
3149 else if ((Srb
.SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3150 SenseBuffer
->SenseKey
== SCSI_SENSE_ILLEGAL_REQUEST
)
3152 /* LUN is not valid, but some device responds there.
3153 Mark it as invalid anyway */
3155 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3160 /* Retry a couple of times if no timeout happened */
3161 if ((RetryCount
< 2) &&
3162 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_NO_DEVICE
) &&
3163 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_SELECTION_TIMEOUT
))
3170 /* That's all, go to exit */
3173 /* Set status according to SRB status */
3174 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_FUNCTION
||
3175 SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH
)
3177 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3181 Status
= STATUS_IO_DEVICE_ERROR
;
3189 ExFreePool(InquiryBuffer
);
3190 ExFreePool(SenseBuffer
);
3192 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status
);
3198 /* Scans all SCSI buses */
3200 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3202 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3206 PSCSI_BUS_SCAN_INFO BusScanInfo
;
3207 PSCSI_LUN_INFO LastLunInfo
, LunInfo
, LunInfoExists
;
3208 BOOLEAN DeviceExists
;
3213 DPRINT("SpiScanAdapter() called\n");
3215 /* Scan all buses */
3216 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
3218 DPRINT(" Scanning bus %d\n", Bus
);
3221 /* Get pointer to the scan information */
3222 BusScanInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
];
3226 /* Find the last LUN info in the list */
3227 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3228 LastLunInfo
= LunInfo
;
3230 while (LunInfo
!= NULL
)
3232 LastLunInfo
= LunInfo
;
3233 LunInfo
= LunInfo
->Next
;
3238 /* We need to allocate this buffer */
3239 BusScanInfo
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_BUS_SCAN_INFO
));
3243 DPRINT1("Out of resources!\n");
3247 /* Store the pointer in the BusScanInfo array */
3248 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
] = BusScanInfo
;
3250 /* Fill this struct (length and bus ids for now) */
3251 BusScanInfo
->Length
= sizeof(SCSI_BUS_SCAN_INFO
);
3252 BusScanInfo
->LogicalUnitsCount
= 0;
3253 BusScanInfo
->BusIdentifier
= DeviceExtension
->PortConfig
->InitiatorBusId
[Bus
];
3254 BusScanInfo
->LunInfo
= NULL
;
3256 /* Set pointer to the last LUN info to NULL */
3260 /* Create LUN information structure */
3261 LunInfo
= ExAllocatePool(PagedPool
, sizeof(SCSI_LUN_INFO
));
3263 if (LunInfo
== NULL
)
3265 DPRINT1("Out of resources!\n");
3269 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3271 /* Create LunExtension */
3272 LunExtension
= SpiAllocateLunExtension (DeviceExtension
);
3274 /* And send INQUIRY to every target */
3275 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
3277 /* TODO: Support scan bottom-up */
3279 /* Skip if it's the same address */
3280 if (Target
== BusScanInfo
->BusIdentifier
)
3283 /* Try to find an existing device here */
3284 DeviceExists
= FALSE
;
3285 LunInfoExists
= BusScanInfo
->LunInfo
;
3287 /* Find matching address on this bus */
3288 while (LunInfoExists
)
3290 if (LunInfoExists
->TargetId
== Target
)
3292 DeviceExists
= TRUE
;
3296 /* Advance to the next one */
3297 LunInfoExists
= LunInfoExists
->Next
;
3300 /* No need to bother rescanning, since we already did that before */
3304 /* Scan all logical units */
3305 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
3310 /* Add extension to the list */
3311 Hint
= (Target
+ Lun
) % LUS_NUMBER
;
3312 LunExtension
->Next
= DeviceExtension
->LunExtensionList
[Hint
];
3313 DeviceExtension
->LunExtensionList
[Hint
] = LunExtension
;
3315 /* Fill Path, Target, Lun fields */
3316 LunExtension
->PathId
= LunInfo
->PathId
= (UCHAR
)Bus
;
3317 LunExtension
->TargetId
= LunInfo
->TargetId
= (UCHAR
) Target
;
3318 LunExtension
->Lun
= LunInfo
->Lun
= (UCHAR
)Lun
;
3320 /* Set flag to prevent race conditions */
3321 LunExtension
->Flags
|= SCSI_PORT_SCAN_IN_PROGRESS
;
3323 /* Zero LU extension contents */
3324 if (DeviceExtension
->LunExtensionSize
)
3326 RtlZeroMemory(LunExtension
+ 1,
3327 DeviceExtension
->LunExtensionSize
);
3330 /* Finally send the inquiry command */
3331 Status
= SpiSendInquiry(DeviceExtension
->DeviceObject
, LunInfo
);
3333 if (NT_SUCCESS(Status
))
3335 /* Let's see if we really found a device */
3336 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3338 /* Check if this device is unsupported */
3339 if (InquiryData
->DeviceTypeQualifier
== DEVICE_QUALIFIER_NOT_SUPPORTED
)
3341 DeviceExtension
->LunExtensionList
[Hint
] =
3342 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3347 /* Clear the "in scan" flag */
3348 LunExtension
->Flags
&= ~SCSI_PORT_SCAN_IN_PROGRESS
;
3350 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3351 InquiryData
->DeviceType
, Bus
, Target
, Lun
);
3353 /* Add this info to the linked list */
3354 LunInfo
->Next
= NULL
;
3356 LastLunInfo
->Next
= LunInfo
;
3358 BusScanInfo
->LunInfo
= LunInfo
;
3360 /* Store the last LUN info */
3361 LastLunInfo
= LunInfo
;
3363 /* Store DeviceObject */
3364 LunInfo
->DeviceObject
= DeviceExtension
->DeviceObject
;
3366 /* Allocate another buffer */
3367 LunInfo
= ExAllocatePool(PagedPool
, sizeof(SCSI_LUN_INFO
));
3371 DPRINT1("Out of resources!\n");
3375 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3377 /* Create a new LU extension */
3378 LunExtension
= SpiAllocateLunExtension(DeviceExtension
);
3384 /* Remove this LUN from the list */
3385 DeviceExtension
->LunExtensionList
[Hint
] =
3386 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3388 /* Decide whether we are continuing or not */
3389 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
3397 /* Free allocated buffers */
3399 ExFreePool(LunExtension
);
3402 ExFreePool(LunInfo
);
3404 /* Sum what we found */
3405 BusScanInfo
->LogicalUnitsCount
+= (UCHAR
) DevicesFound
;
3406 DPRINT(" Found %d devices on bus %d\n", DevicesFound
, Bus
);
3409 DPRINT ("SpiScanAdapter() done\n");
3414 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3417 ULONG InquiryDataSize
;
3418 PSCSI_LUN_INFO LunInfo
;
3419 ULONG BusCount
, LunCount
, Length
;
3420 PIO_STACK_LOCATION IrpStack
;
3421 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
3422 PSCSI_INQUIRY_DATA InquiryData
;
3423 PSCSI_BUS_DATA BusData
;
3427 DPRINT("SpiGetInquiryData() called\n");
3429 /* Get pointer to the buffer */
3430 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3431 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3433 /* Initialize bus and LUN counters */
3434 BusCount
= DeviceExtension
->BusesConfig
->NumberOfBuses
;
3437 /* Calculate total number of LUNs */
3438 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3439 LunCount
+= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3441 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
3443 ((sizeof(SCSI_INQUIRY_DATA
) - 1 + INQUIRYDATABUFFERSIZE
+
3444 sizeof(ULONG
) - 1) & ~(sizeof(ULONG
) - 1));
3446 /* Calculate data size */
3447 Length
= sizeof(SCSI_ADAPTER_BUS_INFO
) + (BusCount
- 1) *
3448 sizeof(SCSI_BUS_DATA
);
3450 Length
+= InquiryDataSize
* LunCount
;
3452 /* Check, if all data is going to fit into provided buffer */
3453 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< Length
)
3455 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3456 return STATUS_BUFFER_TOO_SMALL
;
3459 /* Store data size in the IRP */
3460 Irp
->IoStatus
.Information
= Length
;
3462 DPRINT("Data size: %lu\n", Length
);
3464 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
3466 AdapterBusInfo
->NumberOfBuses
= (UCHAR
)BusCount
;
3468 /* Point InquiryData to the corresponding place inside Buffer */
3469 InquiryData
= (PSCSI_INQUIRY_DATA
)(Buffer
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
3470 (BusCount
- 1) * sizeof(SCSI_BUS_DATA
));
3473 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3475 BusData
= &AdapterBusInfo
->BusData
[Bus
];
3477 /* Calculate and save an offset of the inquiry data */
3478 BusData
->InquiryDataOffset
= (PUCHAR
)InquiryData
- Buffer
;
3480 /* Get a pointer to the LUN information structure */
3481 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3483 /* Store Initiator Bus Id */
3484 BusData
->InitiatorBusId
=
3485 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->BusIdentifier
;
3487 /* Store LUN count */
3488 BusData
->NumberOfLogicalUnits
=
3489 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3492 while (LunInfo
!= NULL
)
3494 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
3495 Bus
, LunInfo
->TargetId
, LunInfo
->Lun
);
3497 /* Fill InquiryData with values */
3498 InquiryData
->PathId
= LunInfo
->PathId
;
3499 InquiryData
->TargetId
= LunInfo
->TargetId
;
3500 InquiryData
->Lun
= LunInfo
->Lun
;
3501 InquiryData
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
3502 InquiryData
->DeviceClaimed
= LunInfo
->DeviceClaimed
;
3503 InquiryData
->NextInquiryDataOffset
=
3504 (PUCHAR
)InquiryData
+ InquiryDataSize
- Buffer
;
3506 /* Copy data in it */
3507 RtlCopyMemory(InquiryData
->InquiryData
,
3508 LunInfo
->InquiryData
,
3509 INQUIRYDATABUFFERSIZE
);
3511 /* Move to the next LUN */
3512 LunInfo
= LunInfo
->Next
;
3513 InquiryData
= (PSCSI_INQUIRY_DATA
) ((PCHAR
)InquiryData
+ InquiryDataSize
);
3516 /* Either mark the end, or set offset to 0 */
3517 if (BusData
->NumberOfLogicalUnits
!= 0)
3518 ((PSCSI_INQUIRY_DATA
) ((PCHAR
) InquiryData
- InquiryDataSize
))->NextInquiryDataOffset
= 0;
3520 BusData
->InquiryDataOffset
= 0;
3523 /* Finish with success */
3524 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3525 return STATUS_SUCCESS
;
3528 static PSCSI_REQUEST_BLOCK_INFO
3529 SpiGetSrbData(IN PVOID DeviceExtension
,
3535 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3537 if (QueueTag
== SP_UNTAGGED
)
3539 /* Untagged request, get LU and return pointer to SrbInfo */
3540 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3545 /* Return NULL in case of error */
3549 /* Return the pointer to SrbInfo */
3550 return &LunExtension
->SrbInfo
;
3554 /* TODO: Implement when we have it */
3561 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3562 IN PSCSI_REQUEST_BLOCK InitialSrb
)
3564 PSCSI_REQUEST_BLOCK Srb
;
3567 PIO_STACK_LOCATION IrpStack
;
3568 LARGE_INTEGER LargeInt
;
3571 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb
);
3574 Srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
) + sizeof(PVOID
));
3575 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3578 LargeInt
.QuadPart
= (LONGLONG
) 1;
3579 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_READ
,
3580 DeviceExtension
->DeviceObject
,
3581 InitialSrb
->SenseInfoBuffer
,
3582 InitialSrb
->SenseInfoBufferLength
,
3586 IoSetCompletionRoutine(Irp
,
3587 (PIO_COMPLETION_ROUTINE
)SpiCompletionRoutine
,
3593 IrpStack
= IoGetNextIrpStackLocation(Irp
);
3594 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3596 /* Put Srb address into Irp... */
3597 IrpStack
->Parameters
.Others
.Argument1
= (PVOID
)Srb
;
3599 /* ...and vice versa */
3600 Srb
->OriginalRequest
= Irp
;
3603 Ptr
= (PVOID
*)(Srb
+1);
3606 /* Build CDB for REQUEST SENSE */
3608 Cdb
= (PCDB
)Srb
->Cdb
;
3610 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
3611 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= 0;
3612 Cdb
->CDB6INQUIRY
.Reserved1
= 0;
3613 Cdb
->CDB6INQUIRY
.PageCode
= 0;
3614 Cdb
->CDB6INQUIRY
.IReserved
= 0;
3615 Cdb
->CDB6INQUIRY
.AllocationLength
= (UCHAR
)InitialSrb
->SenseInfoBufferLength
;
3616 Cdb
->CDB6INQUIRY
.Control
= 0;
3619 Srb
->TargetId
= InitialSrb
->TargetId
;
3620 Srb
->Lun
= InitialSrb
->Lun
;
3621 Srb
->PathId
= InitialSrb
->PathId
;
3623 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3624 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
3626 /* Timeout will be 2 seconds */
3627 Srb
->TimeOutValue
= 2;
3629 /* No auto request sense */
3630 Srb
->SenseInfoBufferLength
= 0;
3631 Srb
->SenseInfoBuffer
= NULL
;
3633 /* Set necessary flags */
3634 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_BYPASS_FROZEN_QUEUE
|
3635 SRB_FLAGS_DISABLE_DISCONNECT
;
3637 /* Transfer disable synch transfer flag */
3638 if (InitialSrb
->SrbFlags
& SRB_FLAGS_DISABLE_SYNCH_TRANSFER
)
3639 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3641 Srb
->DataBuffer
= InitialSrb
->SenseInfoBuffer
;
3643 /* Fill the transfer length */
3644 Srb
->DataTransferLength
= InitialSrb
->SenseInfoBufferLength
;
3646 /* Clear statuses */
3647 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
3650 /* Call the driver */
3651 (VOID
)IoCallDriver(DeviceExtension
->DeviceObject
, Irp
);
3653 DPRINT("SpiSendRequestSense() done\n");
3660 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3661 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
3662 OUT PBOOLEAN NeedToCallStartIo
)
3664 PSCSI_REQUEST_BLOCK Srb
;
3665 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3668 ULONG SequenceNumber
;
3671 Irp
= Srb
->OriginalRequest
;
3673 /* Get Lun extension */
3674 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3679 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
&&
3680 DeviceExtension
->MapBuffers
&&
3683 /* MDL is shared if transfer is broken into smaller parts */
3684 Srb
->DataBuffer
= (PCCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
3685 ((PCCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
3687 /* In case of data going in, flush the buffers */
3688 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
3690 KeFlushIoBuffers(Irp
->MdlAddress
,
3697 /* Flush adapter if needed */
3698 if (SrbInfo
->BaseOfMapRegister
)
3700 /* TODO: Implement */
3704 /* Clear the request */
3705 SrbInfo
->Srb
= NULL
;
3707 /* If disconnect is disabled... */
3708 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3710 /* Acquire the spinlock since we mess with flags */
3711 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3713 /* Set corresponding flag */
3714 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
3716 /* Clear the timer if needed */
3717 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
))
3718 DeviceExtension
->TimerCount
= -1;
3720 /* Spinlock is not needed anymore */
3721 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3723 if (!(DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
) &&
3724 !(DeviceExtension
->Flags
& SCSI_PORT_DEVICE_BUSY
) &&
3725 !(*NeedToCallStartIo
))
3727 /* We're not busy, but we have a request pending */
3728 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
3732 /* Scatter/gather */
3733 if (Srb
->SrbFlags
& SRB_FLAGS_SGLIST_FROM_POOL
)
3735 /* TODO: Implement */
3739 /* Acquire spinlock (we're freeing SrbExtension) */
3740 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3742 /* Free it (if needed) */
3743 if (Srb
->SrbExtension
)
3745 if (Srb
->SenseInfoBuffer
!= NULL
&& DeviceExtension
->SupportsAutoSense
)
3747 ASSERT(Srb
->SenseInfoBuffer
== NULL
|| SrbInfo
->SaveSenseRequest
!= NULL
);
3749 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)
3751 /* Copy sense data to the buffer */
3752 RtlCopyMemory(SrbInfo
->SaveSenseRequest
,
3753 Srb
->SenseInfoBuffer
,
3754 Srb
->SenseInfoBufferLength
);
3757 /* And restore the pointer */
3758 Srb
->SenseInfoBuffer
= SrbInfo
->SaveSenseRequest
;
3761 /* Put it into the free srb extensions list */
3762 *((PVOID
*)Srb
->SrbExtension
) = DeviceExtension
->FreeSrbExtensions
;
3763 DeviceExtension
->FreeSrbExtensions
= Srb
->SrbExtension
;
3766 /* Save transfer length in the IRP */
3767 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
3769 SequenceNumber
= SrbInfo
->SequenceNumber
;
3770 SrbInfo
->SequenceNumber
= 0;
3772 /* Decrement the queue count */
3773 LunExtension
->QueueCount
--;
3775 /* Free Srb, if needed*/
3776 if (Srb
->QueueTag
!= SP_UNTAGGED
)
3778 /* Put it into the free list */
3779 SrbInfo
->Requests
.Blink
= NULL
;
3780 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
3781 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
3784 /* SrbInfo is not used anymore */
3787 if (DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
)
3789 /* Clear the flag */
3790 DeviceExtension
->Flags
&= ~SCSI_PORT_REQUEST_PENDING
;
3792 /* Note the caller about StartIo */
3793 *NeedToCallStartIo
= TRUE
;
3796 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
3798 /* Start the packet */
3799 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3801 if (!(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
) &&
3802 LunExtension
->RequestTimeout
== -1)
3804 /* Start the next packet */
3805 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
3809 /* Release the spinlock */
3810 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3813 DPRINT("IoCompleting request IRP 0x%08X\n", Irp
);
3815 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
3817 /* Decrement number of active requests, and analyze the result */
3818 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
3821 !DeviceExtension
->MapRegisters
&&
3822 DeviceExtension
->AdapterObject
!= NULL
)
3824 /* Nullify map registers */
3825 DeviceExtension
->MapRegisterBase
= NULL
;
3826 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
3829 /* Exit, we're done */
3833 /* Decrement number of active requests, and analyze the result */
3834 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
3837 !DeviceExtension
->MapRegisters
&&
3838 DeviceExtension
->AdapterObject
!= NULL
)
3840 /* Result is negative, so this is a slave, free map registers */
3841 DeviceExtension
->MapRegisterBase
= NULL
;
3842 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
3845 /* Convert status */
3846 Irp
->IoStatus
.Status
= SpiStatusSrbToNt(Srb
->SrbStatus
);
3848 /* It's not a bypass, it's busy or the queue is full? */
3849 if ((Srb
->ScsiStatus
== SCSISTAT_BUSY
||
3850 Srb
->SrbStatus
== SRB_STATUS_BUSY
||
3851 Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
) &&
3852 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
))
3855 DPRINT("Busy SRB status %x\n", Srb
->SrbStatus
);
3857 /* Requeu, if needed */
3858 if (LunExtension
->Flags
& (LUNEX_FROZEN_QUEUE
| LUNEX_BUSY
))
3860 DPRINT("it's being requeued\n");
3862 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
3863 Srb
->ScsiStatus
= 0;
3865 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
3866 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
3869 /* It's a big f.ck up if we got here */
3870 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
3871 Srb
->ScsiStatus
= SCSISTAT_BUSY
;
3877 /* Release the spinlock */
3878 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3881 else if (LunExtension
->AttemptCount
++ < 20)
3883 /* LUN is still busy */
3884 Srb
->ScsiStatus
= 0;
3885 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
3887 LunExtension
->BusyRequest
= Irp
;
3888 LunExtension
->Flags
|= LUNEX_BUSY
;
3890 /* Release the spinlock */
3891 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3896 /* Freeze the queue*/
3897 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
3898 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
3900 /* "Unfull" the queue */
3901 LunExtension
->Flags
&= ~LUNEX_FULL_QUEUE
;
3903 /* Release the spinlock */
3904 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3906 /* Return status that the device is not ready */
3907 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
3908 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
3914 /* Start the next request, if LUN is idle, and this is sense request */
3915 if (((Srb
->ScsiStatus
!= SCSISTAT_CHECK_CONDITION
) ||
3916 (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) ||
3917 !Srb
->SenseInfoBuffer
|| !Srb
->SenseInfoBufferLength
)
3918 && (Srb
->SrbFlags
& SRB_FLAGS_NO_QUEUE_FREEZE
))
3920 if (LunExtension
->RequestTimeout
== -1)
3921 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
3923 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3927 /* Freeze the queue */
3928 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
3929 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
3931 /* Do we need a request sense? */
3932 if (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
3933 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3934 Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
)
3936 /* If LUN is busy, we have to requeue it in order to allow request sense */
3937 if (LunExtension
->Flags
& LUNEX_BUSY
)
3939 DPRINT("Requeueing busy request to allow request sense\n");
3941 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
3942 &LunExtension
->BusyRequest
->Tail
.Overlay
.DeviceQueueEntry
,
3945 /* We should never get here */
3948 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3949 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
3954 /* Clear busy flags */
3955 LunExtension
->Flags
&= ~(LUNEX_FULL_QUEUE
| LUNEX_BUSY
);
3958 /* Release the spinlock */
3959 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3961 /* Send RequestSense */
3962 SpiSendRequestSense(DeviceExtension
, Srb
);
3968 /* Release the spinlock */
3969 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3972 /* Complete the request */
3973 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
3978 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
3982 PSCSI_REQUEST_BLOCK Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
3983 PSCSI_REQUEST_BLOCK InitialSrb
;
3986 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp
);
3988 if ((Srb
->Function
== SRB_FUNCTION_RESET_BUS
) ||
3989 (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
))
3991 /* Deallocate SRB and IRP and exit */
3995 return STATUS_MORE_PROCESSING_REQUIRED
;
3998 /* Get a pointer to the SRB and IRP which were initially sent */
3999 InitialSrb
= *((PVOID
*)(Srb
+1));
4000 InitialIrp
= InitialSrb
->OriginalRequest
;
4002 if ((SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
) ||
4003 (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_DATA_OVERRUN
))
4005 /* Sense data is OK */
4006 InitialSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
4008 /* Set length to be the same */
4009 InitialSrb
->SenseInfoBufferLength
= (UCHAR
)Srb
->DataTransferLength
;
4012 /* Make sure initial SRB's queue is frozen */
4013 ASSERT(InitialSrb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
);
4015 /* Complete this request */
4016 IoCompleteRequest(InitialIrp
, IO_DISK_INCREMENT
);
4018 /* Deallocate everything (internal) */
4021 if (Irp
->MdlAddress
!= NULL
)
4023 MmUnlockPages(Irp
->MdlAddress
);
4024 IoFreeMdl(Irp
->MdlAddress
);
4025 Irp
->MdlAddress
= NULL
;
4029 return STATUS_MORE_PROCESSING_REQUIRED
;
4034 static BOOLEAN STDCALL
4035 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
4036 IN PVOID ServiceContext
)
4038 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4041 DPRINT("ScsiPortIsr() called!\n");
4043 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
4045 /* If interrupts are disabled - we don't expect any */
4046 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_DISABLE_INTERRUPTS
)
4049 /* Call miniport's HwInterrupt routine */
4050 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
4052 /* If flag of notification is set - queue a DPC */
4053 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4055 IoRequestDpc(DeviceExtension
->DeviceObject
,
4056 DeviceExtension
->CurrentIrp
,
4065 SpiSaveInterruptData(IN PVOID Context
)
4067 PSCSI_PORT_SAVE_INTERRUPT InterruptContext
= Context
;
4068 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4069 PSCSI_REQUEST_BLOCK Srb
;
4070 PSCSI_REQUEST_BLOCK_INFO SrbInfo
, NextSrbInfo
;
4071 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4074 /* Get pointer to the device extension */
4075 DeviceExtension
= InterruptContext
->DeviceExtension
;
4077 /* If we don't have anything pending - return */
4078 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
))
4081 /* Actually save the interrupt data */
4082 *InterruptContext
->InterruptData
= DeviceExtension
->InterruptData
;
4084 /* Clear the data stored in the device extension */
4085 DeviceExtension
->InterruptData
.Flags
&=
4086 (SCSI_PORT_RESET
| SCSI_PORT_RESET_REQUEST
| SCSI_PORT_DISABLE_INTERRUPTS
);
4087 DeviceExtension
->InterruptData
.CompletedAbort
= NULL
;
4088 DeviceExtension
->InterruptData
.ReadyLun
= NULL
;
4089 DeviceExtension
->InterruptData
.CompletedRequests
= NULL
;
4091 /* Loop through the list of completed requests */
4092 SrbInfo
= InterruptContext
->InterruptData
->CompletedRequests
;
4096 /* Make sure we have SRV */
4097 ASSERT(SrbInfo
->Srb
);
4099 /* Get SRB and LunExtension */
4102 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4107 /* We have to check special cases if request is unsuccessfull*/
4108 if (Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
)
4110 /* Check if we need request sense by a few conditions */
4111 if (Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
&&
4112 Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4113 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
))
4115 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
4117 /* It means: we tried to send REQUEST SENSE, but failed */
4119 Srb
->ScsiStatus
= 0;
4120 Srb
->SrbStatus
= SRB_STATUS_REQUEST_SENSE_FAILED
;
4124 /* Set the corresponding flag, so that REQUEST SENSE
4126 LunExtension
->Flags
|= LUNEX_NEED_REQUEST_SENSE
;
4131 /* Check for a full queue */
4132 if (Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
)
4134 /* TODO: Implement when it's encountered */
4139 /* Let's decide if we need to watch timeout or not */
4140 if (Srb
->QueueTag
== SP_UNTAGGED
)
4146 if (LunExtension
->SrbInfo
.Requests
.Flink
== &SrbInfo
->Requests
)
4151 /* Remove it from the queue */
4152 RemoveEntryList(&SrbInfo
->Requests
);
4157 /* We have to maintain timeout counter */
4158 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
))
4160 LunExtension
->RequestTimeout
= -1;
4164 NextSrbInfo
= CONTAINING_RECORD(LunExtension
->SrbInfo
.Requests
.Flink
,
4165 SCSI_REQUEST_BLOCK_INFO
,
4168 Srb
= NextSrbInfo
->Srb
;
4170 /* Update timeout counter */
4171 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
4175 SrbInfo
= SrbInfo
->CompletedRequests
;
4183 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4184 IN PSCSI_PORT_LUN_EXTENSION LunExtension
)
4186 PIO_STACK_LOCATION IrpStack
;
4188 PKDEVICE_QUEUE_ENTRY Entry
;
4189 PSCSI_REQUEST_BLOCK Srb
;
4192 /* If LUN is not active or queue is more than maximum allowed */
4193 if (LunExtension
->QueueCount
>= LunExtension
->MaxQueueCount
||
4194 !(LunExtension
->Flags
& SCSI_PORT_LU_ACTIVE
))
4196 /* Release the spinlock and exit */
4197 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4201 /* Check if we can get a next request */
4202 if (LunExtension
->Flags
&
4203 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_BUSY
|
4204 LUNEX_FULL_QUEUE
| LUNEX_FROZEN_QUEUE
| LUNEX_REQUEST_PENDING
))
4206 /* Pending requests can only be started if the queue is empty */
4207 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
) &&
4208 !(LunExtension
->Flags
&
4209 (LUNEX_BUSY
| LUNEX_FROZEN_QUEUE
| LUNEX_FULL_QUEUE
| LUNEX_NEED_REQUEST_SENSE
)))
4211 /* Make sure we have SRB */
4212 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
4214 /* Clear active and pending flags */
4215 LunExtension
->Flags
&= ~(LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
);
4217 /* Get next Irp, and clear pending requests list */
4218 NextIrp
= LunExtension
->PendingRequest
;
4219 LunExtension
->PendingRequest
= NULL
;
4221 /* Set attempt counter to zero */
4222 LunExtension
->AttemptCount
= 0;
4224 /* Release the spinlock */
4225 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4227 /* Start the next pending request */
4228 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4234 /* Release the spinlock, without clearing any flags and exit */
4235 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4241 /* Reset active flag */
4242 LunExtension
->Flags
&= ~SCSI_PORT_LU_ACTIVE
;
4244 /* Set attempt counter to zero */
4245 LunExtension
->AttemptCount
= 0;
4247 /* Remove packet from the device queue */
4248 Entry
= KeRemoveByKeyDeviceQueue(&LunExtension
->DeviceQueue
, LunExtension
->SortKey
);
4252 /* Get pointer to the next irp */
4253 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
4255 /* Get point to the SRB */
4256 IrpStack
= IoGetCurrentIrpStackLocation(NextIrp
);
4257 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
4260 LunExtension
->SortKey
= Srb
->QueueSortKey
;
4261 LunExtension
->SortKey
++;
4263 /* Release the spinlock */
4264 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4266 /* Start the next pending request */
4267 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4271 /* Release the spinlock */
4272 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4278 // ScsiPortDpcForIsr
4285 // IN PDEVICE_OBJECT DpcDeviceObject
4287 // IN PVOID DpcContext
4290 ScsiPortDpcForIsr(IN PKDPC Dpc
,
4291 IN PDEVICE_OBJECT DpcDeviceObject
,
4293 IN PVOID DpcContext
)
4295 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DpcDeviceObject
->DeviceExtension
;
4296 SCSI_PORT_INTERRUPT_DATA InterruptData
;
4297 SCSI_PORT_SAVE_INTERRUPT Context
;
4298 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4299 BOOLEAN NeedToStartIo
;
4300 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
4302 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4303 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
4305 /* We need to acquire spinlock */
4306 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4310 /* Interrupt structure must be snapshotted, and only then analyzed */
4311 Context
.InterruptData
= &InterruptData
;
4312 Context
.DeviceExtension
= DeviceExtension
;
4314 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4315 SpiSaveInterruptData
,
4318 /* Nothing - just return (don't forget to release the spinlock */
4319 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4320 DPRINT("ScsiPortDpcForIsr() done\n");
4324 /* If flush of adapters is needed - do it */
4325 if (InterruptData
.Flags
& SCSI_PORT_FLUSH_ADAPTERS
)
4327 /* TODO: Implement */
4331 /* Check for IoMapTransfer */
4332 if (InterruptData
.Flags
& SCSI_PORT_MAP_TRANSFER
)
4334 /* TODO: Implement */
4338 /* Check if timer is needed */
4339 if (InterruptData
.Flags
& SCIS_PORT_TIMER_NEEDED
)
4341 /* TODO: Implement */
4345 /* If it's ready for the next request */
4346 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4348 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4349 if ((DeviceExtension
->Flags
&
4350 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
)) ==
4351 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
))
4353 /* Clear busy flag set by ScsiPortStartPacket() */
4354 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4356 if (!(InterruptData
.Flags
& SCSI_PORT_RESET
))
4358 /* Ready for next, and no reset is happening */
4359 DeviceExtension
->TimerCount
= -1;
4364 /* Not busy, but not ready for the next request */
4365 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4366 InterruptData
.Flags
&= ~SCSI_PORT_NEXT_REQUEST_READY
;
4371 if (InterruptData
.Flags
& SCSI_PORT_RESET_REPORTED
)
4373 /* Hold for a bit */
4374 DeviceExtension
->TimerCount
= 4;
4377 /* Any ready LUN? */
4378 if (InterruptData
.ReadyLun
!= NULL
)
4381 /* Process all LUNs from the list*/
4384 /* Remove it from the list first (as processed) */
4385 LunExtension
= InterruptData
.ReadyLun
;
4386 InterruptData
.ReadyLun
= LunExtension
->ReadyLun
;
4387 LunExtension
->ReadyLun
= NULL
;
4389 /* Get next request for this LUN */
4390 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4392 /* Still ready requests exist?
4393 If yes - get spinlock, if no - stop here */
4394 if (InterruptData
.ReadyLun
!= NULL
)
4395 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4402 /* Release the spinlock */
4403 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4406 /* If we ready for next packet, start it */
4407 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4408 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4410 NeedToStartIo
= FALSE
;
4412 /* Loop the completed request list */
4413 while (InterruptData
.CompletedRequests
)
4415 /* Remove the request */
4416 SrbInfo
= InterruptData
.CompletedRequests
;
4417 InterruptData
.CompletedRequests
= SrbInfo
->CompletedRequests
;
4418 SrbInfo
->CompletedRequests
= NULL
;
4421 SpiProcessCompletedRequest(DeviceExtension
,
4426 /* Loop abort request list */
4427 while (InterruptData
.CompletedAbort
)
4429 LunExtension
= InterruptData
.CompletedAbort
;
4431 /* Remove the request */
4432 InterruptData
.CompletedAbort
= LunExtension
->CompletedAbortRequests
;
4434 /* Get spinlock since we're going to change flags */
4435 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4437 /* TODO: Put SrbExtension to the list of free extensions */
4441 /* If we need - call StartIo routine */
4444 /* Make sure CurrentIrp is not null! */
4445 ASSERT(DpcDeviceObject
->CurrentIrp
!= NULL
);
4446 ScsiPortStartIo(DpcDeviceObject
, DpcDeviceObject
->CurrentIrp
);
4449 /* Everything has been done, check */
4450 if (InterruptData
.Flags
& SCSI_PORT_ENABLE_INT_REQUEST
)
4452 /* Synchronize using spinlock */
4453 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4455 /* Request an interrupt */
4456 DeviceExtension
->HwInterrupt(DeviceExtension
->MiniPortDeviceExtension
);
4458 ASSERT(DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
);
4460 /* Should interrupts be enabled again? */
4461 if (DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
)
4463 /* Clear this flag */
4464 DeviceExtension
->Flags
&= ~SCSI_PORT_DISABLE_INT_REQUESET
;
4466 /* Call a special routine to do this */
4469 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4470 SpiEnableInterrupts
,
4475 /* If we need a notification again - loop */
4476 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4479 /* Release the spinlock */
4480 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4483 DPRINT("ScsiPortDpcForIsr() done\n");
4488 SpiProcessTimeout(PVOID ServiceContext
)
4490 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
4491 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
4494 DPRINT("SpiProcessTimeout() entered\n");
4496 DeviceExtension
->TimerCount
= -1;
4498 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
4500 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET
;
4502 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET_REQUEST
)
4504 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET_REQUEST
;
4505 ScsiPortStartPacket(ServiceContext
);
4512 DPRINT("Resetting the bus\n");
4514 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
4516 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
, Bus
);
4518 /* Reset flags and set reset timeout to 4 seconds */
4519 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
4520 DeviceExtension
->TimerCount
= 4;
4523 /* If miniport requested - request a dpc for it */
4524 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4525 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
4534 SpiResetBus(PVOID ServiceContext
)
4536 PRESETBUS_PARAMS ResetParams
= (PRESETBUS_PARAMS
)ServiceContext
;
4537 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4539 /* Perform the bus reset */
4540 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ResetParams
->DeviceExtension
;
4541 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
,
4542 ResetParams
->PathId
);
4544 /* Set flags and start the timer */
4545 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
4546 DeviceExtension
->TimerCount
= 4;
4548 /* If miniport requested - give him a DPC */
4549 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4550 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
4557 // This function handles timeouts and other time delayed processing
4562 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
4563 // IN PVOID Context the Controller extension for the
4564 // controller the device is on
4567 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
4570 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4571 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4575 DPRINT("ScsiPortIoTimer()\n");
4577 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
4579 /* Protect with the spinlock */
4580 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4582 /* Check timeouts */
4583 if (DeviceExtension
->TimerCount
> 0)
4585 /* Decrease the timeout counter */
4586 DeviceExtension
->TimerCount
--;
4588 if (DeviceExtension
->TimerCount
== 0)
4590 /* Timeout, process it */
4591 if (KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4593 DeviceExtension
->DeviceObject
))
4595 DPRINT("Error happened during processing timeout, but nothing critical\n");
4599 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4601 /* We should exit now, since timeout is processed */
4605 /* Per-Lun scanning of timeouts is needed... */
4606 for (Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
4608 LunExtension
= DeviceExtension
->LunExtensionList
[Lun
];
4610 while (LunExtension
)
4612 if (LunExtension
->Flags
& LUNEX_BUSY
)
4614 if (!(LunExtension
->Flags
&
4615 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_FROZEN_QUEUE
)))
4617 DPRINT("Retrying busy request\n");
4619 /* Clear flags, and retry busy request */
4620 LunExtension
->Flags
&= ~(LUNEX_BUSY
| LUNEX_FULL_QUEUE
);
4621 Irp
= LunExtension
->BusyRequest
;
4623 /* Clearing busy request */
4624 LunExtension
->BusyRequest
= NULL
;
4626 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4628 IoStartPacket(DeviceObject
, Irp
, (PULONG
)NULL
, NULL
);
4630 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4633 else if (LunExtension
->RequestTimeout
== 0)
4635 RESETBUS_PARAMS ResetParams
;
4637 LunExtension
->RequestTimeout
= -1;
4639 DPRINT("Request timed out, resetting bus\n");
4641 /* Pass params to the bus reset routine */
4642 ResetParams
.PathId
= LunExtension
->PathId
;
4643 ResetParams
.DeviceExtension
= DeviceExtension
;
4645 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4649 DPRINT1("Reset failed\n");
4652 else if (LunExtension
->RequestTimeout
> 0)
4654 /* Decrement the timeout counter */
4655 LunExtension
->RequestTimeout
--;
4658 LunExtension
= LunExtension
->Next
;
4662 /* Release the spinlock */
4663 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4666 /**********************************************************************
4671 * Builds the registry device map of all device which are attached
4672 * to the given SCSI HBA port. The device map is located at:
4673 * \Registry\Machine\DeviceMap\Scsi
4683 * Name of registry driver service key.
4690 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4691 PUNICODE_STRING RegistryPath
)
4693 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4694 OBJECT_ATTRIBUTES ObjectAttributes
;
4695 UNICODE_STRING KeyName
;
4696 UNICODE_STRING ValueName
;
4697 WCHAR NameBuffer
[64];
4700 HANDLE ScsiPortKey
= NULL
;
4701 HANDLE ScsiBusKey
= NULL
;
4702 HANDLE ScsiInitiatorKey
= NULL
;
4703 HANDLE ScsiTargetKey
= NULL
;
4704 HANDLE ScsiLunKey
= NULL
;
4707 ULONG CurrentTarget
;
4714 DPRINT("SpiBuildDeviceMap() called\n");
4716 if (DeviceExtension
== NULL
|| RegistryPath
== NULL
)
4718 DPRINT1("Invalid parameter\n");
4719 return(STATUS_INVALID_PARAMETER
);
4722 /* Open or create the 'Scsi' subkey */
4723 RtlInitUnicodeString(&KeyName
,
4724 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
4725 InitializeObjectAttributes(&ObjectAttributes
,
4727 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
4730 Status
= ZwCreateKey(&ScsiKey
,
4735 REG_OPTION_VOLATILE
,
4737 if (!NT_SUCCESS(Status
))
4739 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4743 /* Create new 'Scsi Port X' subkey */
4744 DPRINT("Scsi Port %lu\n",
4745 DeviceExtension
->PortNumber
);
4747 swprintf(NameBuffer
,
4749 DeviceExtension
->PortNumber
);
4750 RtlInitUnicodeString(&KeyName
,
4752 InitializeObjectAttributes(&ObjectAttributes
,
4757 Status
= ZwCreateKey(&ScsiPortKey
,
4762 REG_OPTION_VOLATILE
,
4765 if (!NT_SUCCESS(Status
))
4767 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4772 * Create port-specific values
4775 /* Set 'DMA Enabled' (REG_DWORD) value */
4776 UlongData
= (ULONG
)!DeviceExtension
->PortCapabilities
.AdapterUsesPio
;
4777 DPRINT(" DMA Enabled = %s\n", (UlongData
) ? "TRUE" : "FALSE");
4778 RtlInitUnicodeString(&ValueName
,
4780 Status
= ZwSetValueKey(ScsiPortKey
,
4786 if (!NT_SUCCESS(Status
))
4788 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status
);
4789 ZwClose(ScsiPortKey
);
4793 /* Set 'Driver' (REG_SZ) value */
4794 DriverName
= wcsrchr(RegistryPath
->Buffer
, L
'\\') + 1;
4795 RtlInitUnicodeString(&ValueName
,
4797 Status
= ZwSetValueKey(ScsiPortKey
,
4802 (wcslen(DriverName
) + 1) * sizeof(WCHAR
));
4803 if (!NT_SUCCESS(Status
))
4805 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status
);
4806 ZwClose(ScsiPortKey
);
4810 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
4811 UlongData
= (ULONG
)DeviceExtension
->PortConfig
->BusInterruptLevel
;
4812 DPRINT(" Interrupt = %lu\n", UlongData
);
4813 RtlInitUnicodeString(&ValueName
,
4815 Status
= ZwSetValueKey(ScsiPortKey
,
4821 if (!NT_SUCCESS(Status
))
4823 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status
);
4824 ZwClose(ScsiPortKey
);
4828 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
4829 UlongData
= ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension
->PortConfig
->AccessRanges
)[0].RangeStart
);
4830 DPRINT(" IOAddress = %lx\n", UlongData
);
4831 RtlInitUnicodeString(&ValueName
,
4833 Status
= ZwSetValueKey(ScsiPortKey
,
4839 if (!NT_SUCCESS(Status
))
4841 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status
);
4842 ZwClose(ScsiPortKey
);
4846 /* Enumerate buses */
4847 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
->NumberOfBuses
; BusNumber
++)
4849 /* Create 'Scsi Bus X' key */
4850 DPRINT(" Scsi Bus %lu\n", BusNumber
);
4851 swprintf(NameBuffer
,
4854 RtlInitUnicodeString(&KeyName
,
4856 InitializeObjectAttributes(&ObjectAttributes
,
4861 Status
= ZwCreateKey(&ScsiBusKey
,
4866 REG_OPTION_VOLATILE
,
4868 if (!NT_SUCCESS(Status
))
4870 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4874 /* Create 'Initiator Id X' key */
4875 DPRINT(" Initiator Id %u\n",
4876 DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
4877 swprintf(NameBuffer
,
4879 (unsigned int)(UCHAR
)DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
4880 RtlInitUnicodeString(&KeyName
,
4882 InitializeObjectAttributes(&ObjectAttributes
,
4887 Status
= ZwCreateKey(&ScsiInitiatorKey
,
4892 REG_OPTION_VOLATILE
,
4894 if (!NT_SUCCESS(Status
))
4896 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4900 /* FIXME: Are there any initiator values (??) */
4902 ZwClose(ScsiInitiatorKey
);
4903 ScsiInitiatorKey
= NULL
;
4906 /* Enumerate targets */
4907 CurrentTarget
= (ULONG
)-1;
4908 ScsiTargetKey
= NULL
;
4909 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
4911 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
4913 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4917 if (LunExtension
!= NULL
)
4919 if (Target
!= CurrentTarget
)
4921 /* Close old target key */
4922 if (ScsiTargetKey
!= NULL
)
4924 ZwClose(ScsiTargetKey
);
4925 ScsiTargetKey
= NULL
;
4928 /* Create 'Target Id X' key */
4929 DPRINT(" Target Id %lu\n", Target
);
4930 swprintf(NameBuffer
,
4933 RtlInitUnicodeString(&KeyName
,
4935 InitializeObjectAttributes(&ObjectAttributes
,
4940 Status
= ZwCreateKey(&ScsiTargetKey
,
4945 REG_OPTION_VOLATILE
,
4947 if (!NT_SUCCESS(Status
))
4949 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4953 CurrentTarget
= Target
;
4956 /* Create 'Logical Unit Id X' key */
4957 DPRINT(" Logical Unit Id %lu\n", Lun
);
4958 swprintf(NameBuffer
,
4959 L
"Logical Unit Id %lu",
4961 RtlInitUnicodeString(&KeyName
,
4963 InitializeObjectAttributes(&ObjectAttributes
,
4968 Status
= ZwCreateKey(&ScsiLunKey
,
4973 REG_OPTION_VOLATILE
,
4975 if (!NT_SUCCESS(Status
))
4977 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4981 /* Set 'Identifier' (REG_SZ) value */
4982 swprintf(NameBuffer
,
4984 LunExtension
->InquiryData
.VendorId
,
4985 LunExtension
->InquiryData
.ProductId
,
4986 LunExtension
->InquiryData
.ProductRevisionLevel
);
4987 DPRINT(" Identifier = '%S'\n", NameBuffer
);
4988 RtlInitUnicodeString(&ValueName
,
4990 Status
= ZwSetValueKey(ScsiLunKey
,
4995 (wcslen(NameBuffer
) + 1) * sizeof(WCHAR
));
4996 if (!NT_SUCCESS(Status
))
4998 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status
);
5002 /* Set 'Type' (REG_SZ) value */
5003 switch (LunExtension
->InquiryData
.DeviceType
)
5006 TypeName
= L
"DiskPeripheral";
5009 TypeName
= L
"TapePeripheral";
5012 TypeName
= L
"PrinterPeripheral";
5015 TypeName
= L
"WormPeripheral";
5018 TypeName
= L
"CdRomPeripheral";
5021 TypeName
= L
"ScannerPeripheral";
5024 TypeName
= L
"OpticalDiskPeripheral";
5027 TypeName
= L
"MediumChangerPeripheral";
5030 TypeName
= L
"CommunicationPeripheral";
5033 TypeName
= L
"OtherPeripheral";
5036 DPRINT(" Type = '%S'\n", TypeName
);
5037 RtlInitUnicodeString(&ValueName
,
5039 Status
= ZwSetValueKey(ScsiLunKey
,
5044 (wcslen(TypeName
) + 1) * sizeof(WCHAR
));
5045 if (!NT_SUCCESS(Status
))
5047 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status
);
5051 ZwClose(ScsiLunKey
);
5056 /* Close old target key */
5057 if (ScsiTargetKey
!= NULL
)
5059 ZwClose(ScsiTargetKey
);
5060 ScsiTargetKey
= NULL
;
5064 ZwClose(ScsiBusKey
);
5069 if (ScsiLunKey
!= NULL
)
5070 ZwClose (ScsiLunKey
);
5072 if (ScsiInitiatorKey
!= NULL
)
5073 ZwClose (ScsiInitiatorKey
);
5075 if (ScsiTargetKey
!= NULL
)
5076 ZwClose (ScsiTargetKey
);
5078 if (ScsiBusKey
!= NULL
)
5079 ZwClose (ScsiBusKey
);
5081 if (ScsiPortKey
!= NULL
)
5082 ZwClose (ScsiPortKey
);
5084 DPRINT("SpiBuildDeviceMap() done\n");
5091 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
5092 IN PVOID DeviceObject
,
5093 IN PVOID SystemArgument1
,
5094 IN PVOID SystemArgument2
)
5096 DPRINT1("Miniport timer DPC\n");
5100 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5101 PHW_INITIALIZATION_DATA HwInitData
,
5102 PCONFIGURATION_INFO InternalConfigInfo
,
5103 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5106 UNICODE_STRING UnicodeString
;
5107 OBJECT_ATTRIBUTES ObjectAttributes
;
5108 PCONFIGURATION_INFORMATION DdkConfigInformation
;
5109 HANDLE RootKey
, Key
;
5111 WCHAR DeviceBuffer
[16];
5112 WCHAR StrBuffer
[512];
5116 /* Zero out the struct if told so */
5119 /* First zero the portconfig */
5120 RtlZeroMemory(ConfigInfo
, sizeof(PORT_CONFIGURATION_INFORMATION
));
5122 /* Then access ranges */
5123 RtlZeroMemory(InternalConfigInfo
->AccessRanges
,
5124 HwInitData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
5126 /* Initialize the struct */
5127 ConfigInfo
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
5128 ConfigInfo
->AdapterInterfaceType
= HwInitData
->AdapterInterfaceType
;
5129 ConfigInfo
->InterruptMode
= Latched
;
5130 ConfigInfo
->DmaChannel
= SP_UNINITIALIZED_VALUE
;
5131 ConfigInfo
->DmaPort
= SP_UNINITIALIZED_VALUE
;
5132 ConfigInfo
->MaximumTransferLength
= SP_UNINITIALIZED_VALUE
;
5133 ConfigInfo
->NumberOfAccessRanges
= HwInitData
->NumberOfAccessRanges
;
5134 ConfigInfo
->MaximumNumberOfTargets
= 8;
5136 /* Store parameters */
5137 ConfigInfo
->NeedPhysicalAddresses
= HwInitData
->NeedPhysicalAddresses
;
5138 ConfigInfo
->MapBuffers
= HwInitData
->MapBuffers
;
5139 ConfigInfo
->AutoRequestSense
= HwInitData
->AutoRequestSense
;
5140 ConfigInfo
->ReceiveEvent
= HwInitData
->ReceiveEvent
;
5141 ConfigInfo
->TaggedQueuing
= HwInitData
->TaggedQueuing
;
5142 ConfigInfo
->MultipleRequestPerLu
= HwInitData
->MultipleRequestPerLu
;
5144 /* Get the disk usage */
5145 DdkConfigInformation
= IoGetConfigurationInformation();
5146 ConfigInfo
->AtdiskPrimaryClaimed
= DdkConfigInformation
->AtDiskPrimaryAddressClaimed
;
5147 ConfigInfo
->AtdiskSecondaryClaimed
= DdkConfigInformation
->AtDiskSecondaryAddressClaimed
;
5149 /* Initiator bus id is not set */
5150 for (Bus
= 0; Bus
< 8; Bus
++)
5151 ConfigInfo
->InitiatorBusId
[Bus
] = (CCHAR
)SP_UNINITIALIZED_VALUE
;
5154 ConfigInfo
->NumberOfPhysicalBreaks
= 17;
5156 /* Clear this information */
5157 InternalConfigInfo
->DisableTaggedQueueing
= FALSE
;
5158 InternalConfigInfo
->DisableMultipleLun
= FALSE
;
5160 /* Store Bus Number */
5161 ConfigInfo
->SystemIoBusNumber
= InternalConfigInfo
->BusNumber
;
5165 if (ConfigInfo
->AdapterInterfaceType
== Internal
)
5167 /* Open registry key for HW database */
5168 InitializeObjectAttributes(&ObjectAttributes
,
5169 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
5170 OBJ_CASE_INSENSITIVE
,
5174 Status
= ZwOpenKey(&RootKey
,
5178 if (NT_SUCCESS(Status
))
5180 /* Create name for it */
5181 swprintf(StrBuffer
, L
"ScsiAdapter\\%lu",
5182 InternalConfigInfo
->AdapterNumber
);
5184 RtlInitUnicodeString(&UnicodeString
, StrBuffer
);
5186 /* Open device key */
5187 InitializeObjectAttributes(&ObjectAttributes
,
5189 OBJ_CASE_INSENSITIVE
,
5193 Status
= ZwOpenKey(&Key
,
5199 if (NT_SUCCESS(Status
))
5201 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5203 DPRINT("Hardware info found at %S\n", StrBuffer
);
5206 SpiParseDeviceInfo(DeviceExtension
,
5212 InternalConfigInfo
->BusNumber
= 0;
5216 /* Try the next adapter */
5217 InternalConfigInfo
->AdapterNumber
++;
5223 /* Info was not found, exit */
5224 return STATUS_DEVICE_DOES_NOT_EXIST
;
5230 /* Look at device params */
5232 if (InternalConfigInfo
->Parameter
)
5234 ExFreePool(InternalConfigInfo
->Parameter
);
5235 InternalConfigInfo
->Parameter
= NULL
;
5238 if (InternalConfigInfo
->ServiceKey
!= NULL
)
5240 swprintf(DeviceBuffer
, L
"Device%lu", InternalConfigInfo
->AdapterNumber
);
5241 RtlInitUnicodeString(&UnicodeString
, DeviceBuffer
);
5243 /* Open the service key */
5244 InitializeObjectAttributes(&ObjectAttributes
,
5246 OBJ_CASE_INSENSITIVE
,
5247 InternalConfigInfo
->ServiceKey
,
5250 Status
= ZwOpenKey(&Key
,
5255 /* Parse device key */
5256 if (InternalConfigInfo
->DeviceKey
!= NULL
)
5258 SpiParseDeviceInfo(DeviceExtension
,
5259 InternalConfigInfo
->DeviceKey
,
5265 /* Then parse hw info */
5268 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5270 SpiParseDeviceInfo(DeviceExtension
,
5281 /* Adapter not found, go try the next one */
5282 InternalConfigInfo
->AdapterNumber
++;
5291 /* Update the last adapter number */
5292 InternalConfigInfo
->LastAdapterNumber
= InternalConfigInfo
->AdapterNumber
;
5294 /* Do we have this kind of bus at all? */
5296 Status
= IoQueryDeviceDescription(&HwInitData
->AdapterInterfaceType
,
5297 &InternalConfigInfo
->BusNumber
,
5302 SpQueryDeviceCallout
,
5305 /* This bus was not found */
5308 INTERFACE_TYPE InterfaceType
= Eisa
;
5310 /* Check for EISA */
5311 if (HwInitData
->AdapterInterfaceType
== Isa
)
5313 Status
= IoQueryDeviceDescription(&InterfaceType
,
5314 &InternalConfigInfo
->BusNumber
,
5319 SpQueryDeviceCallout
,
5322 /* Return respectively */
5324 return STATUS_SUCCESS
;
5326 return STATUS_DEVICE_DOES_NOT_EXIST
;
5330 return STATUS_DEVICE_DOES_NOT_EXIST
;
5335 return STATUS_SUCCESS
;
5340 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5342 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5343 IN PCONFIGURATION_INFO InternalConfigInfo
,
5346 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
5347 PCM_FULL_RESOURCE_DESCRIPTOR FullResource
;
5348 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
5349 PCM_SCSI_DEVICE_DATA ScsiDeviceData
;
5350 ULONG Length
, Count
;
5351 ULONG Index
= 0, RangeCount
= 0;
5352 UNICODE_STRING UnicodeString
;
5353 ANSI_STRING AnsiString
;
5354 NTSTATUS Status
= STATUS_SUCCESS
;
5357 KeyValueInformation
= (PKEY_VALUE_FULL_INFORMATION
) Buffer
;
5359 /* Loop through all values in the device node */
5362 Status
= ZwEnumerateValueKey(Key
,
5364 KeyValueFullInformation
,
5369 if (!NT_SUCCESS(Status
))
5374 /* Length for DWORD is ok? */
5375 if (KeyValueInformation
->Type
== REG_DWORD
&&
5376 KeyValueInformation
->DataLength
!= sizeof(ULONG
))
5381 /* Get MaximumLogicalUnit */
5382 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumLogicalUnit",
5383 KeyValueInformation
->NameLength
/2) == 0)
5386 if (KeyValueInformation
->Type
!= REG_DWORD
)
5388 DPRINT("Bad data type for MaximumLogicalUnit\n");
5392 DeviceExtension
->MaxLunCount
= *((PUCHAR
)
5393 (Buffer
+ KeyValueInformation
->DataOffset
));
5395 /* Check / reset if needed */
5396 if (DeviceExtension
->MaxLunCount
> SCSI_MAXIMUM_LOGICAL_UNITS
)
5397 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
5399 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension
->MaxLunCount
);
5402 /* Get InitiatorTargetId */
5403 if (_wcsnicmp(KeyValueInformation
->Name
, L
"InitiatorTargetId",
5404 KeyValueInformation
->NameLength
/ 2) == 0)
5407 if (KeyValueInformation
->Type
!= REG_DWORD
)
5409 DPRINT("Bad data type for InitiatorTargetId\n");
5413 ConfigInfo
->InitiatorBusId
[0] = *((PUCHAR
)
5414 (Buffer
+ KeyValueInformation
->DataOffset
));
5416 /* Check / reset if needed */
5417 if (ConfigInfo
->InitiatorBusId
[0] > ConfigInfo
->MaximumNumberOfTargets
- 1)
5418 ConfigInfo
->InitiatorBusId
[0] = (CCHAR
)-1;
5420 DPRINT("InitiatorTargetId = %d\n", ConfigInfo
->InitiatorBusId
[0]);
5424 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ScsiDebug",
5425 KeyValueInformation
->NameLength
/2) == 0)
5427 DPRINT("ScsiDebug key not supported\n");
5430 /* Check for a breakpoint */
5431 if (_wcsnicmp(KeyValueInformation
->Name
, L
"BreakPointOnEntry",
5432 KeyValueInformation
->NameLength
/2) == 0)
5434 DPRINT1("Breakpoint on entry requested!\n");
5438 /* Get DisableSynchronousTransfers */
5439 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableSynchronousTransfers",
5440 KeyValueInformation
->NameLength
/2) == 0)
5442 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5443 DPRINT("Synch transfers disabled\n");
5446 /* Get DisableDisconnects */
5447 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableDisconnects",
5448 KeyValueInformation
->NameLength
/2) == 0)
5450 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
5451 DPRINT("Disconnects disabled\n");
5454 /* Get DisableTaggedQueuing */
5455 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableTaggedQueuing",
5456 KeyValueInformation
->NameLength
/2) == 0)
5458 InternalConfigInfo
->DisableTaggedQueueing
= TRUE
;
5459 DPRINT("Tagged queueing disabled\n");
5462 /* Get DisableMultipleRequests */
5463 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableMultipleRequests",
5464 KeyValueInformation
->NameLength
/2) == 0)
5466 InternalConfigInfo
->DisableMultipleLun
= TRUE
;
5467 DPRINT("Multiple requests disabled\n");
5470 /* Get DriverParameters */
5471 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DriverParameters",
5472 KeyValueInformation
->NameLength
/2) == 0)
5474 /* Skip if nothing */
5475 if (KeyValueInformation
->DataLength
== 0)
5478 /* If there was something previously allocated - free it */
5479 if (InternalConfigInfo
->Parameter
!= NULL
)
5480 ExFreePool(InternalConfigInfo
->Parameter
);
5483 InternalConfigInfo
->Parameter
= ExAllocatePool(NonPagedPool
,
5484 KeyValueInformation
->DataLength
);
5486 if (InternalConfigInfo
->Parameter
!= NULL
)
5488 if (KeyValueInformation
->Type
!= REG_SZ
)
5492 InternalConfigInfo
->Parameter
,
5493 (PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
,
5494 KeyValueInformation
->DataLength
);
5498 /* If it's a unicode string, convert it to ansi */
5499 UnicodeString
.Length
= (USHORT
)KeyValueInformation
->DataLength
;
5500 UnicodeString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
5501 UnicodeString
.Buffer
=
5502 (PWSTR
)((PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
5504 AnsiString
.Length
= 0;
5505 AnsiString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
5506 AnsiString
.Buffer
= (PCHAR
)InternalConfigInfo
->Parameter
;
5508 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
5512 /* In case of error, free the allocated space */
5513 if (!NT_SUCCESS(Status
))
5515 ExFreePool(InternalConfigInfo
->Parameter
);
5516 InternalConfigInfo
->Parameter
= NULL
;
5522 DPRINT("Found driver parameter\n");
5525 /* Get MaximumSGList */
5526 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumSGList",
5527 KeyValueInformation
->NameLength
/2) == 0)
5529 if (KeyValueInformation
->Type
!= REG_DWORD
)
5531 DPRINT("Bad data type for MaximumSGList\n");
5535 ConfigInfo
->NumberOfPhysicalBreaks
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
5538 if (ConfigInfo
->NumberOfPhysicalBreaks
> SCSI_MAXIMUM_PHYSICAL_BREAKS
)
5540 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MAXIMUM_PHYSICAL_BREAKS
;
5542 else if (ConfigInfo
->NumberOfPhysicalBreaks
< SCSI_MINIMUM_PHYSICAL_BREAKS
)
5544 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MINIMUM_PHYSICAL_BREAKS
;
5547 DPRINT("MaximumSGList = %d\n", ConfigInfo
->NumberOfPhysicalBreaks
);
5550 /* Get NumberOfRequests */
5551 if (_wcsnicmp(KeyValueInformation
->Name
, L
"NumberOfRequests",
5552 KeyValueInformation
->NameLength
/2) == 0)
5554 if (KeyValueInformation
->Type
!= REG_DWORD
)
5556 DPRINT("NumberOfRequests has wrong data type\n");
5560 DeviceExtension
->RequestsNumber
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
5563 if (DeviceExtension
->RequestsNumber
< 16)
5565 DeviceExtension
->RequestsNumber
= 16;
5567 else if (DeviceExtension
->RequestsNumber
> 512)
5569 DeviceExtension
->RequestsNumber
= 512;
5572 DPRINT("Number Of Requests = %d\n", DeviceExtension
->RequestsNumber
);
5575 /* Get resource list */
5576 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ResourceList",
5577 KeyValueInformation
->NameLength
/2) == 0 ||
5578 _wcsnicmp(KeyValueInformation
->Name
, L
"Configuration Data",
5579 KeyValueInformation
->NameLength
/2) == 0 )
5581 if (KeyValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
||
5582 KeyValueInformation
->DataLength
< sizeof(REG_FULL_RESOURCE_DESCRIPTOR
))
5584 DPRINT("Bad data type for ResourceList\n");
5589 DPRINT("Found ResourceList\n");
5592 FullResource
= (PCM_FULL_RESOURCE_DESCRIPTOR
)(Buffer
+ KeyValueInformation
->DataOffset
);
5594 /* Copy some info from it */
5595 InternalConfigInfo
->BusNumber
= FullResource
->BusNumber
;
5596 ConfigInfo
->SystemIoBusNumber
= FullResource
->BusNumber
;
5598 /* Loop through it */
5599 for (Count
= 0; Count
< FullResource
->PartialResourceList
.Count
; Count
++)
5601 /* Get partial descriptor */
5603 &FullResource
->PartialResourceList
.PartialDescriptors
[Count
];
5605 /* Check datalength */
5606 if ((ULONG
)((PCHAR
)(PartialDescriptor
+ 1) -
5607 (PCHAR
)FullResource
) > KeyValueInformation
->DataLength
)
5609 DPRINT("Resource data is of incorrect size\n");
5613 switch (PartialDescriptor
->Type
)
5615 case CmResourceTypePort
:
5616 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
5618 DPRINT("Too many access ranges\n");
5622 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= FALSE
;
5623 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Port
.Start
;
5624 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Port
.Length
;
5629 case CmResourceTypeMemory
:
5630 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
5632 DPRINT("Too many access ranges\n");
5636 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= TRUE
;
5637 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Memory
.Start
;
5638 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Memory
.Length
;
5643 case CmResourceTypeInterrupt
:
5644 ConfigInfo
->BusInterruptLevel
=
5645 PartialDescriptor
->u
.Interrupt
.Level
;
5647 ConfigInfo
->BusInterruptVector
=
5648 PartialDescriptor
->u
.Interrupt
.Vector
;
5651 case CmResourceTypeDma
:
5652 ConfigInfo
->DmaChannel
= PartialDescriptor
->u
.Dma
.Channel
;
5653 ConfigInfo
->DmaPort
= PartialDescriptor
->u
.Dma
.Port
;
5656 case CmResourceTypeDeviceSpecific
:
5657 if (PartialDescriptor
->u
.DeviceSpecificData
.DataSize
<
5658 sizeof(CM_SCSI_DEVICE_DATA
) ||
5659 (PCHAR
) (PartialDescriptor
+ 1) - (PCHAR
)FullResource
+
5660 PartialDescriptor
->u
.DeviceSpecificData
.DataSize
>
5661 KeyValueInformation
->DataLength
)
5663 DPRINT("Resource data length is incorrect");
5667 /* Set only one field from it */
5668 ScsiDeviceData
= (PCM_SCSI_DEVICE_DATA
) (PartialDescriptor
+1);
5669 ConfigInfo
->InitiatorBusId
[0] = ScsiDeviceData
->HostIdentifier
;
5680 SpQueryDeviceCallout(IN PVOID Context
,
5681 IN PUNICODE_STRING PathName
,
5682 IN INTERFACE_TYPE BusType
,
5684 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
5685 IN CONFIGURATION_TYPE ControllerType
,
5686 IN ULONG ControllerNumber
,
5687 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
5688 IN CONFIGURATION_TYPE PeripheralType
,
5689 IN ULONG PeripheralNumber
,
5690 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
5692 PBOOLEAN Found
= (PBOOLEAN
)Context
;
5693 /* We just set our Found variable to TRUE */
5696 return STATUS_SUCCESS
;
5703 SpiStatusSrbToNt(UCHAR SrbStatus
)
5705 switch (SRB_STATUS(SrbStatus
))
5707 case SRB_STATUS_TIMEOUT
:
5708 case SRB_STATUS_COMMAND_TIMEOUT
:
5709 return STATUS_IO_TIMEOUT
;
5711 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH
:
5712 case SRB_STATUS_BAD_FUNCTION
:
5713 return STATUS_INVALID_DEVICE_REQUEST
;
5715 case SRB_STATUS_NO_DEVICE
:
5716 case SRB_STATUS_INVALID_LUN
:
5717 case SRB_STATUS_INVALID_TARGET_ID
:
5718 case SRB_STATUS_NO_HBA
:
5719 return STATUS_DEVICE_DOES_NOT_EXIST
;
5721 case SRB_STATUS_DATA_OVERRUN
:
5722 return STATUS_BUFFER_OVERFLOW
;
5724 case SRB_STATUS_SELECTION_TIMEOUT
:
5725 return STATUS_DEVICE_NOT_CONNECTED
;
5728 return STATUS_IO_DEVICE_ERROR
;
5731 return STATUS_IO_DEVICE_ERROR
;
5735 #undef ScsiPortConvertPhysicalAddressToUlong
5740 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
5742 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
5743 return(Address
.u
.LowPart
);