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 *****************************************************************/
43 #include "scsiport_int.h"
45 ULONG InternalDebugLevel
= 0x00;
47 /* TYPES *********************************************************************/
49 /* GLOBALS *******************************************************************/
52 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
53 IN PDEVICE_OBJECT DeviceObject
,
54 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
55 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
56 IN PUNICODE_STRING RegistryPath
,
58 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
);
60 static NTSTATUS STDCALL
61 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
64 static NTSTATUS STDCALL
65 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
68 static NTSTATUS STDCALL
69 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
73 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
76 static BOOLEAN STDCALL
77 ScsiPortStartPacket(IN OUT PVOID Context
);
80 static PSCSI_PORT_LUN_EXTENSION
81 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
83 static PSCSI_PORT_LUN_EXTENSION
84 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
90 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
91 IN PSCSI_LUN_INFO LunInfo
);
94 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
97 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
100 static PSCSI_REQUEST_BLOCK_INFO
101 SpiGetSrbData(IN PVOID DeviceExtension
,
107 static BOOLEAN STDCALL
108 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
109 IN PVOID ServiceContext
);
112 ScsiPortDpcForIsr(IN PKDPC Dpc
,
113 IN PDEVICE_OBJECT DpcDeviceObject
,
115 IN PVOID DpcContext
);
118 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
122 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
123 PUNICODE_STRING RegistryPath
);
126 SpiStatusSrbToNt(UCHAR SrbStatus
);
129 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
130 IN PSCSI_REQUEST_BLOCK Srb
);
133 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
139 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
140 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
141 OUT PBOOLEAN NeedToCallStartIo
);
144 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
145 IN PSCSI_PORT_LUN_EXTENSION LunExtension
);
148 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
149 IN PVOID DeviceObject
,
150 IN PVOID SystemArgument1
,
151 IN PVOID SystemArgument2
);
154 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
155 PHW_INITIALIZATION_DATA HwInitData
,
156 PCONFIGURATION_INFO InternalConfigInfo
,
157 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
161 SpQueryDeviceCallout(IN PVOID Context
,
162 IN PUNICODE_STRING PathName
,
163 IN INTERFACE_TYPE BusType
,
165 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
166 IN CONFIGURATION_TYPE ControllerType
,
167 IN ULONG ControllerNumber
,
168 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
169 IN CONFIGURATION_TYPE PeripheralType
,
170 IN ULONG PeripheralNumber
,
171 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
);
174 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
176 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
177 IN PCONFIGURATION_INFO InternalConfigInfo
,
181 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
182 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
183 IN PPORT_CONFIGURATION_INFORMATION PortConfig
);
185 static PCM_RESOURCE_LIST
186 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
187 PPORT_CONFIGURATION_INFORMATION PortConfig
);
190 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
193 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
197 /* FUNCTIONS *****************************************************************/
199 /**********************************************************************
204 * This function initializes the driver.
211 * System allocated Driver Object for this driver.
214 * Name of registry driver service key.
221 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
222 IN PUNICODE_STRING RegistryPath
)
224 DPRINT("ScsiPort Driver %s\n", VERSION
);
225 return(STATUS_SUCCESS
);
229 /**********************************************************************
234 * Prints debugging messages.
241 * Debug level of the given message.
244 * Pointer to printf()-compatible format string.
247 Additional output data (see printf()).
256 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
257 IN PCHAR DebugMessage
,
263 if (DebugPrintLevel
> InternalDebugLevel
)
266 va_start(ap
, DebugMessage
);
267 vsprintf(Buffer
, DebugMessage
, ap
);
278 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
284 DPRINT("ScsiPortCompleteRequest()\n");
292 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
294 DPRINT("ScsiPortFlushDma()\n");
303 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
304 IN PVOID MappedAddress
)
306 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
307 PMAPPED_ADDRESS NextMa
, LastMa
;
309 //DPRINT("ScsiPortFreeDeviceBase() called\n");
311 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
312 SCSI_PORT_DEVICE_EXTENSION
,
313 MiniPortDeviceExtension
);
316 /* Initialize our pointers */
317 NextMa
= DeviceExtension
->MappedAddressList
;
322 if (NextMa
->MappedAddress
== MappedAddress
)
325 MmUnmapIoSpace(MappedAddress
, NextMa
->NumberOfBytes
);
327 /* Remove it from the list */
328 if (NextMa
== DeviceExtension
->MappedAddressList
)
330 /* Remove the first entry */
331 DeviceExtension
->MappedAddressList
= NextMa
->NextMappedAddress
;
335 LastMa
->NextMappedAddress
= NextMa
->NextMappedAddress
;
338 /* Free the resources and quit */
346 NextMa
= NextMa
->NextMappedAddress
;
356 ScsiPortGetBusData(IN PVOID DeviceExtension
,
357 IN ULONG BusDataType
,
358 IN ULONG SystemIoBusNumber
,
363 return(HalGetBusData(BusDataType
,
375 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
376 IN INTERFACE_TYPE BusType
,
377 IN ULONG SystemIoBusNumber
,
378 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
379 IN ULONG NumberOfBytes
,
380 IN BOOLEAN InIoSpace
)
382 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
383 PHYSICAL_ADDRESS TranslatedAddress
;
384 PMAPPED_ADDRESS DeviceBase
;
388 //DPRINT ("ScsiPortGetDeviceBase() called\n");
390 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
391 SCSI_PORT_DEVICE_EXTENSION
,
392 MiniPortDeviceExtension
);
394 AddressSpace
= (ULONG
)InIoSpace
;
395 if (HalTranslateBusAddress(BusType
,
399 &TranslatedAddress
) == FALSE
)
405 if (AddressSpace
!= 0)
406 return((PVOID
)TranslatedAddress
.u
.LowPart
);
408 MappedAddress
= MmMapIoSpace(TranslatedAddress
,
412 DeviceBase
= ExAllocatePool(NonPagedPool
,
413 sizeof(MAPPED_ADDRESS
));
415 if (DeviceBase
== NULL
)
416 return MappedAddress
;
418 DeviceBase
->MappedAddress
= MappedAddress
;
419 DeviceBase
->NumberOfBytes
= NumberOfBytes
;
420 DeviceBase
->IoAddress
= IoAddress
;
421 DeviceBase
->BusNumber
= SystemIoBusNumber
;
423 /* Link it to the Device Extension list */
424 DeviceBase
->NextMappedAddress
= DeviceExtension
->MappedAddressList
;
425 DeviceExtension
->MappedAddressList
= DeviceBase
;
427 return MappedAddress
;
434 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
441 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
442 PSCSI_PORT_LUN_EXTENSION LunExtension
;
445 DPRINT("ScsiPortGetLogicalUnit() called\n");
447 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
448 SCSI_PORT_DEVICE_EXTENSION
,
449 MiniPortDeviceExtension
);
450 if (IsListEmpty(&DeviceExtension
->LunExtensionListHead
))
453 Entry
= DeviceExtension
->LunExtensionListHead
.Flink
;
454 while (Entry
!= &DeviceExtension
->LunExtensionListHead
)
456 LunExtension
= CONTAINING_RECORD(Entry
,
457 SCSI_PORT_LUN_EXTENSION
,
459 if (LunExtension
->PathId
== PathId
&&
460 LunExtension
->TargetId
== TargetId
&&
461 LunExtension
->Lun
== Lun
)
463 return (PVOID
)&LunExtension
->MiniportLunExtension
;
466 Entry
= Entry
->Flink
;
476 SCSI_PHYSICAL_ADDRESS STDCALL
477 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
478 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
479 IN PVOID VirtualAddress
,
482 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
483 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
484 SCSI_PHYSICAL_ADDRESS NextPhysicalAddress
;
485 ULONG BufferLength
= 0;
489 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
490 HwDeviceExtension
, Srb
, VirtualAddress
, Length
);
492 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
493 SCSI_PORT_DEVICE_EXTENSION
,
494 MiniPortDeviceExtension
);
500 if ((ULONG_PTR
)DeviceExtension
->VirtualAddress
> (ULONG_PTR
)VirtualAddress
)
502 PhysicalAddress
.QuadPart
= 0ULL;
503 return PhysicalAddress
;
506 Offset
= (ULONG_PTR
)VirtualAddress
- (ULONG_PTR
)DeviceExtension
->VirtualAddress
;
507 if (Offset
>= DeviceExtension
->CommonBufferLength
)
509 PhysicalAddress
.QuadPart
= 0ULL;
510 return PhysicalAddress
;
513 PhysicalAddress
.QuadPart
=
514 DeviceExtension
->PhysicalAddress
.QuadPart
+ (ULONGLONG
)Offset
;
515 BufferLength
= DeviceExtension
->CommonBufferLength
- Offset
;
519 EndAddress
= (PVOID
)((ULONG_PTR
)Srb
->DataBuffer
+ Srb
->DataTransferLength
);
520 if (VirtualAddress
== NULL
)
522 VirtualAddress
= Srb
->DataBuffer
;
524 else if (VirtualAddress
< Srb
->DataBuffer
|| VirtualAddress
>= EndAddress
)
526 PhysicalAddress
.QuadPart
= 0LL;
527 return PhysicalAddress
;
530 PhysicalAddress
= MmGetPhysicalAddress(VirtualAddress
);
531 if (PhysicalAddress
.QuadPart
== 0LL)
533 return PhysicalAddress
;
536 Offset
= (ULONG_PTR
)VirtualAddress
& (PAGE_SIZE
- 1);
540 * MmGetPhysicalAddress doesn't return the offset within the page.
541 * We must set the correct offset.
543 PhysicalAddress
.u
.LowPart
= (PhysicalAddress
.u
.LowPart
& ~(PAGE_SIZE
- 1)) + Offset
;
545 BufferLength
+= PAGE_SIZE
- Offset
;
546 while ((ULONG_PTR
)VirtualAddress
+ BufferLength
< (ULONG_PTR
)EndAddress
)
548 NextPhysicalAddress
= MmGetPhysicalAddress((PVOID
)((ULONG_PTR
)VirtualAddress
+ BufferLength
));
549 if (PhysicalAddress
.QuadPart
+ (ULONGLONG
)BufferLength
!= NextPhysicalAddress
.QuadPart
)
553 BufferLength
+= PAGE_SIZE
;
555 if ((ULONG_PTR
)VirtualAddress
+ BufferLength
>= (ULONG_PTR
)EndAddress
)
557 BufferLength
= (ULONG_PTR
)EndAddress
- (ULONG_PTR
)VirtualAddress
;
561 *Length
= BufferLength
;
563 return PhysicalAddress
;
570 PSCSI_REQUEST_BLOCK STDCALL
571 ScsiPortGetSrb(IN PVOID DeviceExtension
,
577 DPRINT1("ScsiPortGetSrb() unimplemented\n");
587 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
588 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
589 IN ULONG NumberOfBytes
)
591 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
592 DEVICE_DESCRIPTION DeviceDescription
;
594 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
595 HwDeviceExtension
, ConfigInfo
, NumberOfBytes
);
597 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
598 SCSI_PORT_DEVICE_EXTENSION
,
599 MiniPortDeviceExtension
);
601 /* Check for allocated common DMA buffer */
602 if (DeviceExtension
->VirtualAddress
!= NULL
)
604 DPRINT1("The HBA has already got a common DMA buffer!\n");
608 /* Check for DMA adapter object */
609 if (DeviceExtension
->AdapterObject
== NULL
)
611 /* Initialize DMA adapter description */
612 RtlZeroMemory(&DeviceDescription
,
613 sizeof(DEVICE_DESCRIPTION
));
614 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
615 DeviceDescription
.Master
= ConfigInfo
->Master
;
616 DeviceDescription
.ScatterGather
= ConfigInfo
->ScatterGather
;
617 DeviceDescription
.DemandMode
= ConfigInfo
->DemandMode
;
618 DeviceDescription
.Dma32BitAddresses
= ConfigInfo
->Dma32BitAddresses
;
619 DeviceDescription
.BusNumber
= ConfigInfo
->SystemIoBusNumber
;
620 DeviceDescription
.DmaChannel
= ConfigInfo
->DmaChannel
;
621 DeviceDescription
.InterfaceType
= ConfigInfo
->AdapterInterfaceType
;
622 DeviceDescription
.DmaWidth
= ConfigInfo
->DmaWidth
;
623 DeviceDescription
.DmaSpeed
= ConfigInfo
->DmaSpeed
;
624 DeviceDescription
.MaximumLength
= ConfigInfo
->MaximumTransferLength
;
625 DeviceDescription
.DmaPort
= ConfigInfo
->DmaPort
;
627 /* Get a DMA adapter object */
628 DeviceExtension
->AdapterObject
= HalGetAdapter(&DeviceDescription
,
629 &DeviceExtension
->MapRegisterCount
);
630 if (DeviceExtension
->AdapterObject
== NULL
)
632 DPRINT1("HalGetAdapter() failed\n");
637 /* Allocate a common DMA buffer */
638 DeviceExtension
->CommonBufferLength
=
639 NumberOfBytes
+ DeviceExtension
->SrbExtensionSize
;
640 DeviceExtension
->VirtualAddress
=
641 HalAllocateCommonBuffer(DeviceExtension
->AdapterObject
,
642 DeviceExtension
->CommonBufferLength
,
643 &DeviceExtension
->PhysicalAddress
,
645 if (DeviceExtension
->VirtualAddress
== NULL
)
647 DPRINT1("HalAllocateCommonBuffer() failed!\n");
648 DeviceExtension
->CommonBufferLength
= 0;
652 return (PVOID
)((ULONG_PTR
)DeviceExtension
->VirtualAddress
+
653 DeviceExtension
->SrbExtensionSize
);
661 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
662 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
664 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
667 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
668 HwDeviceExtension
, PhysicalAddress
.QuadPart
);
670 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
671 SCSI_PORT_DEVICE_EXTENSION
,
672 MiniPortDeviceExtension
);
674 if (DeviceExtension
->PhysicalAddress
.QuadPart
> PhysicalAddress
.QuadPart
)
677 Offset
= (ULONG
)(PhysicalAddress
.QuadPart
- DeviceExtension
->PhysicalAddress
.QuadPart
);
678 if (Offset
>= DeviceExtension
->CommonBufferLength
)
681 return (PVOID
)((ULONG_PTR
)DeviceExtension
->VirtualAddress
+ Offset
);
685 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo
, PUNICODE_STRING RegistryPath
)
687 OBJECT_ATTRIBUTES ObjectAttributes
;
688 UNICODE_STRING KeyName
;
691 /* Open the service key */
692 InitializeObjectAttributes(&ObjectAttributes
,
694 OBJ_CASE_INSENSITIVE
,
698 Status
= ZwOpenKey(&ConfigInfo
->ServiceKey
,
702 if (!NT_SUCCESS(Status
))
704 DPRINT1("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath
, Status
);
705 ConfigInfo
->ServiceKey
= NULL
;
708 /* If we could open driver's service key, then proceed to the Parameters key */
709 if (ConfigInfo
->ServiceKey
!= NULL
)
711 RtlInitUnicodeString(&KeyName
, L
"Parameters");
712 InitializeObjectAttributes(&ObjectAttributes
,
714 OBJ_CASE_INSENSITIVE
,
715 ConfigInfo
->ServiceKey
,
716 (PSECURITY_DESCRIPTOR
) NULL
);
719 Status
= ZwOpenKey(&ConfigInfo
->DeviceKey
,
723 if (NT_SUCCESS(Status
))
725 /* Yes, Parameters key exist, and it must be used instead of
727 ZwClose(ConfigInfo
->ServiceKey
);
728 ConfigInfo
->ServiceKey
= ConfigInfo
->DeviceKey
;
729 ConfigInfo
->DeviceKey
= NULL
;
733 /* Open the Device key */
734 RtlInitUnicodeString(&KeyName
, L
"Device");
735 InitializeObjectAttributes(&ObjectAttributes
,
737 OBJ_CASE_INSENSITIVE
,
738 ConfigInfo
->ServiceKey
,
741 /* We don't check for failure here - not needed */
742 ZwOpenKey(&ConfigInfo
->DeviceKey
,
748 /**********************************************************************
753 * Initializes SCSI port driver specific data.
760 * Pointer to the miniport driver's driver object.
763 * Pointer to the miniport driver's registry path.
765 * HwInitializationData
766 * Pointer to port driver specific configuration data.
769 Miniport driver specific context.
778 ScsiPortInitialize(IN PVOID Argument1
,
780 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
783 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
784 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
785 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
786 PCONFIGURATION_INFORMATION SystemConfig
;
787 PPORT_CONFIGURATION_INFORMATION PortConfig
;
788 PORT_CONFIGURATION_INFORMATION InitialPortConfig
;
789 CONFIGURATION_INFO ConfigInfo
;
790 ULONG DeviceExtensionSize
;
791 ULONG PortConfigSize
;
793 BOOLEAN DeviceFound
= FALSE
;
794 BOOLEAN FirstConfigCall
= TRUE
;
799 PCI_SLOT_NUMBER SlotNumber
;
801 PDEVICE_OBJECT PortDeviceObject
;
802 WCHAR NameBuffer
[80];
803 UNICODE_STRING DeviceName
;
804 WCHAR DosNameBuffer
[80];
805 UNICODE_STRING DosDeviceName
;
806 PIO_SCSI_CAPABILITIES PortCapabilities
;
811 PCM_RESOURCE_LIST ResourceList
;
815 DPRINT ("ScsiPortInitialize() called!\n");
817 /* Check params for validity */
818 if ((HwInitializationData
->HwInitialize
== NULL
) ||
819 (HwInitializationData
->HwStartIo
== NULL
) ||
820 (HwInitializationData
->HwInterrupt
== NULL
) ||
821 (HwInitializationData
->HwFindAdapter
== NULL
) ||
822 (HwInitializationData
->HwResetBus
== NULL
))
824 return STATUS_INVALID_PARAMETER
;
828 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
829 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
830 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
831 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
832 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
833 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
835 /* Obtain configuration information */
836 SystemConfig
= IoGetConfigurationInformation();
838 /* Zero the internal configuration info structure */
839 RtlZeroMemory(&ConfigInfo
, sizeof(CONFIGURATION_INFO
));
841 /* Allocate space for access ranges */
842 if (HwInitializationData
->NumberOfAccessRanges
)
844 ConfigInfo
.AccessRanges
=
845 ExAllocatePool(PagedPool
,
846 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
849 if (ConfigInfo
.AccessRanges
== NULL
)
850 return STATUS_INSUFFICIENT_RESOURCES
;
853 /* Open registry keys */
854 SpiInitOpenKeys(&ConfigInfo
, (PUNICODE_STRING
)Argument2
);
856 /* Last adapter number = not known */
857 ConfigInfo
.LastAdapterNumber
= SP_UNINITIALIZED_VALUE
;
859 /* Calculate sizes of DeviceExtension and PortConfig */
860 DeviceExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
861 HwInitializationData
->DeviceExtensionSize
;
863 MaxBus
= (HwInitializationData
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
864 DPRINT("MaxBus: %lu\n", MaxBus
);
868 /* Create a unicode device name */
870 L
"\\Device\\ScsiPort%lu",
871 SystemConfig
->ScsiPortCount
);
872 RtlInitUnicodeString(&DeviceName
, NameBuffer
);
874 DPRINT("Creating device: %wZ\n", &DeviceName
);
876 /* Create the port device */
877 Status
= IoCreateDevice(DriverObject
,
880 FILE_DEVICE_CONTROLLER
,
885 if (!NT_SUCCESS(Status
))
887 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
888 PortDeviceObject
= NULL
;
892 DPRINT ("Created device: %wZ (%p)\n", &DeviceName
, PortDeviceObject
);
894 /* Set the buffering strategy here... */
895 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
896 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
; /* FIXME: Is this really needed? */
898 /* Fill Device Extension */
899 DeviceExtension
= PortDeviceObject
->DeviceExtension
;
900 DPRINT1("DeviceExtension: %p\n", DeviceExtension
);
901 DeviceExtension
->Length
= DeviceExtensionSize
;
902 DeviceExtension
->DeviceObject
= PortDeviceObject
;
903 DeviceExtension
->PortNumber
= SystemConfig
->ScsiPortCount
;
905 /* Driver's routines... */
906 DeviceExtension
->HwInitialize
= HwInitializationData
->HwInitialize
;
907 DeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
908 DeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
909 DeviceExtension
->HwResetBus
= HwInitializationData
->HwResetBus
;
910 DeviceExtension
->HwDmaStarted
= HwInitializationData
->HwDmaStarted
;
912 /* Extensions sizes */
913 DeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
914 DeviceExtension
->LunExtensionSize
= HwInitializationData
->SpecificLuExtensionSize
;
915 DeviceExtension
->SrbExtensionSize
= HwInitializationData
->SrbExtensionSize
;
917 /* Round Srb extension size to the quadword */
918 DeviceExtension
->SrbExtensionSize
=
919 ~(sizeof(LONGLONG
) - 1) & (DeviceExtension
->SrbExtensionSize
+
920 sizeof(LONGLONG
) - 1);
922 /* Fill some numbers (bus count, lun count, etc) */
923 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
924 DeviceExtension
->RequestsNumber
= 16;
926 /* Initialize the spin lock in the controller extension */
927 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
928 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
930 /* Initialize the DPC object */
931 IoInitializeDpcRequest(PortDeviceObject
,
934 /* Initialize the device timer */
935 DeviceExtension
->TimerCount
= -1;
936 IoInitializeTimer(PortDeviceObject
,
940 /* Initialize miniport timer */
941 KeInitializeTimer(&DeviceExtension
->MiniportTimer
);
942 KeInitializeDpc(&DeviceExtension
->MiniportTimerDpc
,
948 Status
= SpiCreatePortConfig(DeviceExtension
,
949 HwInitializationData
,
954 if (!NT_SUCCESS(Status
))
957 /* Allocate and initialize port configuration info */
958 PortConfigSize
= (sizeof(PORT_CONFIGURATION_INFORMATION
) +
959 HwInitializationData
->NumberOfAccessRanges
*
960 sizeof(ACCESS_RANGE
) + 7) & ~7;
961 DeviceExtension
->PortConfig
= ExAllocatePool(NonPagedPool
, PortConfigSize
);
964 if (DeviceExtension
->PortConfig
== NULL
)
966 Status
= STATUS_INSUFFICIENT_RESOURCES
;
970 PortConfig
= DeviceExtension
->PortConfig
;
972 /* Copy information here */
973 RtlCopyMemory(PortConfig
,
975 sizeof(PORT_CONFIGURATION_INFORMATION
));
978 /* Copy extension sizes into the PortConfig */
979 PortConfig
->SpecificLuExtensionSize
= DeviceExtension
->LunExtensionSize
;
980 PortConfig
->SrbExtensionSize
= DeviceExtension
->SrbExtensionSize
;
982 /* Initialize Access ranges */
983 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
985 PortConfig
->AccessRanges
= (PVOID
)(PortConfig
+1);
987 /* Align to LONGLONG */
988 PortConfig
->AccessRanges
= (PVOID
)((ULONG
)(PortConfig
->AccessRanges
) + 7);
989 PortConfig
->AccessRanges
= (PVOID
)((ULONG
)(PortConfig
->AccessRanges
) & ~7);
992 RtlCopyMemory(PortConfig
->AccessRanges
,
993 ConfigInfo
.AccessRanges
,
994 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
997 /* Search for matching PCI device */
998 if ((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
999 (HwInitializationData
->VendorIdLength
> 0) &&
1000 (HwInitializationData
->VendorId
!= NULL
) &&
1001 (HwInitializationData
->DeviceIdLength
> 0) &&
1002 (HwInitializationData
->DeviceId
!= NULL
))
1004 PortConfig
->BusInterruptLevel
= 0;
1006 /* Get PCI device data */
1007 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1008 HwInitializationData
->VendorIdLength
,
1009 HwInitializationData
->VendorId
,
1010 HwInitializationData
->DeviceIdLength
,
1011 HwInitializationData
->DeviceId
);
1013 if (!SpiGetPciConfigData(DriverObject
,
1015 HwInitializationData
,
1021 /* Continue to the next bus, nothing here */
1022 ConfigInfo
.BusNumber
++;
1023 DeviceExtension
->PortConfig
= NULL
;
1024 ExFreePool(PortConfig
);
1026 goto CreatePortConfig
;
1029 if (!PortConfig
->BusInterruptLevel
)
1031 /* Bypass this slot, because no interrupt was assigned */
1032 DeviceExtension
->PortConfig
= NULL
;
1033 ExFreePool(PortConfig
);
1034 goto CreatePortConfig
;
1039 DPRINT("Non-pci bus\n");
1042 /* Note: HwFindAdapter is called once for each bus */
1044 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
1045 Result
= (HwInitializationData
->HwFindAdapter
)(&DeviceExtension
->MiniPortDeviceExtension
,
1047 0, /* BusInformation */
1048 ConfigInfo
.Parameter
, /* ArgumentString */
1052 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1053 Result
, (Again
) ? "True" : "False");
1055 /* Free MapRegisterBase, it's not needed anymore */
1056 if (DeviceExtension
->MapRegisterBase
!= NULL
)
1058 ExFreePool(DeviceExtension
->MapRegisterBase
);
1059 DeviceExtension
->MapRegisterBase
= NULL
;
1062 /* If result is nothing good... */
1063 if (Result
!= SP_RETURN_FOUND
)
1065 DPRINT("HwFindAdapter() Result: %lu\n", Result
);
1067 if (Result
== SP_RETURN_NOT_FOUND
)
1069 /* We can continue on the next bus */
1070 ConfigInfo
.BusNumber
++;
1073 DeviceExtension
->PortConfig
= NULL
;
1074 ExFreePool(PortConfig
);
1075 goto CreatePortConfig
;
1078 /* Otherwise, break */
1079 Status
= STATUS_INTERNAL_ERROR
;
1083 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1084 PortConfig
->BusInterruptVector
, PortConfig
->InitiatorBusId
[0]);
1086 /* If the SRB extension size was updated */
1087 if (!DeviceExtension
->NonCachedExtension
&&
1088 (PortConfig
->SrbExtensionSize
!= DeviceExtension
->SrbExtensionSize
))
1090 /* Set it (rounding to LONGLONG again) */
1091 DeviceExtension
->SrbExtensionSize
=
1092 (PortConfig
->SrbExtensionSize
+
1093 sizeof(LONGLONG
)) & ~(sizeof(LONGLONG
) - 1);
1096 /* The same with LUN extension size */
1097 if (PortConfig
->SpecificLuExtensionSize
!= DeviceExtension
->LunExtensionSize
)
1098 DeviceExtension
->LunExtensionSize
= PortConfig
->SpecificLuExtensionSize
;
1101 if (!((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1102 (HwInitializationData
->VendorIdLength
> 0) &&
1103 (HwInitializationData
->VendorId
!= NULL
) &&
1104 (HwInitializationData
->DeviceIdLength
> 0) &&
1105 (HwInitializationData
->DeviceId
!= NULL
)))
1107 /* Construct a resource list */
1108 ResourceList
= SpiConfigToResource(DeviceExtension
,
1113 UNICODE_STRING UnicodeString
;
1114 RtlInitUnicodeString(&UnicodeString
, L
"ScsiAdapter");
1115 DPRINT("Reporting resources\n");
1116 Status
= IoReportResourceUsage(&UnicodeString
,
1122 FIELD_OFFSET(CM_RESOURCE_LIST
,
1123 List
[0].PartialResourceList
.PartialDescriptors
) +
1124 ResourceList
->List
[0].PartialResourceList
.Count
1125 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
1128 ExFreePool(ResourceList
);
1130 /* In case of a failure or a conflict, break */
1131 if (Conflict
|| (!NT_SUCCESS(Status
)))
1134 Status
= STATUS_CONFLICTING_ADDRESSES
;
1140 /* Reset the Conflict var */
1143 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1144 if (PortConfig
->MaximumNumberOfTargets
> SCSI_MAXIMUM_TARGETS_PER_BUS
)
1145 DeviceExtension
->MaxTargedIds
= SCSI_MAXIMUM_TARGETS_PER_BUS
;
1147 DeviceExtension
->MaxTargedIds
= PortConfig
->MaximumNumberOfTargets
;
1149 DeviceExtension
->BusNum
= PortConfig
->NumberOfBuses
;
1150 DeviceExtension
->CachesData
= PortConfig
->CachesData
;
1151 DeviceExtension
->ReceiveEvent
= PortConfig
->ReceiveEvent
;
1152 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->TaggedQueuing
;
1153 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
;
1155 /* If something was disabled via registry - apply it */
1156 if (ConfigInfo
.DisableMultipleLun
)
1157 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1159 if (ConfigInfo
.DisableTaggedQueueing
)
1160 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1162 /* Check if we need to alloc SRB data */
1163 if (DeviceExtension
->SupportsTaggedQueuing
||
1164 DeviceExtension
->MultipleReqsPerLun
)
1166 DeviceExtension
->NeedSrbDataAlloc
= TRUE
;
1170 DeviceExtension
->NeedSrbDataAlloc
= FALSE
;
1173 /* Get a pointer to the port capabilities */
1174 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1176 /* Copy one field there */
1177 DeviceExtension
->MapBuffers
= PortConfig
->MapBuffers
;
1178 PortCapabilities
->AdapterUsesPio
= PortConfig
->MapBuffers
;
1180 if (DeviceExtension
->AdapterObject
== NULL
&&
1181 (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
|| PortConfig
->Master
))
1183 DPRINT1("DMA is not supported yet\n");
1187 if (DeviceExtension
->SrbExtensionBuffer
== NULL
&&
1188 (DeviceExtension
->SrbExtensionSize
!= 0 ||
1189 PortConfig
->AutoRequestSense
))
1191 DeviceExtension
->SupportsAutoSense
= PortConfig
->AutoRequestSense
;
1192 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
1194 //Status = STATUS_UNSUCCESFUL;
1195 /* TODO: Allocate common buffer */
1198 /* Check for failure */
1199 if (!NT_SUCCESS(Status
))
1203 /* Allocate SrbData, if needed */
1204 if (DeviceExtension
->NeedSrbDataAlloc
)
1207 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1209 if (DeviceExtension
->SrbDataCount
!= 0)
1210 Count
= DeviceExtension
->SrbDataCount
;
1212 Count
= DeviceExtension
->RequestsNumber
* 2;
1214 /* Allocate the data */
1215 SrbData
= ExAllocatePool(NonPagedPool
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
));
1216 if (SrbData
== NULL
)
1217 return STATUS_INSUFFICIENT_RESOURCES
;
1219 RtlZeroMemory(SrbData
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
));
1221 DeviceExtension
->SrbInfo
= SrbData
;
1222 DeviceExtension
->FreeSrbInfo
= SrbData
;
1223 DeviceExtension
->SrbDataCount
= Count
;
1225 /* Link it to the list */
1228 SrbData
->Requests
.Flink
= (PLIST_ENTRY
)(SrbData
+ 1);
1233 /* Mark the last entry of the list */
1235 SrbData
->Requests
.Flink
= NULL
;
1238 /* Initialize port capabilities */
1239 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1240 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1241 PortCapabilities
->MaximumTransferLength
= PortConfig
->MaximumTransferLength
;
1243 if (PortConfig
->ReceiveEvent
)
1244 PortCapabilities
->SupportedAsynchronousEvents
|= SRBEV_SCSI_ASYNC_NOTIFICATION
;
1246 PortCapabilities
->TaggedQueuing
= DeviceExtension
->SupportsTaggedQueuing
;
1247 PortCapabilities
->AdapterScansDown
= PortConfig
->AdapterScansDown
;
1249 if (PortConfig
->AlignmentMask
> PortDeviceObject
->AlignmentRequirement
)
1250 PortDeviceObject
->AlignmentRequirement
= PortConfig
->AlignmentMask
;
1252 PortCapabilities
->AlignmentMask
= PortDeviceObject
->AlignmentRequirement
;
1254 if (PortCapabilities
->MaximumPhysicalPages
== 0)
1256 PortCapabilities
->MaximumPhysicalPages
=
1257 BYTES_TO_PAGES(PortCapabilities
->MaximumTransferLength
);
1259 /* Apply miniport's limits */
1260 if (PortConfig
->NumberOfPhysicalBreaks
< PortCapabilities
->MaximumPhysicalPages
)
1262 PortCapabilities
->MaximumPhysicalPages
= PortConfig
->NumberOfPhysicalBreaks
;
1266 /* Deal with interrupts */
1267 if (DeviceExtension
->HwInterrupt
== NULL
||
1268 (PortConfig
->BusInterruptLevel
== 0 && PortConfig
->BusInterruptVector
== 0))
1271 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1273 /* FIXME: Use synchronization routine */
1274 ASSERT("No interrupts branch requires changes in synchronization\n");
1276 DeviceExtension
->Interrupt
= (PVOID
)DeviceExtension
;
1277 DPRINT("No interrupts\n");
1282 /* Are 2 interrupts needed? */
1283 if (DeviceExtension
->HwInterrupt
!= NULL
&&
1284 (PortConfig
->BusInterruptLevel
!= 0 || PortConfig
->BusInterruptVector
!= 0) &&
1285 (PortConfig
->BusInterruptLevel2
!= 0 || PortConfig
->BusInterruptVector2
!= 0))
1287 DPRINT1("2 interrupts requested! Not yet supported\n");
1292 BOOLEAN InterruptShareable
;
1294 /* No, only 1 interrupt */
1295 DPRINT("1 interrupt, IRQ is %d\n", PortConfig
->BusInterruptLevel
);
1297 DeviceExtension
->InterruptLevel
= PortConfig
->BusInterruptLevel
;
1299 /* Register an interrupt handler for this device */
1300 MappedIrq
= HalGetInterruptVector(PortConfig
->AdapterInterfaceType
,
1301 PortConfig
->SystemIoBusNumber
,
1302 PortConfig
->BusInterruptLevel
,
1303 PortConfig
->BusInterruptVector
,
1307 /* Determing IRQ sharability as usual */
1308 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1309 PortConfig
->InterruptMode
== LevelSensitive
)
1311 InterruptShareable
= TRUE
;
1315 InterruptShareable
= FALSE
;
1318 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
,
1319 (PKSERVICE_ROUTINE
)ScsiPortIsr
,
1325 PortConfig
->InterruptMode
,
1330 if (!(NT_SUCCESS(Status
)))
1332 DPRINT1("Could not connect interrupt %d\n",
1333 PortConfig
->BusInterruptVector
);
1334 DeviceExtension
->Interrupt
= NULL
;
1341 /* Save IoAddress (from access ranges) */
1342 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1344 DeviceExtension
->IoAddress
=
1345 ((*(PortConfig
->AccessRanges
))[0]).RangeStart
.LowPart
;
1347 DPRINT("Io Address %x\n", DeviceExtension
->IoAddress
);
1350 /* Set flag that it's allowed to disconnect during this command */
1351 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
1353 /* Initialize counter of active requests (-1 means there are none) */
1354 DeviceExtension
->ActiveRequestCounter
= -1;
1356 /* Analyze what we have about DMA */
1357 if (DeviceExtension
->AdapterObject
!= NULL
&&
1358 PortConfig
->Master
&&
1359 PortConfig
->NeedPhysicalAddresses
)
1361 DeviceExtension
->MapRegisters
= TRUE
;
1365 DeviceExtension
->MapRegisters
= FALSE
;
1368 /* Call HwInitialize at DISPATCH_LEVEL */
1369 KeRaiseIrql(DISPATCH_LEVEL
, &Dirql
);
1371 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1372 DeviceExtension
->HwInitialize
,
1373 DeviceExtension
->MiniPortDeviceExtension
))
1375 DPRINT1("HwInitialize() failed!\n");
1377 Status
= STATUS_ADAPTER_HARDWARE_ERROR
;
1381 /* Check if a notification is needed */
1382 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
1384 /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1385 ScsiPortDpcForIsr(NULL
,
1386 DeviceExtension
->DeviceObject
,
1391 /* Lower irql back to what it was */
1394 /* Start our timer */
1395 IoStartTimer(PortDeviceObject
);
1397 /* Initialize bus scanning information */
1398 DeviceExtension
->BusesConfig
= ExAllocatePool(PagedPool
,
1399 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1402 if (!DeviceExtension
->BusesConfig
)
1404 DPRINT1("Out of resources!\n");
1405 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1410 RtlZeroMemory(DeviceExtension
->BusesConfig
,
1411 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1414 /* Store number of buses there */
1415 DeviceExtension
->BusesConfig
->NumberOfBuses
= DeviceExtension
->BusNum
;
1417 /* Scan the adapter for devices */
1418 SpiScanAdapter(DeviceExtension
);
1420 /* Build the registry device map */
1421 SpiBuildDeviceMap(DeviceExtension
,
1422 (PUNICODE_STRING
)Argument2
);
1424 /* Create the dos device link */
1425 swprintf(DosNameBuffer
,
1427 SystemConfig
->ScsiPortCount
);
1428 RtlInitUnicodeString(&DosDeviceName
, DosNameBuffer
);
1429 IoCreateSymbolicLink(&DosDeviceName
, &DeviceName
);
1431 /* Increase the port count */
1432 SystemConfig
->ScsiPortCount
++;
1433 FirstConfigCall
= FALSE
;
1435 /* Increase adapter number and bus number respectively */
1436 ConfigInfo
.AdapterNumber
++;
1439 ConfigInfo
.BusNumber
++;
1441 DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber
, MaxBus
);
1446 /* Clean up the mess */
1447 SpiCleanupAfterInit(DeviceExtension
);
1449 /* Close registry keys */
1450 if (ConfigInfo
.ServiceKey
!= NULL
)
1451 ZwClose(ConfigInfo
.ServiceKey
);
1453 if (ConfigInfo
.DeviceKey
!= NULL
)
1454 ZwClose(ConfigInfo
.DeviceKey
);
1456 if (ConfigInfo
.BusKey
!= NULL
)
1457 ZwClose(ConfigInfo
.BusKey
);
1459 if (ConfigInfo
.AccessRanges
!= NULL
)
1460 ExFreePool(ConfigInfo
.AccessRanges
);
1462 if (ConfigInfo
.Parameter
!= NULL
)
1463 ExFreePool(ConfigInfo
.Parameter
);
1465 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %b!\n",
1466 Status
, DeviceFound
);
1468 return (DeviceFound
== FALSE
) ? Status
: STATUS_SUCCESS
;
1472 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1474 PSCSI_LUN_INFO LunInfo
;
1478 /* Check if we have something to clean up */
1479 if (DeviceExtension
== NULL
)
1482 /* Stop the timer and disconnect the interrupt */
1483 if (DeviceExtension
->Interrupt
)
1485 IoStopTimer(DeviceExtension
->DeviceObject
);
1486 IoDisconnectInterrupt(DeviceExtension
->Interrupt
);
1489 /* Delete ConfigInfo */
1490 if (DeviceExtension
->BusesConfig
)
1492 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
1494 if (!DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
])
1497 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
1501 /* Free current, but save pointer to the next one */
1502 Ptr
= LunInfo
->Next
;
1503 ExFreePool(LunInfo
);
1507 ExFreePool(DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]);
1510 ExFreePool(DeviceExtension
->BusesConfig
);
1513 /* Free PortConfig */
1514 if (DeviceExtension
->PortConfig
)
1515 ExFreePool(DeviceExtension
->PortConfig
);
1518 for(Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
1520 while (DeviceExtension
->LunExtensionList
[Lun
])
1522 Ptr
= DeviceExtension
->LunExtensionList
[Lun
];
1523 DeviceExtension
->LunExtensionList
[Lun
] = DeviceExtension
->LunExtensionList
[Lun
]->Next
;
1529 /* Free common buffer (if it exists) */
1530 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
&&
1531 DeviceExtension
->CommonBufferSize
!= 0)
1533 if (!DeviceExtension
->AdapterObject
)
1535 ExFreePool(DeviceExtension
->SrbExtensionBuffer
);
1540 HalFreeCommonBuffer(DeviceExtension
->AdapterObject
,
1541 DeviceExtension
->CommonBufferSize
,
1542 DeviceExtension
->PhysicalCommonBuffer
,
1543 DeviceExtension
->SrbExtensionBuffer
,
1550 if (DeviceExtension
->SrbInfo
!= NULL
)
1551 ExFreePool(DeviceExtension
->SrbInfo
);
1553 /* Unmap mapped addresses */
1554 while (DeviceExtension
->MappedAddressList
!= NULL
)
1556 MmUnmapIoSpace(DeviceExtension
->MappedAddressList
->MappedAddress
,
1557 DeviceExtension
->MappedAddressList
->NumberOfBytes
);
1559 Ptr
= DeviceExtension
->MappedAddressList
;
1560 DeviceExtension
->MappedAddressList
= DeviceExtension
->MappedAddressList
->NextMappedAddress
;
1565 /* Finally delete the device object */
1566 DPRINT("Deleting device %p\n", DeviceExtension
->DeviceObject
);
1567 IoDeleteDevice(DeviceExtension
->DeviceObject
);
1576 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
1577 IN PSCSI_REQUEST_BLOCK Srb
,
1578 IN PVOID LogicalAddress
,
1581 DPRINT1("ScsiPortIoMapTransfer()\n");
1590 ScsiPortLogError(IN PVOID HwDeviceExtension
,
1591 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
1598 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1600 DPRINT1("ScsiPortLogError() called\n");
1602 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1603 SCSI_PORT_DEVICE_EXTENSION
,
1604 MiniPortDeviceExtension
);
1607 DPRINT("ScsiPortLogError() done\n");
1615 ScsiPortMoveMemory(OUT PVOID Destination
,
1619 RtlMoveMemory(Destination
,
1629 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
1630 IN PVOID HwDeviceExtension
,
1633 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1636 DPRINT("ScsiPortNotification() called\n");
1638 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1639 SCSI_PORT_DEVICE_EXTENSION
,
1640 MiniPortDeviceExtension
);
1642 DPRINT("DeviceExtension %p\n", DeviceExtension
);
1644 va_start(ap
, HwDeviceExtension
);
1646 switch (NotificationType
)
1648 case RequestComplete
:
1650 PSCSI_REQUEST_BLOCK Srb
;
1651 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1653 Srb
= (PSCSI_REQUEST_BLOCK
) va_arg (ap
, PSCSI_REQUEST_BLOCK
);
1655 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb
);
1657 /* Make sure Srb is allright */
1658 ASSERT(Srb
->SrbStatus
!= SRB_STATUS_PENDING
);
1659 ASSERT(Srb
->Function
!= SRB_FUNCTION_EXECUTE_SCSI
|| Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
|| Srb
->ScsiStatus
== SCSISTAT_GOOD
);
1661 if (!(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
1663 /* It's been already completed */
1668 /* It's not active anymore */
1669 Srb
->SrbFlags
&= ~SRB_FLAGS_IS_ACTIVE
;
1671 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
1673 /* TODO: Treat it specially */
1678 /* Get the SRB data */
1679 SrbData
= SpiGetSrbData(DeviceExtension
,
1685 /* Make sure there are no CompletedRequests and there is a Srb */
1686 ASSERT(SrbData
->CompletedRequests
== NULL
&& SrbData
->Srb
!= NULL
);
1688 /* If it's a read/write request, make sure it has data inside it */
1689 if ((Srb
->SrbStatus
== SRB_STATUS_SUCCESS
) &&
1690 ((Srb
->Cdb
[0] == SCSIOP_READ
) || (Srb
->Cdb
[0] == SCSIOP_WRITE
)))
1692 ASSERT(Srb
->DataTransferLength
);
1695 SrbData
->CompletedRequests
= DeviceExtension
->InterruptData
.CompletedRequests
;
1696 DeviceExtension
->InterruptData
.CompletedRequests
= SrbData
;
1702 DPRINT("Notify: NextRequest\n");
1703 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1712 PathId
= (UCHAR
) va_arg (ap
, int);
1713 TargetId
= (UCHAR
) va_arg (ap
, int);
1714 Lun
= (UCHAR
) va_arg (ap
, int);
1716 DPRINT1 ("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1717 PathId
, TargetId
, Lun
);
1718 /* FIXME: Implement it! */
1721 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
1722 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT_LU;
1725 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
1730 DPRINT1("Notify: ResetDetected\n");
1735 DPRINT1 ("Unsupported notification %lu\n", NotificationType
);
1741 /* Request a DPC after we're done with the interrupt */
1742 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NOTIFICATION_NEEDED
;
1750 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
1751 IN ULONG BusDataType
,
1752 IN ULONG SystemIoBusNumber
,
1753 IN ULONG SlotNumber
,
1758 DPRINT("ScsiPortSetBusDataByOffset()\n");
1759 return(HalSetBusDataByOffset(BusDataType
,
1772 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
1773 IN INTERFACE_TYPE BusType
,
1774 IN ULONG SystemIoBusNumber
,
1775 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
1776 IN ULONG NumberOfBytes
,
1777 IN BOOLEAN InIoSpace
)
1779 DPRINT("ScsiPortValidateRange()\n");
1784 /* INTERNAL FUNCTIONS ********************************************************/
1787 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
1788 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
1789 IN PPORT_CONFIGURATION_INFORMATION PortConfig
)
1791 PACCESS_RANGE AccessRange
;
1792 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData
;
1798 /* Loop through all entries */
1799 for (Index
= 0; Index
< ResourceDescriptor
->PartialResourceList
.Count
; Index
++)
1801 PartialData
= &ResourceDescriptor
->PartialResourceList
.PartialDescriptors
[Index
];
1803 switch (PartialData
->Type
)
1805 case CmResourceTypePort
:
1806 /* Copy access ranges */
1807 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
1809 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
1811 AccessRange
->RangeStart
= PartialData
->u
.Port
.Start
;
1812 AccessRange
->RangeLength
= PartialData
->u
.Port
.Length
;
1814 AccessRange
->RangeInMemory
= FALSE
;
1819 case CmResourceTypeMemory
:
1820 /* Copy access ranges */
1821 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
1823 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
1825 AccessRange
->RangeStart
= PartialData
->u
.Memory
.Start
;
1826 AccessRange
->RangeLength
= PartialData
->u
.Memory
.Length
;
1828 AccessRange
->RangeInMemory
= TRUE
;
1833 case CmResourceTypeInterrupt
:
1834 /* Copy interrupt data */
1835 PortConfig
->BusInterruptLevel
= PartialData
->u
.Interrupt
.Level
;
1836 PortConfig
->BusInterruptVector
= PartialData
->u
.Interrupt
.Vector
;
1838 /* Set interrupt mode accordingly to the resource */
1839 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
1841 PortConfig
->InterruptMode
= Latched
;
1843 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
1845 PortConfig
->InterruptMode
= LevelSensitive
;
1849 case CmResourceTypeDma
:
1850 PortConfig
->DmaChannel
= PartialData
->u
.Dma
.Channel
;
1851 PortConfig
->DmaPort
= PartialData
->u
.Dma
.Port
;
1857 static PCM_RESOURCE_LIST
1858 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1859 PPORT_CONFIGURATION_INFORMATION PortConfig
)
1861 PCONFIGURATION_INFORMATION ConfigInfo
;
1862 PCM_RESOURCE_LIST ResourceList
;
1863 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
1864 PACCESS_RANGE AccessRange
;
1866 ULONG ListLength
= 0, i
, FullSize
;
1869 /* Get current Atdisk usage from the system */
1870 ConfigInfo
= IoGetConfigurationInformation();
1872 if (PortConfig
->AtdiskPrimaryClaimed
)
1873 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
1875 if (PortConfig
->AtdiskSecondaryClaimed
)
1876 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
1878 /* Do we use DMA? */
1879 if (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
||
1880 PortConfig
->DmaPort
!= SP_UNINITIALIZED_VALUE
)
1890 /* How many interrupts to we have? */
1891 if (DeviceExtension
->HwInterrupt
== NULL
||
1892 (PortConfig
->BusInterruptLevel
== 0 &&
1893 PortConfig
->BusInterruptVector
== 0))
1903 if (DeviceExtension
->HwInterrupt
!= NULL
&&
1904 (PortConfig
->BusInterruptLevel2
!= 0 ||
1905 PortConfig
->BusInterruptVector2
!= 0))
1911 /* How many access ranges do we use? */
1912 AccessRange
= &((*(PortConfig
->AccessRanges
))[0]);
1913 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
1915 if (AccessRange
->RangeLength
!= 0)
1921 /* Allocate the resource list, since we know its size now */
1922 FullSize
= sizeof(CM_RESOURCE_LIST
) + (ListLength
- 1) *
1923 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1925 ResourceList
= (PCM_RESOURCE_LIST
)ExAllocatePool(PagedPool
, FullSize
);
1931 RtlZeroMemory(ResourceList
, FullSize
);
1934 ResourceList
->Count
= 1;
1935 ResourceList
->List
[0].InterfaceType
= PortConfig
->AdapterInterfaceType
;
1936 ResourceList
->List
[0].BusNumber
= PortConfig
->SystemIoBusNumber
;
1937 ResourceList
->List
[0].PartialResourceList
.Count
= ListLength
;
1938 ResourceDescriptor
= ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
;
1940 /* Copy access ranges array over */
1941 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
1943 AccessRange
= &((*(PortConfig
->AccessRanges
))[i
]);
1945 /* If the range is empty - skip it */
1946 if (AccessRange
->RangeLength
== 0)
1949 if (AccessRange
->RangeInMemory
)
1951 ResourceDescriptor
->Type
= CmResourceTypeMemory
;
1952 ResourceDescriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
;
1956 ResourceDescriptor
->Type
= CmResourceTypePort
;
1957 ResourceDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
1960 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
1962 ResourceDescriptor
->u
.Memory
.Start
= AccessRange
->RangeStart
;
1963 ResourceDescriptor
->u
.Memory
.Length
= AccessRange
->RangeLength
;
1965 ResourceDescriptor
++;
1968 /* If we use interrupt(s), copy them */
1971 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
1973 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1974 PortConfig
->InterruptMode
== LevelSensitive
)
1976 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
1977 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
1981 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
1982 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
1985 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
1986 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
1987 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
1989 ResourceDescriptor
++;
1993 /* Copy 2nd interrupt
1994 FIXME: Stupid code duplication, remove */
1997 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
1999 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2000 PortConfig
->InterruptMode
== LevelSensitive
)
2002 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2003 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2007 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2008 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2011 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
2012 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
2013 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2015 ResourceDescriptor
++;
2021 ResourceDescriptor
->Type
= CmResourceTypeDma
;
2022 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2023 ResourceDescriptor
->u
.Dma
.Channel
= PortConfig
->DmaChannel
;
2024 ResourceDescriptor
->u
.Dma
.Port
= PortConfig
->DmaPort
;
2025 ResourceDescriptor
->Flags
= 0;
2027 if (PortConfig
->DmaChannel
== SP_UNINITIALIZED_VALUE
)
2028 ResourceDescriptor
->u
.Dma
.Channel
= 0;
2030 if (PortConfig
->DmaPort
== SP_UNINITIALIZED_VALUE
)
2031 ResourceDescriptor
->u
.Dma
.Port
= 0;
2034 return ResourceList
;
2039 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
2040 IN PDEVICE_OBJECT DeviceObject
,
2041 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
2042 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
2043 IN PUNICODE_STRING RegistryPath
,
2045 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
)
2047 PCI_COMMON_CONFIG PciConfig
;
2048 PCI_SLOT_NUMBER SlotNumber
;
2051 ULONG FunctionNumber
;
2052 CHAR VendorIdString
[8];
2053 CHAR DeviceIdString
[8];
2054 UNICODE_STRING UnicodeStr
;
2055 PCM_RESOURCE_LIST ResourceList
;
2058 DPRINT ("SpiGetPciConfiguration() called\n");
2060 SlotNumber
.u
.AsULONG
= 0;
2062 /* Loop through all devices */
2063 for (DeviceNumber
= NextSlotNumber
->u
.bits
.DeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
2065 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
2067 /* Loop through all functions */
2068 for (FunctionNumber
= NextSlotNumber
->u
.bits
.FunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
2070 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
2072 /* Get PCI config bytes */
2073 DataSize
= HalGetBusData(PCIConfiguration
,
2075 SlotNumber
.u
.AsULONG
,
2079 /* There is nothing there */
2080 if (DataSize
< sizeof(ULONG
))
2083 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
2086 sprintf (VendorIdString
, "%04hx", PciConfig
.VendorID
);
2087 sprintf (DeviceIdString
, "%04hx", PciConfig
.DeviceID
);
2089 if (_strnicmp(VendorIdString
, HwInitializationData
->VendorId
, HwInitializationData
->VendorIdLength
) ||
2090 _strnicmp(DeviceIdString
, HwInitializationData
->DeviceId
, HwInitializationData
->DeviceIdLength
))
2092 /* It is not our device */
2096 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2100 SlotNumber
.u
.bits
.DeviceNumber
,
2101 SlotNumber
.u
.bits
.FunctionNumber
);
2104 RtlInitUnicodeString(&UnicodeStr
, L
"ScsiAdapter");
2105 Status
= HalAssignSlotResources(RegistryPath
,
2111 SlotNumber
.u
.AsULONG
,
2114 if (!NT_SUCCESS(Status
))
2117 /* Create configuration information */
2118 SpiResourceToConfig(HwInitializationData
,
2122 /* Free the resource list */
2123 ExFreePool(ResourceList
);
2125 /* Set dev & fn numbers */
2126 NextSlotNumber
->u
.bits
.DeviceNumber
= DeviceNumber
;
2127 NextSlotNumber
->u
.bits
.FunctionNumber
= FunctionNumber
+ 1;
2129 /* Save the slot number */
2130 PortConfig
->SlotNumber
= SlotNumber
.u
.AsULONG
;
2134 NextSlotNumber
->u
.bits
.FunctionNumber
= 0;
2137 NextSlotNumber
->u
.bits
.DeviceNumber
= 0;
2138 DPRINT ("No device found\n");
2145 /**********************************************************************
2147 * ScsiPortCreateClose
2150 * Answer requests for Create/Close calls: a null operation.
2157 * Pointer to a device object.
2160 * Pointer to an IRP.
2166 static NTSTATUS STDCALL
2167 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
2170 DPRINT("ScsiPortCreateClose()\n");
2172 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2173 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2175 return STATUS_SUCCESS
;
2179 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2182 PSCSI_LUN_INFO LunInfo
;
2183 PIO_STACK_LOCATION IrpStack
;
2184 PDEVICE_OBJECT DeviceObject
;
2185 PSCSI_REQUEST_BLOCK Srb
;
2188 /* Get pointer to the SRB */
2189 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2190 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
2192 /* Check if PathId matches number of buses */
2193 if (DeviceExtension
->BusesConfig
== NULL
||
2194 DeviceExtension
->BusesConfig
->NumberOfBuses
<= Srb
->PathId
)
2196 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2197 return STATUS_DEVICE_DOES_NOT_EXIST
;
2200 /* Get pointer to LunInfo */
2201 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Srb
->PathId
]->LunInfo
;
2203 /* Find matching LunInfo */
2206 if (LunInfo
->PathId
== Srb
->PathId
&&
2207 LunInfo
->TargetId
== Srb
->TargetId
&&
2208 LunInfo
->Lun
== Srb
->Lun
)
2213 LunInfo
= LunInfo
->Next
;
2216 /* If we couldn't find it - exit */
2217 if (LunInfo
== NULL
)
2218 return STATUS_DEVICE_DOES_NOT_EXIST
;
2222 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2224 /* Release, if asked */
2225 if (Srb
->Function
== SRB_FUNCTION_RELEASE_DEVICE
)
2227 LunInfo
->DeviceClaimed
= FALSE
;
2228 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2229 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2231 return STATUS_SUCCESS
;
2234 /* Attach, if not already claimed */
2235 if (LunInfo
->DeviceClaimed
)
2237 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2238 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
2240 return STATUS_DEVICE_BUSY
;
2243 /* Save the device object */
2244 DeviceObject
= LunInfo
->DeviceObject
;
2246 if (Srb
->Function
== SRB_FUNCTION_CLAIM_DEVICE
)
2247 LunInfo
->DeviceClaimed
= TRUE
;
2249 if (Srb
->Function
== SRB_FUNCTION_ATTACH_DEVICE
)
2250 LunInfo
->DeviceObject
= Srb
->DataBuffer
;
2252 Srb
->DataBuffer
= DeviceObject
;
2254 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2255 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2257 return STATUS_SUCCESS
;
2261 /**********************************************************************
2263 * ScsiPortDispatchScsi
2266 * Answer requests for SCSI calls
2272 * Standard dispatch arguments
2278 static NTSTATUS STDCALL
2279 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
2282 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2283 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2284 PIO_STACK_LOCATION Stack
;
2285 PSCSI_REQUEST_BLOCK Srb
;
2287 NTSTATUS Status
= STATUS_SUCCESS
;
2288 PIRP NextIrp
, IrpList
;
2289 PKDEVICE_QUEUE_ENTRY Entry
;
2291 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2294 DeviceExtension
= DeviceObject
->DeviceExtension
;
2295 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2297 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2300 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2301 Status
= STATUS_UNSUCCESSFUL
;
2303 Irp
->IoStatus
.Status
= Status
;
2304 Irp
->IoStatus
.Information
= 0;
2306 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2311 DPRINT("Srb: %p\n", Srb
);
2312 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
2313 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
2315 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2319 if (LunExtension
== NULL
)
2321 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2322 Status
= STATUS_NO_SUCH_DEVICE
;
2324 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2325 Irp
->IoStatus
.Status
= Status
;
2326 Irp
->IoStatus
.Information
= 0;
2328 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2333 switch (Srb
->Function
)
2335 case SRB_FUNCTION_SHUTDOWN
:
2336 case SRB_FUNCTION_FLUSH
:
2337 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2338 if (DeviceExtension
->CachesData
== FALSE
)
2340 /* All success here */
2341 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2342 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2343 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2344 return STATUS_SUCCESS
;
2346 /* Fall through to a usual execute operation */
2348 case SRB_FUNCTION_EXECUTE_SCSI
:
2349 case SRB_FUNCTION_IO_CONTROL
:
2350 /* Mark IRP as pending in all cases */
2351 IoMarkIrpPending(Irp
);
2353 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2355 /* Start IO directly */
2356 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2362 /* We need to be at DISPATCH_LEVEL */
2363 KeRaiseIrql (DISPATCH_LEVEL
, &oldIrql
);
2365 /* Insert IRP into the queue */
2366 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
2367 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
2370 /* It means the queue is empty, and we just start this request */
2371 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2374 /* Back to the old IRQL */
2375 KeLowerIrql (oldIrql
);
2377 return STATUS_PENDING
;
2379 case SRB_FUNCTION_CLAIM_DEVICE
:
2380 case SRB_FUNCTION_ATTACH_DEVICE
:
2381 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2383 /* Reference device object and keep the device object */
2384 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2387 case SRB_FUNCTION_RELEASE_DEVICE
:
2388 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2390 /* Dereference device object and clear the device object */
2391 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2394 case SRB_FUNCTION_RELEASE_QUEUE
:
2395 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2397 /* Guard with the spinlock */
2398 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2400 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2402 DPRINT("Queue is not frozen really\n");
2404 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2405 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2406 Status
= STATUS_SUCCESS
;
2411 /* Unfreeze the queue */
2412 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2414 if (LunExtension
->SrbInfo
.Srb
== NULL
)
2416 /* Get next logical unit request */
2417 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
2419 /* SpiGetNextRequestFromLun() releases the spinlock */
2424 DPRINT("The queue has active request\n");
2425 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2429 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2430 Status
= STATUS_SUCCESS
;
2433 case SRB_FUNCTION_FLUSH_QUEUE
:
2434 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2436 /* Guard with the spinlock */
2437 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2439 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2441 DPRINT("Queue is not frozen really\n");
2443 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2444 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2448 /* Make sure there is no active request */
2449 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
2451 /* Compile a list from the device queue */
2453 while ((Entry
= KeRemoveDeviceQueue(&LunExtension
->DeviceQueue
)) != NULL
)
2455 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
2458 Stack
= IoGetCurrentIrpStackLocation(NextIrp
);
2459 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2462 Srb
->SrbStatus
= SRB_STATUS_REQUEST_FLUSHED
;
2463 NextIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2465 /* Add then to the list */
2466 NextIrp
->Tail
.Overlay
.ListEntry
.Flink
= (PLIST_ENTRY
)IrpList
;
2470 /* Unfreeze the queue */
2471 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2473 /* Release the spinlock */
2474 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2476 /* Complete those requests */
2480 IrpList
= (PIRP
)NextIrp
->Tail
.Overlay
.ListEntry
.Flink
;
2482 IoCompleteRequest(NextIrp
, 0);
2485 Status
= STATUS_SUCCESS
;
2489 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
2490 Status
= STATUS_NOT_IMPLEMENTED
;
2494 Irp
->IoStatus
.Status
= Status
;
2496 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2502 /**********************************************************************
2504 * ScsiPortDeviceControl
2507 * Answer requests for device control calls
2513 * Standard dispatch arguments
2519 static NTSTATUS STDCALL
2520 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
2523 PIO_STACK_LOCATION Stack
;
2524 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2525 NTSTATUS Status
= STATUS_SUCCESS
;;
2527 DPRINT("ScsiPortDeviceControl()\n");
2529 Irp
->IoStatus
.Information
= 0;
2531 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2532 DeviceExtension
= DeviceObject
->DeviceExtension
;
2534 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
2536 case IOCTL_SCSI_GET_DUMP_POINTERS
:
2538 PDUMP_POINTERS DumpPointers
;
2539 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2540 DumpPointers
= (PDUMP_POINTERS
)Irp
->AssociatedIrp
.SystemBuffer
;
2541 DumpPointers
->DeviceObject
= DeviceObject
;
2543 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2547 case IOCTL_SCSI_GET_CAPABILITIES
:
2548 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2549 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
== sizeof(PVOID
))
2551 *((PVOID
*)Irp
->AssociatedIrp
.SystemBuffer
) = &DeviceExtension
->PortCapabilities
;
2553 Irp
->IoStatus
.Information
= sizeof(PVOID
);
2554 Status
= STATUS_SUCCESS
;
2558 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(IO_SCSI_CAPABILITIES
))
2560 Status
= STATUS_BUFFER_TOO_SMALL
;
2564 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2565 &DeviceExtension
->PortCapabilities
,
2566 sizeof(IO_SCSI_CAPABILITIES
));
2568 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
2569 Status
= STATUS_SUCCESS
;
2572 case IOCTL_SCSI_GET_INQUIRY_DATA
:
2573 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2575 /* Copy inquiry data to the port device extension */
2576 Status
= SpiGetInquiryData(DeviceExtension
, Irp
);
2580 DPRINT1(" unknown ioctl code: 0x%lX\n",
2581 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2585 /* Complete the request with the given status */
2586 Irp
->IoStatus
.Status
= Status
;
2587 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2594 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
2597 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2598 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2599 PIO_STACK_LOCATION IrpStack
;
2600 PSCSI_REQUEST_BLOCK Srb
;
2601 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2604 DPRINT("ScsiPortStartIo() called!\n");
2606 DeviceExtension
= DeviceObject
->DeviceExtension
;
2607 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2609 DPRINT("DeviceExtension %p\n", DeviceExtension
);
2611 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2613 /* Apply "default" flags */
2614 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
2616 /* Get LUN extension */
2617 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2622 if (DeviceExtension
->NeedSrbDataAlloc
||
2623 DeviceExtension
->NeedSrbExtensionAlloc
)
2625 /* TODO: Implement */
2631 /* No allocations are needed */
2632 SrbInfo
= &LunExtension
->SrbInfo
;
2633 Srb
->SrbExtension
= NULL
;
2634 Srb
->QueueTag
= SP_UNTAGGED
;
2637 /* Increase sequence number of SRB */
2638 if (!SrbInfo
->SequenceNumber
)
2640 /* Increase global sequence number */
2641 DeviceExtension
->SequenceNumber
++;
2644 SrbInfo
->SequenceNumber
= DeviceExtension
->SequenceNumber
;
2647 /* Check some special SRBs */
2648 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2650 /* Some special handling */
2651 DPRINT1("Abort command! Unimplemented now\n");
2658 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
)
2660 // Store the MDL virtual address in SrbInfo structure
2661 SrbInfo
->DataOffset
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2663 if (DeviceExtension
->MapBuffers
&& Irp
->MdlAddress
)
2665 /* Calculate offset within DataBuffer */
2666 SrbInfo
->DataOffset
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
2667 Srb
->DataBuffer
= SrbInfo
->DataOffset
+
2668 (ULONG
)((PUCHAR
)Srb
->DataBuffer
-
2669 (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2672 if (DeviceExtension
->AdapterObject
)
2675 KeFlushIoBuffers(Irp
->MdlAddress
,
2676 Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? TRUE
: FALSE
,
2680 if (DeviceExtension
->MapRegisters
)
2683 /* Calculate number of needed map registers */
2684 SrbInfo
->NumberOfMapRegisters
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
2686 Srb
->DataTransferLength
);
2688 /* Allocate adapter channel */
2689 Status
= IoAllocateAdapterChannel(DeviceExtension
->AdapterObject
,
2690 DeviceExtension
->DeviceObject
,
2691 SrbInfo
->NumberOfMapRegisters
,
2695 if (!NT_SUCCESS(Status
))
2697 DPRINT1("IoAllocateAdapterChannel() failed!\n");
2699 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
2700 ScsiPortNotification(RequestComplete
,
2701 DeviceExtension
+ 1,
2704 ScsiPortNotification(NextRequest
,
2705 DeviceExtension
+ 1);
2707 /* Request DPC for that work */
2708 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2711 /* Control goes to SpiAdapterControl */
2719 /* Increase active request counter */
2720 CounterResult
= InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
2722 if (CounterResult
== 0 &&
2723 DeviceExtension
->AdapterObject
!= NULL
&&
2724 !DeviceExtension
->MapRegisters
)
2727 IoAllocateAdapterChannel(
2728 DeviceExtension
->AdapterObject
,
2730 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
,
2731 ScsiPortAllocationRoutine
,
2737 /* TODO: DMA is not implemented yet */
2743 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
2745 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
2746 ScsiPortStartPacket
,
2749 DPRINT("Synchronization failed!\n");
2751 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2752 Irp
->IoStatus
.Information
= 0;
2753 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
2755 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2758 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
2760 DPRINT("ScsiPortStartIo() done\n");
2764 static BOOLEAN STDCALL
2765 ScsiPortStartPacket(IN OUT PVOID Context
)
2767 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2768 PIO_STACK_LOCATION IrpStack
;
2769 PSCSI_REQUEST_BLOCK Srb
;
2770 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)Context
;
2771 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2775 DPRINT("ScsiPortStartPacket() called\n");
2777 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
2779 IrpStack
= IoGetCurrentIrpStackLocation(DeviceObject
->CurrentIrp
);
2780 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2782 /* Get LUN extension */
2783 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2788 /* Check if we are in a reset state */
2789 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
2791 /* Mark the we've got requests while being in the reset state */
2792 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET_REQUEST
;
2796 /* Set the time out value */
2797 DeviceExtension
->TimerCount
= Srb
->TimeOutValue
;
2800 DeviceExtension
->Flags
|= SCSI_PORT_DEVICE_BUSY
;
2802 if (LunExtension
->RequestTimeout
!= -1)
2804 /* Timer already active */
2809 /* It hasn't been initialized yet */
2810 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
2814 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2816 /* Handle bypass-requests */
2818 /* Is this an abort request? */
2819 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2821 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2823 /* Get pointer to SRB info structure */
2824 SrbInfo
= SpiGetSrbData(DeviceExtension
,
2830 /* Check if the request is still "active" */
2831 if (SrbInfo
== NULL
||
2832 SrbInfo
->Srb
== NULL
||
2833 !(SrbInfo
->Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
2835 /* It's not, mark it as active then */
2836 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
2839 LunExtension
->RequestTimeout
= -1;
2841 DPRINT("Request has been already completed, but abort request came\n");
2842 Srb
->SrbStatus
= SRB_STATUS_ABORT_FAILED
;
2844 /* Notify about request complete */
2845 ScsiPortNotification(RequestComplete
,
2846 DeviceExtension
->MiniPortDeviceExtension
,
2849 /* and about readiness for the next request */
2850 ScsiPortNotification(NextRequest
,
2851 DeviceExtension
->MiniPortDeviceExtension
);
2853 /* They might ask for some work, so queue the DPC for them */
2854 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2856 /* We're done in this branch */
2862 /* Add number of queued requests */
2863 LunExtension
->QueueCount
++;
2866 /* Bypass requests don't need request sense */
2867 LunExtension
->Flags
&= ~LUNEX_NEED_REQUEST_SENSE
;
2869 /* Is disconnect disabled for this request? */
2870 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
2872 /* Set the corresponding flag */
2873 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
2876 /* Transfer timeout value from Srb to Lun */
2877 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
2881 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
2883 /* It's a disconnect, so no more requests can go */
2884 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
2887 LunExtension
->Flags
|= SCSI_PORT_LU_ACTIVE
;
2889 /* Increment queue count */
2890 LunExtension
->QueueCount
++;
2892 /* If it's tagged - special thing */
2893 if (Srb
->QueueTag
!= SP_UNTAGGED
)
2895 /* TODO: Support tagged requests */
2900 /* Mark this Srb active */
2901 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
2903 /* Call HwStartIo routine */
2904 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
2907 /* If notification is needed, then request a DPC */
2908 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
2909 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2914 static PSCSI_PORT_LUN_EXTENSION
2915 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
2917 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2918 ULONG LunExtensionSize
;
2920 DPRINT("SpiAllocateLunExtension (%p)\n",
2923 /* Round LunExtensionSize first to the sizeof LONGLONG */
2924 LunExtensionSize
= (DeviceExtension
->LunExtensionSize
+
2925 sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
2927 LunExtensionSize
+= sizeof(SCSI_PORT_LUN_EXTENSION
);
2928 DPRINT("LunExtensionSize %lu\n", LunExtensionSize
);
2930 LunExtension
= ExAllocatePool(NonPagedPool
, LunExtensionSize
);
2931 if (LunExtension
== NULL
)
2933 DPRINT1("Out of resources!\n");
2937 /* Zero everything */
2938 RtlZeroMemory(LunExtension
, LunExtensionSize
);
2940 /* Initialize a list of requests */
2941 InitializeListHead(&LunExtension
->SrbInfo
.Requests
);
2943 /* Initialize timeout counter */
2944 LunExtension
->RequestTimeout
= -1;
2946 /* Set maximum queue size */
2947 LunExtension
->MaxQueueCount
= 256;
2949 /* Initialize request queue */
2950 KeInitializeDeviceQueue (&LunExtension
->DeviceQueue
);
2952 return LunExtension
;
2955 static PSCSI_PORT_LUN_EXTENSION
2956 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2961 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2963 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
2964 DeviceExtension
, PathId
, TargetId
, Lun
);
2966 /* Get appropriate list */
2967 LunExtension
= DeviceExtension
->LunExtensionList
[(TargetId
+ Lun
) % LUS_NUMBER
];
2969 /* Iterate it until we find what we need */
2970 while (LunExtension
)
2972 if (LunExtension
->TargetId
== TargetId
&&
2973 LunExtension
->Lun
== Lun
&&
2974 LunExtension
->PathId
== PathId
)
2976 /* All matches, return */
2977 return LunExtension
;
2980 /* Advance to the next item */
2981 LunExtension
= LunExtension
->Next
;
2984 /* We did not find anything */
2985 DPRINT("Nothing found\n");
2991 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
2992 IN PSCSI_LUN_INFO LunInfo
)
2994 IO_STATUS_BLOCK IoStatusBlock
;
2995 PIO_STACK_LOCATION IrpStack
;
3000 PINQUIRYDATA InquiryBuffer
;
3001 PSENSE_DATA SenseBuffer
;
3002 BOOLEAN KeepTrying
= TRUE
;
3003 ULONG RetryCount
= 0;
3004 SCSI_REQUEST_BLOCK Srb
;
3006 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3007 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3009 DPRINT ("SpiSendInquiry() called\n");
3011 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3013 InquiryBuffer
= ExAllocatePool (NonPagedPool
, INQUIRYDATABUFFERSIZE
);
3014 if (InquiryBuffer
== NULL
)
3015 return STATUS_INSUFFICIENT_RESOURCES
;
3017 SenseBuffer
= ExAllocatePool (NonPagedPool
, SENSE_BUFFER_SIZE
);
3018 if (SenseBuffer
== NULL
)
3019 return STATUS_INSUFFICIENT_RESOURCES
;
3023 /* Initialize event for waiting */
3024 KeInitializeEvent(&Event
,
3029 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN
,
3034 INQUIRYDATABUFFERSIZE
,
3040 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3041 return STATUS_INSUFFICIENT_RESOURCES
;
3045 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3047 Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
3048 Srb
.OriginalRequest
= Irp
;
3049 Srb
.PathId
= LunInfo
->PathId
;
3050 Srb
.TargetId
= LunInfo
->TargetId
;
3051 Srb
.Lun
= LunInfo
->Lun
;
3052 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3053 Srb
.SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3054 Srb
.TimeOutValue
= 4;
3057 Srb
.SenseInfoBuffer
= SenseBuffer
;
3058 Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3060 Srb
.DataBuffer
= InquiryBuffer
;
3061 Srb
.DataTransferLength
= INQUIRYDATABUFFERSIZE
;
3063 /* Attach Srb to the Irp */
3064 IrpStack
= IoGetNextIrpStackLocation (Irp
);
3065 IrpStack
->Parameters
.Scsi
.Srb
= &Srb
;
3068 Cdb
= (PCDB
)Srb
.Cdb
;
3069 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_INQUIRY
;
3070 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= LunInfo
->Lun
;
3071 Cdb
->CDB6INQUIRY
.AllocationLength
= INQUIRYDATABUFFERSIZE
;
3073 /* Call the driver */
3074 Status
= IoCallDriver(DeviceObject
, Irp
);
3076 /* Wait for it to complete */
3077 if (Status
== STATUS_PENDING
)
3079 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3080 KeWaitForSingleObject(&Event
,
3085 Status
= IoStatusBlock
.Status
;
3088 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status
);
3090 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_SUCCESS
)
3092 /* All fine, copy data over */
3093 RtlCopyMemory(LunInfo
->InquiryData
,
3095 INQUIRYDATABUFFERSIZE
);
3097 Status
= STATUS_SUCCESS
;
3102 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb
.SrbStatus
);
3103 /* Check if the queue is frozen */
3104 if (Srb
.SrbStatus
& SRB_STATUS_QUEUE_FROZEN
)
3106 /* Something weird happened, deal with it (unfreeze the queue) */
3109 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb
.TargetId
);
3111 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3116 /* Clear frozen flag */
3117 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
3119 /* Acquire the spinlock */
3120 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
3122 /* Process the request */
3123 SpiGetNextRequestFromLun(DeviceObject
->DeviceExtension
, LunExtension
);
3125 /* SpiGetNextRequestFromLun() releases the spinlock,
3126 so we just lower irql back to what it was before */
3130 /* Check if data overrun happened */
3131 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
3133 DPRINT("Data overrun at TargetId %d\n", LunInfo
->TargetId
);
3134 /* Nothing dramatic, just copy data, but limiting the size */
3135 RtlCopyMemory(LunInfo
->InquiryData
,
3137 (Srb
.DataTransferLength
> INQUIRYDATABUFFERSIZE
) ?
3138 INQUIRYDATABUFFERSIZE
: Srb
.DataTransferLength
);
3140 Status
= STATUS_SUCCESS
;
3143 else if ((Srb
.SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3144 SenseBuffer
->SenseKey
== SCSI_SENSE_ILLEGAL_REQUEST
)
3146 /* LUN is not valid, but some device responds there.
3147 Mark it as invalid anyway */
3149 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3154 /* Retry a couple of times if no timeout happened */
3155 if ((RetryCount
< 2) &&
3156 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_NO_DEVICE
) &&
3157 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_SELECTION_TIMEOUT
))
3164 /* That's all, go to exit */
3167 /* Set status according to SRB status */
3168 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_FUNCTION
||
3169 SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH
)
3171 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3175 Status
= STATUS_IO_DEVICE_ERROR
;
3183 ExFreePool(InquiryBuffer
);
3184 ExFreePool(SenseBuffer
);
3186 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status
);
3192 /* Scans all SCSI buses */
3194 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3196 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3200 PSCSI_BUS_SCAN_INFO BusScanInfo
;
3201 PSCSI_LUN_INFO LastLunInfo
, LunInfo
, LunInfoExists
;
3202 BOOLEAN DeviceExists
;
3207 DPRINT("SpiScanAdapter() called\n");
3209 /* Scan all buses */
3210 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
3212 DPRINT(" Scanning bus %d\n", Bus
);
3215 /* Get pointer to the scan information */
3216 BusScanInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
];
3220 /* Find the last LUN info in the list */
3221 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3222 LastLunInfo
= LunInfo
;
3224 while (LunInfo
!= NULL
)
3226 LastLunInfo
= LunInfo
;
3227 LunInfo
= LunInfo
->Next
;
3232 /* We need to allocate this buffer */
3233 BusScanInfo
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_BUS_SCAN_INFO
));
3237 DPRINT1("Out of resources!\n");
3241 /* Store the pointer in the BusScanInfo array */
3242 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
] = BusScanInfo
;
3244 /* Fill this struct (length and bus ids for now) */
3245 BusScanInfo
->Length
= sizeof(SCSI_BUS_SCAN_INFO
);
3246 BusScanInfo
->LogicalUnitsCount
= 0;
3247 BusScanInfo
->BusIdentifier
= DeviceExtension
->PortConfig
->InitiatorBusId
[Bus
];
3248 BusScanInfo
->LunInfo
= NULL
;
3250 /* Set pointer to the last LUN info to NULL */
3254 /* Create LUN information structure */
3255 LunInfo
= ExAllocatePool(PagedPool
, sizeof(SCSI_LUN_INFO
));
3257 if (LunInfo
== NULL
)
3259 DPRINT1("Out of resources!\n");
3263 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3265 /* Create LunExtension */
3266 LunExtension
= SpiAllocateLunExtension (DeviceExtension
);
3268 /* And send INQUIRY to every target */
3269 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
3271 /* TODO: Support scan bottom-up */
3273 /* Skip if it's the same address */
3274 if (Target
== BusScanInfo
->BusIdentifier
)
3277 /* Try to find an existing device here */
3278 DeviceExists
= FALSE
;
3279 LunInfoExists
= BusScanInfo
->LunInfo
;
3281 /* Find matching address on this bus */
3282 while (LunInfoExists
)
3284 if (LunInfoExists
->TargetId
== Target
)
3286 DeviceExists
= TRUE
;
3290 /* Advance to the next one */
3291 LunInfoExists
= LunInfoExists
->Next
;
3294 /* No need to bother rescanning, since we already did that before */
3298 /* Scan all logical units */
3299 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
3304 /* Add extension to the list */
3305 Hint
= (Target
+ Lun
) % LUS_NUMBER
;
3306 LunExtension
->Next
= DeviceExtension
->LunExtensionList
[Hint
];
3307 DeviceExtension
->LunExtensionList
[Hint
] = LunExtension
;
3309 /* Fill Path, Target, Lun fields */
3310 LunExtension
->PathId
= LunInfo
->PathId
= Bus
;
3311 LunExtension
->TargetId
= LunInfo
->TargetId
= Target
;
3312 LunExtension
->Lun
= LunInfo
->Lun
= Lun
;
3314 /* Set flag to prevent race conditions */
3315 LunExtension
->Flags
|= SCSI_PORT_SCAN_IN_PROGRESS
;
3317 /* Zero LU extension contents */
3318 if (DeviceExtension
->LunExtensionSize
)
3320 RtlZeroMemory(LunExtension
+ 1,
3321 DeviceExtension
->LunExtensionSize
);
3324 /* Finally send the inquiry command */
3325 Status
= SpiSendInquiry(DeviceExtension
->DeviceObject
, LunInfo
);
3327 if (NT_SUCCESS(Status
))
3329 /* Let's see if we really found a device */
3330 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3332 /* Check if this device is unsupported */
3333 if (InquiryData
->DeviceTypeQualifier
== DEVICE_QUALIFIER_NOT_SUPPORTED
)
3335 DeviceExtension
->LunExtensionList
[Hint
] =
3336 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3341 /* Clear the "in scan" flag */
3342 LunExtension
->Flags
&= ~SCSI_PORT_SCAN_IN_PROGRESS
;
3344 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3345 InquiryData
->DeviceType
, Bus
, Target
, Lun
);
3347 /* Add this info to the linked list */
3348 LunInfo
->Next
= NULL
;
3350 LastLunInfo
->Next
= LunInfo
;
3352 BusScanInfo
->LunInfo
= LunInfo
;
3354 /* Store the last LUN info */
3355 LastLunInfo
= LunInfo
;
3357 /* Store DeviceObject */
3358 LunInfo
->DeviceObject
= DeviceExtension
->DeviceObject
;
3360 /* Allocate another buffer */
3361 LunInfo
= ExAllocatePool(PagedPool
, sizeof(SCSI_LUN_INFO
));
3365 DPRINT1("Out of resources!\n");
3369 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3371 /* Create a new LU extension */
3372 LunExtension
= SpiAllocateLunExtension(DeviceExtension
);
3378 /* Remove this LUN from the list */
3379 DeviceExtension
->LunExtensionList
[Hint
] =
3380 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3382 /* Decide whether we are continuing or not */
3383 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
3391 /* Free allocated buffers */
3393 ExFreePool(LunExtension
);
3396 ExFreePool(LunInfo
);
3398 /* Sum what we found */
3399 BusScanInfo
->LogicalUnitsCount
+= DevicesFound
;
3400 DPRINT(" Found %d devices on bus %d\n", DevicesFound
, Bus
);
3403 DPRINT ("SpiScanAdapter() done\n");
3408 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3411 ULONG InquiryDataSize
;
3412 PSCSI_LUN_INFO LunInfo
;
3413 ULONG BusCount
, LunCount
, Length
;
3414 PIO_STACK_LOCATION IrpStack
;
3415 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
3416 PSCSI_INQUIRY_DATA InquiryData
;
3417 PSCSI_BUS_DATA BusData
;
3421 DPRINT("SpiGetInquiryData() called\n");
3423 /* Get pointer to the buffer */
3424 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3425 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3427 /* Initialize bus and LUN counters */
3428 BusCount
= DeviceExtension
->BusesConfig
->NumberOfBuses
;
3431 /* Calculate total number of LUNs */
3432 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3433 LunCount
+= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3435 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
3437 ((sizeof(SCSI_INQUIRY_DATA
) - 1 + INQUIRYDATABUFFERSIZE
+
3438 sizeof(ULONG
) - 1) & ~(sizeof(ULONG
) - 1));
3440 /* Calculate data size */
3441 Length
= sizeof(SCSI_ADAPTER_BUS_INFO
) + (BusCount
- 1) *
3442 sizeof(SCSI_BUS_DATA
);
3444 Length
+= InquiryDataSize
* LunCount
;
3446 /* Check, if all data is going to fit into provided buffer */
3447 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< Length
)
3449 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3450 return STATUS_BUFFER_TOO_SMALL
;
3453 /* Store data size in the IRP */
3454 Irp
->IoStatus
.Information
= Length
;
3456 DPRINT("Data size: %lu\n", Length
);
3458 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
3460 AdapterBusInfo
->NumberOfBuses
= (UCHAR
)BusCount
;
3462 /* Point InquiryData to the corresponding place inside Buffer */
3463 InquiryData
= (PSCSI_INQUIRY_DATA
)(Buffer
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
3464 (BusCount
- 1) * sizeof(SCSI_BUS_DATA
));
3467 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3469 BusData
= &AdapterBusInfo
->BusData
[Bus
];
3471 /* Calculate and save an offset of the inquiry data */
3472 BusData
->InquiryDataOffset
= (PUCHAR
)InquiryData
- Buffer
;
3474 /* Get a pointer to the LUN information structure */
3475 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3477 /* Store Initiator Bus Id */
3478 BusData
->InitiatorBusId
=
3479 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->BusIdentifier
;
3481 /* Store LUN count */
3482 BusData
->NumberOfLogicalUnits
=
3483 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3486 while (LunInfo
!= NULL
)
3488 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
3489 Bus
, LunInfo
->TargetId
, LunInfo
->Lun
);
3491 /* Fill InquiryData with values */
3492 InquiryData
->PathId
= LunInfo
->PathId
;
3493 InquiryData
->TargetId
= LunInfo
->TargetId
;
3494 InquiryData
->Lun
= LunInfo
->Lun
;
3495 InquiryData
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
3496 InquiryData
->DeviceClaimed
= LunInfo
->DeviceClaimed
;
3497 InquiryData
->NextInquiryDataOffset
=
3498 (PUCHAR
)InquiryData
+ InquiryDataSize
- Buffer
;
3500 /* Copy data in it */
3501 RtlCopyMemory(InquiryData
->InquiryData
,
3502 LunInfo
->InquiryData
,
3503 INQUIRYDATABUFFERSIZE
);
3505 /* Move to the next LUN */
3506 LunInfo
= LunInfo
->Next
;
3507 InquiryData
= (PSCSI_INQUIRY_DATA
) ((PCHAR
)InquiryData
+ InquiryDataSize
);
3510 /* Either mark the end, or set offset to 0 */
3511 if (BusData
->NumberOfLogicalUnits
!= 0)
3512 ((PSCSI_INQUIRY_DATA
) ((PCHAR
) InquiryData
- InquiryDataSize
))->NextInquiryDataOffset
= 0;
3514 BusData
->InquiryDataOffset
= 0;
3517 /* Finish with success */
3518 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3519 return STATUS_SUCCESS
;
3522 static PSCSI_REQUEST_BLOCK_INFO
3523 SpiGetSrbData(IN PVOID DeviceExtension
,
3529 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3531 if (QueueTag
== SP_UNTAGGED
)
3533 /* Untagged request, get LU and return pointer to SrbInfo */
3534 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3539 /* Return NULL in case of error */
3543 /* Return the pointer to SrbInfo */
3544 return &LunExtension
->SrbInfo
;
3548 /* TODO: Implement when we have it */
3555 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3556 IN PSCSI_REQUEST_BLOCK InitialSrb
)
3558 PSCSI_REQUEST_BLOCK Srb
;
3561 PIO_STACK_LOCATION IrpStack
;
3562 LARGE_INTEGER LargeInt
;
3565 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb
);
3568 Srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
) + sizeof(PVOID
));
3569 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3572 LargeInt
.QuadPart
= (LONGLONG
) 1;
3573 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_READ
,
3574 DeviceExtension
->DeviceObject
,
3575 InitialSrb
->SenseInfoBuffer
,
3576 InitialSrb
->SenseInfoBufferLength
,
3580 IoSetCompletionRoutine(Irp
,
3581 (PIO_COMPLETION_ROUTINE
)SpiCompletionRoutine
,
3587 IrpStack
= IoGetNextIrpStackLocation(Irp
);
3588 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3590 /* Put Srb address into Irp... */
3591 IrpStack
->Parameters
.Others
.Argument1
= (PVOID
)Srb
;
3593 /* ...and vice versa */
3594 Srb
->OriginalRequest
= Irp
;
3597 Ptr
= (PVOID
*)(Srb
+1);
3600 /* Build CDB for REQUEST SENSE */
3602 Cdb
= (PCDB
)Srb
->Cdb
;
3604 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
3605 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= 0;
3606 Cdb
->CDB6INQUIRY
.Reserved1
= 0;
3607 Cdb
->CDB6INQUIRY
.PageCode
= 0;
3608 Cdb
->CDB6INQUIRY
.IReserved
= 0;
3609 Cdb
->CDB6INQUIRY
.AllocationLength
= (UCHAR
)InitialSrb
->SenseInfoBufferLength
;
3610 Cdb
->CDB6INQUIRY
.Control
= 0;
3613 Srb
->TargetId
= InitialSrb
->TargetId
;
3614 Srb
->Lun
= InitialSrb
->Lun
;
3615 Srb
->PathId
= InitialSrb
->PathId
;
3617 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3618 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
3620 /* Timeout will be 2 seconds */
3621 Srb
->TimeOutValue
= 2;
3623 /* No auto request sense */
3624 Srb
->SenseInfoBufferLength
= 0;
3625 Srb
->SenseInfoBuffer
= NULL
;
3627 /* Set necessary flags */
3628 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_BYPASS_FROZEN_QUEUE
|
3629 SRB_FLAGS_DISABLE_DISCONNECT
;
3631 /* Transfer disable synch transfer flag */
3632 if (InitialSrb
->SrbFlags
& SRB_FLAGS_DISABLE_SYNCH_TRANSFER
)
3633 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3635 Srb
->DataBuffer
= InitialSrb
->SenseInfoBuffer
;
3637 /* Fill the transfer length */
3638 Srb
->DataTransferLength
= InitialSrb
->SenseInfoBufferLength
;
3640 /* Clear statuses */
3641 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
3644 /* Call the driver */
3645 (VOID
)IoCallDriver(DeviceExtension
->DeviceObject
, Irp
);
3647 DPRINT("SpiSendRequestSense() done\n");
3654 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3655 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
3656 OUT PBOOLEAN NeedToCallStartIo
)
3658 PSCSI_REQUEST_BLOCK Srb
;
3659 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3662 ULONG SequenceNumber
;
3665 Irp
= Srb
->OriginalRequest
;
3667 /* Get Lun extension */
3668 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3673 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
&&
3674 DeviceExtension
->MapBuffers
&&
3677 /* MDL is shared if transfer is broken into smaller parts */
3678 Srb
->DataBuffer
= (PCCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
3679 ((PCCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
3681 /* In case of data going in, flush the buffers */
3682 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
3684 KeFlushIoBuffers(Irp
->MdlAddress
,
3691 /* Flush adapter if needed */
3692 if (SrbInfo
->BaseOfMapRegister
)
3694 /* TODO: Implement */
3698 /* Clear the request */
3699 SrbInfo
->Srb
= NULL
;
3701 /* If disconnect is disabled... */
3702 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3704 /* Acquire the spinlock since we mess with flags */
3705 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3707 /* Set corresponding flag */
3708 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
3710 /* Clear the timer if needed */
3711 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
))
3712 DeviceExtension
->TimerCount
= -1;
3714 /* Spinlock is not needed anymore */
3715 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3717 if (!(DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
) &&
3718 !(DeviceExtension
->Flags
& SCSI_PORT_DEVICE_BUSY
) &&
3719 !(*NeedToCallStartIo
))
3721 /* We're not busy, but we have a request pending */
3722 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
3726 /* Scatter/gather */
3727 if (Srb
->SrbFlags
& SRB_FLAGS_SGLIST_FROM_POOL
)
3729 /* TODO: Implement */
3733 /* Acquire spinlock (we're freeing SrbExtension) */
3734 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3736 /* Free it (if needed) */
3737 if (Srb
->SrbExtension
)
3739 if (Srb
->SenseInfoBuffer
!= NULL
&& DeviceExtension
->SupportsAutoSense
)
3741 ASSERT(Srb
->SenseInfoBuffer
== NULL
|| SrbInfo
->SaveSenseRequest
!= NULL
);
3743 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)
3745 /* Copy sense data to the buffer */
3746 RtlCopyMemory(SrbInfo
->SaveSenseRequest
,
3747 Srb
->SenseInfoBuffer
,
3748 Srb
->SenseInfoBufferLength
);
3751 /* And restore the pointer */
3752 Srb
->SenseInfoBuffer
= SrbInfo
->SaveSenseRequest
;
3755 /* Put it into the free srb extensions list */
3756 *((PVOID
*)Srb
->SrbExtension
) = DeviceExtension
->FreeSrbExtensions
;
3757 DeviceExtension
->FreeSrbExtensions
= Srb
->SrbExtension
;
3760 /* Save transfer length in the IRP */
3761 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
3763 SequenceNumber
= SrbInfo
->SequenceNumber
;
3764 SrbInfo
->SequenceNumber
= 0;
3766 /* Decrement the queue count */
3767 LunExtension
->QueueCount
--;
3769 /* Free Srb, if needed*/
3770 if (Srb
->QueueTag
!= SP_UNTAGGED
)
3772 /* Put it into the free list */
3773 SrbInfo
->Requests
.Blink
= NULL
;
3774 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
3775 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
3778 /* SrbInfo is not used anymore */
3781 if (DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
)
3783 /* Clear the flag */
3784 DeviceExtension
->Flags
&= ~SCSI_PORT_REQUEST_PENDING
;
3786 /* Note the caller about StartIo */
3787 *NeedToCallStartIo
= TRUE
;
3790 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
3792 /* Start the packet */
3793 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3795 if (!(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
) &&
3796 LunExtension
->RequestTimeout
== -1)
3798 /* Start the next packet */
3799 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
3803 /* Release the spinlock */
3804 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3807 DPRINT("IoCompleting request IRP 0x%08X\n", Irp
);
3809 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
3811 /* Decrement number of active requests, and analyze the result */
3812 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
3815 !DeviceExtension
->MapRegisters
&&
3816 DeviceExtension
->AdapterObject
!= NULL
)
3818 /* Nullify map registers */
3819 DeviceExtension
->MapRegisterBase
= NULL
;
3820 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
3823 /* Exit, we're done */
3827 /* Decrement number of active requests, and analyze the result */
3828 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
3831 !DeviceExtension
->MapRegisters
&&
3832 DeviceExtension
->AdapterObject
!= NULL
)
3834 /* Result is negative, so this is a slave, free map registers */
3835 DeviceExtension
->MapRegisterBase
= NULL
;
3836 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
3839 /* Convert status */
3840 Irp
->IoStatus
.Status
= SpiStatusSrbToNt(Srb
->SrbStatus
);
3842 /* It's not a bypass, it's busy or the queue is full? */
3843 if ((Srb
->ScsiStatus
== SCSISTAT_BUSY
||
3844 Srb
->SrbStatus
== SRB_STATUS_BUSY
||
3845 Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
) &&
3846 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
))
3849 DPRINT("Busy SRB status %x\n", Srb
->SrbStatus
);
3851 /* Requeu, if needed */
3852 if (LunExtension
->Flags
& (LUNEX_FROZEN_QUEUE
| LUNEX_BUSY
))
3854 DPRINT("it's being requeued\n");
3856 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
3857 Srb
->ScsiStatus
= 0;
3859 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
3860 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
3863 /* It's a big f.ck up if we got here */
3864 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
3865 Srb
->ScsiStatus
= SCSISTAT_BUSY
;
3871 /* Release the spinlock */
3872 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3875 else if (LunExtension
->AttemptCount
++ < 20)
3877 /* LUN is still busy */
3878 Srb
->ScsiStatus
= 0;
3879 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
3881 LunExtension
->BusyRequest
= Irp
;
3882 LunExtension
->Flags
|= LUNEX_BUSY
;
3884 /* Release the spinlock */
3885 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3890 /* Freeze the queue*/
3891 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
3892 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
3894 /* "Unfull" the queue */
3895 LunExtension
->Flags
&= ~LUNEX_FULL_QUEUE
;
3897 /* Release the spinlock */
3898 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3900 /* Return status that the device is not ready */
3901 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
3902 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
3908 /* Start the next request, if LUN is idle, and this is sense request */
3909 if (((Srb
->ScsiStatus
!= SCSISTAT_CHECK_CONDITION
) ||
3910 (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) ||
3911 !Srb
->SenseInfoBuffer
|| !Srb
->SenseInfoBufferLength
)
3912 && (Srb
->SrbFlags
& SRB_FLAGS_NO_QUEUE_FREEZE
))
3914 if (LunExtension
->RequestTimeout
== -1)
3915 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
3917 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3921 /* Freeze the queue */
3922 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
3923 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
3925 /* Do we need a request sense? */
3926 if (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
3927 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3928 Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
)
3930 /* If LUN is busy, we have to requeue it in order to allow request sense */
3931 if (LunExtension
->Flags
& LUNEX_BUSY
)
3933 DPRINT("Requeueing busy request to allow request sense\n");
3935 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
3936 &LunExtension
->BusyRequest
->Tail
.Overlay
.DeviceQueueEntry
,
3939 /* We should never get here */
3942 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3943 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
3948 /* Clear busy flags */
3949 LunExtension
->Flags
&= ~(LUNEX_FULL_QUEUE
| LUNEX_BUSY
);
3952 /* Release the spinlock */
3953 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3955 /* Send RequestSense */
3956 SpiSendRequestSense(DeviceExtension
, Srb
);
3962 /* Release the spinlock */
3963 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3966 /* Complete the request */
3967 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
3972 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
3976 PSCSI_REQUEST_BLOCK Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
3977 PSCSI_REQUEST_BLOCK InitialSrb
;
3980 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp
);
3982 if ((Srb
->Function
== SRB_FUNCTION_RESET_BUS
) ||
3983 (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
))
3985 /* Deallocate SRB and IRP and exit */
3989 return STATUS_MORE_PROCESSING_REQUIRED
;
3992 /* Get a pointer to the SRB and IRP which were initially sent */
3993 InitialSrb
= *((PVOID
*)(Srb
+1));
3994 InitialIrp
= InitialSrb
->OriginalRequest
;
3996 if ((SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
) ||
3997 (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_DATA_OVERRUN
))
3999 /* Sense data is OK */
4000 InitialSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
4002 /* Set length to be the same */
4003 InitialSrb
->SenseInfoBufferLength
= (UCHAR
)Srb
->DataTransferLength
;
4006 /* Make sure initial SRB's queue is frozen */
4007 ASSERT(InitialSrb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
);
4009 /* Complete this request */
4010 IoCompleteRequest(InitialIrp
, IO_DISK_INCREMENT
);
4012 /* Deallocate everything (internal) */
4015 if (Irp
->MdlAddress
!= NULL
)
4017 MmUnlockPages(Irp
->MdlAddress
);
4018 IoFreeMdl(Irp
->MdlAddress
);
4019 Irp
->MdlAddress
= NULL
;
4023 return STATUS_MORE_PROCESSING_REQUIRED
;
4028 static BOOLEAN STDCALL
4029 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
4030 IN PVOID ServiceContext
)
4032 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4035 DPRINT("ScsiPortIsr() called!\n");
4037 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
4039 /* If interrupts are disabled - we don't expect any */
4040 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_DISABLE_INTERRUPTS
)
4043 /* Call miniport's HwInterrupt routine */
4044 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
4046 /* If flag of notification is set - queue a DPC */
4047 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4049 IoRequestDpc(DeviceExtension
->DeviceObject
,
4050 DeviceExtension
->CurrentIrp
,
4059 SpiSaveInterruptData(IN PVOID Context
)
4061 PSCSI_PORT_SAVE_INTERRUPT InterruptContext
= Context
;
4062 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4063 PSCSI_REQUEST_BLOCK Srb
;
4064 PSCSI_REQUEST_BLOCK_INFO SrbInfo
, NextSrbInfo
;
4065 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4068 /* Get pointer to the device extension */
4069 DeviceExtension
= InterruptContext
->DeviceExtension
;
4071 /* If we don't have anything pending - return */
4072 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
))
4075 /* Actually save the interrupt data */
4076 *InterruptContext
->InterruptData
= DeviceExtension
->InterruptData
;
4078 /* Clear the data stored in the device extension */
4079 DeviceExtension
->InterruptData
.Flags
&=
4080 (SCSI_PORT_RESET
| SCSI_PORT_RESET_REQUEST
| SCSI_PORT_DISABLE_INTERRUPTS
);
4081 DeviceExtension
->InterruptData
.CompletedAbort
= NULL
;
4082 DeviceExtension
->InterruptData
.ReadyLun
= NULL
;
4083 DeviceExtension
->InterruptData
.CompletedRequests
= NULL
;
4085 /* Loop through the list of completed requests */
4086 SrbInfo
= InterruptContext
->InterruptData
->CompletedRequests
;
4090 /* Make sure we have SRV */
4091 ASSERT(SrbInfo
->Srb
);
4093 /* Get SRB and LunExtension */
4096 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4101 /* We have to check special cases if request is unsuccessfull*/
4102 if (Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
)
4104 /* Check if we need request sense by a few conditions */
4105 if (Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
&&
4106 Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4107 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
))
4109 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
4111 /* It means: we tried to send REQUEST SENSE, but failed */
4113 Srb
->ScsiStatus
= 0;
4114 Srb
->SrbStatus
= SRB_STATUS_REQUEST_SENSE_FAILED
;
4118 /* Set the corresponding flag, so that REQUEST SENSE
4120 LunExtension
->Flags
|= LUNEX_NEED_REQUEST_SENSE
;
4125 /* Check for a full queue */
4126 if (Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
)
4128 /* TODO: Implement when it's encountered */
4133 /* Let's decide if we need to watch timeout or not */
4134 if (Srb
->QueueTag
== SP_UNTAGGED
)
4140 if (LunExtension
->SrbInfo
.Requests
.Flink
== &SrbInfo
->Requests
)
4145 /* Remove it from the queue */
4146 RemoveEntryList(&SrbInfo
->Requests
);
4151 /* We have to maintain timeout counter */
4152 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
))
4154 LunExtension
->RequestTimeout
= -1;
4158 NextSrbInfo
= CONTAINING_RECORD(LunExtension
->SrbInfo
.Requests
.Flink
,
4159 SCSI_REQUEST_BLOCK_INFO
,
4162 Srb
= NextSrbInfo
->Srb
;
4164 /* Update timeout counter */
4165 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
4169 SrbInfo
= SrbInfo
->CompletedRequests
;
4177 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4178 IN PSCSI_PORT_LUN_EXTENSION LunExtension
)
4180 PIO_STACK_LOCATION IrpStack
;
4182 PKDEVICE_QUEUE_ENTRY Entry
;
4183 PSCSI_REQUEST_BLOCK Srb
;
4186 /* If LUN is not active or queue is more than maximum allowed */
4187 if (LunExtension
->QueueCount
>= LunExtension
->MaxQueueCount
||
4188 !(LunExtension
->Flags
& SCSI_PORT_LU_ACTIVE
))
4190 /* Release the spinlock and exit */
4191 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4195 /* Check if we can get a next request */
4196 if (LunExtension
->Flags
&
4197 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_BUSY
|
4198 LUNEX_FULL_QUEUE
| LUNEX_FROZEN_QUEUE
| LUNEX_REQUEST_PENDING
))
4200 /* Pending requests can only be started if the queue is empty */
4201 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
) &&
4202 !(LunExtension
->Flags
&
4203 (LUNEX_BUSY
| LUNEX_FROZEN_QUEUE
| LUNEX_FULL_QUEUE
| LUNEX_NEED_REQUEST_SENSE
)))
4205 /* Make sure we have SRB */
4206 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
4208 /* Clear active and pending flags */
4209 LunExtension
->Flags
&= ~(LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
);
4211 /* Get next Irp, and clear pending requests list */
4212 NextIrp
= LunExtension
->PendingRequest
;
4213 LunExtension
->PendingRequest
= NULL
;
4215 /* Set attempt counter to zero */
4216 LunExtension
->AttemptCount
= 0;
4218 /* Release the spinlock */
4219 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4221 /* Start the next pending request */
4222 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4228 /* Release the spinlock, without clearing any flags and exit */
4229 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4235 /* Reset active flag */
4236 LunExtension
->Flags
&= ~SCSI_PORT_LU_ACTIVE
;
4238 /* Set attempt counter to zero */
4239 LunExtension
->AttemptCount
= 0;
4241 /* Remove packet from the device queue */
4242 Entry
= KeRemoveByKeyDeviceQueue(&LunExtension
->DeviceQueue
, LunExtension
->SortKey
);
4246 /* Get pointer to the next irp */
4247 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
4249 /* Get point to the SRB */
4250 IrpStack
= IoGetCurrentIrpStackLocation(NextIrp
);
4251 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
4254 LunExtension
->SortKey
= Srb
->QueueSortKey
;
4255 LunExtension
->SortKey
++;
4257 /* Release the spinlock */
4258 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4260 /* Start the next pending request */
4261 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4265 /* Release the spinlock */
4266 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4272 // ScsiPortDpcForIsr
4279 // IN PDEVICE_OBJECT DpcDeviceObject
4281 // IN PVOID DpcContext
4284 ScsiPortDpcForIsr(IN PKDPC Dpc
,
4285 IN PDEVICE_OBJECT DpcDeviceObject
,
4287 IN PVOID DpcContext
)
4289 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DpcDeviceObject
->DeviceExtension
;
4290 SCSI_PORT_INTERRUPT_DATA InterruptData
;
4291 SCSI_PORT_SAVE_INTERRUPT Context
;
4292 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4293 BOOLEAN NeedToStartIo
;
4294 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
4296 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4297 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
4299 /* We need to acquire spinlock */
4300 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4304 /* Interrupt structure must be snapshotted, and only then analyzed */
4305 Context
.InterruptData
= &InterruptData
;
4306 Context
.DeviceExtension
= DeviceExtension
;
4308 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4309 SpiSaveInterruptData
,
4312 /* Nothing - just return (don't forget to release the spinlock */
4313 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4314 DPRINT("ScsiPortDpcForIsr() done\n");
4318 /* If flush of adapters is needed - do it */
4319 if (InterruptData
.Flags
& SCSI_PORT_FLUSH_ADAPTERS
)
4321 /* TODO: Implement */
4325 /* Check for IoMapTransfer */
4326 if (InterruptData
.Flags
& SCSI_PORT_MAP_TRANSFER
)
4328 /* TODO: Implement */
4332 /* Check if timer is needed */
4333 if (InterruptData
.Flags
& SCIS_PORT_TIMER_NEEDED
)
4335 /* TODO: Implement */
4339 /* If it's ready for the next request */
4340 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4342 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4343 if ((DeviceExtension
->Flags
&
4344 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
)) ==
4345 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
))
4347 /* Clear busy flag set by ScsiPortStartPacket() */
4348 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4350 if (!(InterruptData
.Flags
& SCSI_PORT_RESET
))
4352 /* Ready for next, and no reset is happening */
4353 DeviceExtension
->TimerCount
= -1;
4358 /* Not busy, but not ready for the next request */
4359 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4360 InterruptData
.Flags
&= ~SCSI_PORT_NEXT_REQUEST_READY
;
4365 if (InterruptData
.Flags
& SCSI_PORT_RESET_REPORTED
)
4367 /* Hold for a bit */
4368 DeviceExtension
->TimerCount
= 4;
4371 /* Any ready LUN? */
4372 if (InterruptData
.ReadyLun
!= NULL
)
4375 /* Process all LUNs from the list*/
4378 /* Remove it from the list first (as processed) */
4379 LunExtension
= InterruptData
.ReadyLun
;
4380 InterruptData
.ReadyLun
= LunExtension
->ReadyLun
;
4381 LunExtension
->ReadyLun
= NULL
;
4383 /* Get next request for this LUN */
4384 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4386 /* Still ready requests exist?
4387 If yes - get spinlock, if no - stop here */
4388 if (InterruptData
.ReadyLun
!= NULL
)
4389 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4396 /* Release the spinlock */
4397 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4400 /* If we ready for next packet, start it */
4401 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4402 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4404 NeedToStartIo
= FALSE
;
4406 /* Loop the completed request list */
4407 while (InterruptData
.CompletedRequests
)
4409 /* Remove the request */
4410 SrbInfo
= InterruptData
.CompletedRequests
;
4411 InterruptData
.CompletedRequests
= SrbInfo
->CompletedRequests
;
4412 SrbInfo
->CompletedRequests
= NULL
;
4415 SpiProcessCompletedRequest(DeviceExtension
,
4420 /* Loop abort request list */
4421 while (InterruptData
.CompletedAbort
)
4423 LunExtension
= InterruptData
.CompletedAbort
;
4425 /* Remove the request */
4426 InterruptData
.CompletedAbort
= LunExtension
->CompletedAbortRequests
;
4428 /* Get spinlock since we're going to change flags */
4429 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4431 /* TODO: Put SrbExtension to the list of free extensions */
4435 /* If we need - call StartIo routine */
4438 /* Make sure CurrentIrp is not null! */
4439 ASSERT(DpcDeviceObject
->CurrentIrp
!= NULL
);
4440 ScsiPortStartIo(DpcDeviceObject
, DpcDeviceObject
->CurrentIrp
);
4443 /* Everything has been done, check */
4444 if (InterruptData
.Flags
& SCSI_PORT_ENABLE_INT_REQUEST
)
4446 /* Synchronize using spinlock */
4447 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4449 /* Request an interrupt */
4450 DeviceExtension
->HwInterrupt(DeviceExtension
->MiniPortDeviceExtension
);
4452 ASSERT(DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
);
4454 /* Should interrupts be enabled again? */
4455 if (DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
)
4457 /* Clear this flag */
4458 DeviceExtension
->Flags
&= ~SCSI_PORT_DISABLE_INT_REQUESET
;
4460 /* Call a special routine to do this */
4463 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4464 SpiEnableInterrupts
,
4469 /* If we need a notification again - loop */
4470 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4473 /* Release the spinlock */
4474 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4477 DPRINT("ScsiPortDpcForIsr() done\n");
4482 SpiProcessTimeout(PVOID ServiceContext
)
4484 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
4485 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
4488 DPRINT("SpiProcessTimeout() entered\n");
4490 DeviceExtension
->TimerCount
= -1;
4492 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
4494 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET
;
4496 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET_REQUEST
)
4498 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET_REQUEST
;
4499 ScsiPortStartPacket(ServiceContext
);
4506 DPRINT("Resetting the bus\n");
4508 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
4510 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
, Bus
);
4512 /* Reset flags and set reset timeout to 4 seconds */
4513 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
4514 DeviceExtension
->TimerCount
= 4;
4517 /* If miniport requested - request a dpc for it */
4518 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4519 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
4528 SpiResetBus(PVOID ServiceContext
)
4530 PRESETBUS_PARAMS ResetParams
= (PRESETBUS_PARAMS
)ServiceContext
;
4531 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4533 /* Perform the bus reset */
4534 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ResetParams
->DeviceExtension
;
4535 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
,
4536 ResetParams
->PathId
);
4538 /* Set flags and start the timer */
4539 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
4540 DeviceExtension
->TimerCount
= 4;
4542 /* If miniport requested - give him a DPC */
4543 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4544 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
4551 // This function handles timeouts and other time delayed processing
4556 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
4557 // IN PVOID Context the Controller extension for the
4558 // controller the device is on
4561 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
4564 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4565 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4569 DPRINT("ScsiPortIoTimer()\n");
4571 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
4573 /* Protect with the spinlock */
4574 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4576 /* Check timeouts */
4577 if (DeviceExtension
->TimerCount
> 0)
4579 /* Decrease the timeout counter */
4580 DeviceExtension
->TimerCount
--;
4582 if (DeviceExtension
->TimerCount
== 0)
4584 /* Timeout, process it */
4585 if (KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4587 DeviceExtension
->DeviceObject
))
4589 DPRINT("Error happened during processing timeout, but nothing critical\n");
4593 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4595 /* We should exit now, since timeout is processed */
4599 /* Per-Lun scanning of timeouts is needed... */
4600 for (Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
4602 LunExtension
= DeviceExtension
->LunExtensionList
[Lun
];
4604 while (LunExtension
)
4606 if (LunExtension
->Flags
& LUNEX_BUSY
)
4608 if (!(LunExtension
->Flags
&
4609 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_FROZEN_QUEUE
)))
4611 DPRINT("Retrying busy request\n");
4613 /* Clear flags, and retry busy request */
4614 LunExtension
->Flags
&= ~(LUNEX_BUSY
| LUNEX_FULL_QUEUE
);
4615 Irp
= LunExtension
->BusyRequest
;
4617 /* Clearing busy request */
4618 LunExtension
->BusyRequest
= NULL
;
4620 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4622 IoStartPacket(DeviceObject
, Irp
, (PULONG
)NULL
, NULL
);
4624 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4627 else if (LunExtension
->RequestTimeout
== 0)
4629 RESETBUS_PARAMS ResetParams
;
4631 LunExtension
->RequestTimeout
= -1;
4633 DPRINT("Request timed out, resetting bus\n");
4635 /* Pass params to the bus reset routine */
4636 ResetParams
.PathId
= LunExtension
->PathId
;
4637 ResetParams
.DeviceExtension
= DeviceExtension
;
4639 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4643 DPRINT1("Reset failed\n");
4646 else if (LunExtension
->RequestTimeout
> 0)
4648 /* Decrement the timeout counter */
4649 LunExtension
->RequestTimeout
--;
4652 LunExtension
= LunExtension
->Next
;
4656 /* Release the spinlock */
4657 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4660 /**********************************************************************
4665 * Builds the registry device map of all device which are attached
4666 * to the given SCSI HBA port. The device map is located at:
4667 * \Registry\Machine\DeviceMap\Scsi
4677 * Name of registry driver service key.
4684 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4685 PUNICODE_STRING RegistryPath
)
4687 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4688 OBJECT_ATTRIBUTES ObjectAttributes
;
4689 UNICODE_STRING KeyName
;
4690 UNICODE_STRING ValueName
;
4691 WCHAR NameBuffer
[64];
4694 HANDLE ScsiPortKey
= NULL
;
4695 HANDLE ScsiBusKey
= NULL
;
4696 HANDLE ScsiInitiatorKey
= NULL
;
4697 HANDLE ScsiTargetKey
= NULL
;
4698 HANDLE ScsiLunKey
= NULL
;
4701 ULONG CurrentTarget
;
4708 DPRINT("SpiBuildDeviceMap() called\n");
4710 if (DeviceExtension
== NULL
|| RegistryPath
== NULL
)
4712 DPRINT1("Invalid parameter\n");
4713 return(STATUS_INVALID_PARAMETER
);
4716 /* Open or create the 'Scsi' subkey */
4717 RtlInitUnicodeString(&KeyName
,
4718 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
4719 InitializeObjectAttributes(&ObjectAttributes
,
4721 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
4724 Status
= ZwCreateKey(&ScsiKey
,
4729 REG_OPTION_VOLATILE
,
4731 if (!NT_SUCCESS(Status
))
4733 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4737 /* Create new 'Scsi Port X' subkey */
4738 DPRINT("Scsi Port %lu\n",
4739 DeviceExtension
->PortNumber
);
4741 swprintf(NameBuffer
,
4743 DeviceExtension
->PortNumber
);
4744 RtlInitUnicodeString(&KeyName
,
4746 InitializeObjectAttributes(&ObjectAttributes
,
4751 Status
= ZwCreateKey(&ScsiPortKey
,
4756 REG_OPTION_VOLATILE
,
4759 if (!NT_SUCCESS(Status
))
4761 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4766 * Create port-specific values
4769 /* Set 'DMA Enabled' (REG_DWORD) value */
4770 UlongData
= (ULONG
)!DeviceExtension
->PortCapabilities
.AdapterUsesPio
;
4771 DPRINT(" DMA Enabled = %s\n", (UlongData
) ? "TRUE" : "FALSE");
4772 RtlInitUnicodeString(&ValueName
,
4774 Status
= ZwSetValueKey(ScsiPortKey
,
4780 if (!NT_SUCCESS(Status
))
4782 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status
);
4783 ZwClose(ScsiPortKey
);
4787 /* Set 'Driver' (REG_SZ) value */
4788 DriverName
= wcsrchr(RegistryPath
->Buffer
, L
'\\') + 1;
4789 RtlInitUnicodeString(&ValueName
,
4791 Status
= ZwSetValueKey(ScsiPortKey
,
4796 (wcslen(DriverName
) + 1) * sizeof(WCHAR
));
4797 if (!NT_SUCCESS(Status
))
4799 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status
);
4800 ZwClose(ScsiPortKey
);
4804 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
4805 UlongData
= (ULONG
)DeviceExtension
->PortConfig
->BusInterruptLevel
;
4806 DPRINT(" Interrupt = %lu\n", UlongData
);
4807 RtlInitUnicodeString(&ValueName
,
4809 Status
= ZwSetValueKey(ScsiPortKey
,
4815 if (!NT_SUCCESS(Status
))
4817 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status
);
4818 ZwClose(ScsiPortKey
);
4822 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
4823 UlongData
= ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension
->PortConfig
->AccessRanges
)[0].RangeStart
);
4824 DPRINT(" IOAddress = %lx\n", UlongData
);
4825 RtlInitUnicodeString(&ValueName
,
4827 Status
= ZwSetValueKey(ScsiPortKey
,
4833 if (!NT_SUCCESS(Status
))
4835 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status
);
4836 ZwClose(ScsiPortKey
);
4840 /* Enumerate buses */
4841 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
->NumberOfBuses
; BusNumber
++)
4843 /* Create 'Scsi Bus X' key */
4844 DPRINT(" Scsi Bus %lu\n", BusNumber
);
4845 swprintf(NameBuffer
,
4848 RtlInitUnicodeString(&KeyName
,
4850 InitializeObjectAttributes(&ObjectAttributes
,
4855 Status
= ZwCreateKey(&ScsiBusKey
,
4860 REG_OPTION_VOLATILE
,
4862 if (!NT_SUCCESS(Status
))
4864 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4868 /* Create 'Initiator Id X' key */
4869 DPRINT(" Initiator Id %u\n",
4870 DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
4871 swprintf(NameBuffer
,
4873 (unsigned int)(UCHAR
)DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
4874 RtlInitUnicodeString(&KeyName
,
4876 InitializeObjectAttributes(&ObjectAttributes
,
4881 Status
= ZwCreateKey(&ScsiInitiatorKey
,
4886 REG_OPTION_VOLATILE
,
4888 if (!NT_SUCCESS(Status
))
4890 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4894 /* FIXME: Are there any initiator values (??) */
4896 ZwClose(ScsiInitiatorKey
);
4897 ScsiInitiatorKey
= NULL
;
4900 /* Enumerate targets */
4901 CurrentTarget
= (ULONG
)-1;
4902 ScsiTargetKey
= NULL
;
4903 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
4905 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
4907 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4911 if (LunExtension
!= NULL
)
4913 if (Target
!= CurrentTarget
)
4915 /* Close old target key */
4916 if (ScsiTargetKey
!= NULL
)
4918 ZwClose(ScsiTargetKey
);
4919 ScsiTargetKey
= NULL
;
4922 /* Create 'Target Id X' key */
4923 DPRINT(" Target Id %lu\n", Target
);
4924 swprintf(NameBuffer
,
4927 RtlInitUnicodeString(&KeyName
,
4929 InitializeObjectAttributes(&ObjectAttributes
,
4934 Status
= ZwCreateKey(&ScsiTargetKey
,
4939 REG_OPTION_VOLATILE
,
4941 if (!NT_SUCCESS(Status
))
4943 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4947 CurrentTarget
= Target
;
4950 /* Create 'Logical Unit Id X' key */
4951 DPRINT(" Logical Unit Id %lu\n", Lun
);
4952 swprintf(NameBuffer
,
4953 L
"Logical Unit Id %lu",
4955 RtlInitUnicodeString(&KeyName
,
4957 InitializeObjectAttributes(&ObjectAttributes
,
4962 Status
= ZwCreateKey(&ScsiLunKey
,
4967 REG_OPTION_VOLATILE
,
4969 if (!NT_SUCCESS(Status
))
4971 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4975 /* Set 'Identifier' (REG_SZ) value */
4976 swprintf(NameBuffer
,
4978 LunExtension
->InquiryData
.VendorId
,
4979 LunExtension
->InquiryData
.ProductId
,
4980 LunExtension
->InquiryData
.ProductRevisionLevel
);
4981 DPRINT(" Identifier = '%S'\n", NameBuffer
);
4982 RtlInitUnicodeString(&ValueName
,
4984 Status
= ZwSetValueKey(ScsiLunKey
,
4989 (wcslen(NameBuffer
) + 1) * sizeof(WCHAR
));
4990 if (!NT_SUCCESS(Status
))
4992 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status
);
4996 /* Set 'Type' (REG_SZ) value */
4997 switch (LunExtension
->InquiryData
.DeviceType
)
5000 TypeName
= L
"DiskPeripheral";
5003 TypeName
= L
"TapePeripheral";
5006 TypeName
= L
"PrinterPeripheral";
5009 TypeName
= L
"WormPeripheral";
5012 TypeName
= L
"CdRomPeripheral";
5015 TypeName
= L
"ScannerPeripheral";
5018 TypeName
= L
"OpticalDiskPeripheral";
5021 TypeName
= L
"MediumChangerPeripheral";
5024 TypeName
= L
"CommunicationPeripheral";
5027 TypeName
= L
"OtherPeripheral";
5030 DPRINT(" Type = '%S'\n", TypeName
);
5031 RtlInitUnicodeString(&ValueName
,
5033 Status
= ZwSetValueKey(ScsiLunKey
,
5038 (wcslen(TypeName
) + 1) * sizeof(WCHAR
));
5039 if (!NT_SUCCESS(Status
))
5041 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status
);
5045 ZwClose(ScsiLunKey
);
5050 /* Close old target key */
5051 if (ScsiTargetKey
!= NULL
)
5053 ZwClose(ScsiTargetKey
);
5054 ScsiTargetKey
= NULL
;
5058 ZwClose(ScsiBusKey
);
5063 if (ScsiLunKey
!= NULL
)
5064 ZwClose (ScsiLunKey
);
5066 if (ScsiInitiatorKey
!= NULL
)
5067 ZwClose (ScsiInitiatorKey
);
5069 if (ScsiTargetKey
!= NULL
)
5070 ZwClose (ScsiTargetKey
);
5072 if (ScsiBusKey
!= NULL
)
5073 ZwClose (ScsiBusKey
);
5075 if (ScsiPortKey
!= NULL
)
5076 ZwClose (ScsiPortKey
);
5078 DPRINT("SpiBuildDeviceMap() done\n");
5085 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
5086 IN PVOID DeviceObject
,
5087 IN PVOID SystemArgument1
,
5088 IN PVOID SystemArgument2
)
5090 DPRINT1("Miniport timer DPC\n");
5094 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5095 PHW_INITIALIZATION_DATA HwInitData
,
5096 PCONFIGURATION_INFO InternalConfigInfo
,
5097 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5100 UNICODE_STRING UnicodeString
;
5101 OBJECT_ATTRIBUTES ObjectAttributes
;
5102 PCONFIGURATION_INFORMATION DdkConfigInformation
;
5103 HANDLE RootKey
, Key
;
5105 WCHAR DeviceBuffer
[16];
5106 WCHAR StrBuffer
[512];
5110 /* Zero out the struct if told so */
5113 /* First zero the portconfig */
5114 RtlZeroMemory(ConfigInfo
, sizeof(PORT_CONFIGURATION_INFORMATION
));
5116 /* Then access ranges */
5117 RtlZeroMemory(InternalConfigInfo
->AccessRanges
,
5118 HwInitData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
5120 /* Initialize the struct */
5121 ConfigInfo
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
5122 ConfigInfo
->AdapterInterfaceType
= HwInitData
->AdapterInterfaceType
;
5123 ConfigInfo
->InterruptMode
= Latched
;
5124 ConfigInfo
->DmaChannel
= SP_UNINITIALIZED_VALUE
;
5125 ConfigInfo
->DmaPort
= SP_UNINITIALIZED_VALUE
;
5126 ConfigInfo
->MaximumTransferLength
= SP_UNINITIALIZED_VALUE
;
5127 ConfigInfo
->NumberOfAccessRanges
= HwInitData
->NumberOfAccessRanges
;
5128 ConfigInfo
->MaximumNumberOfTargets
= 8;
5130 /* Store parameters */
5131 ConfigInfo
->NeedPhysicalAddresses
= HwInitData
->NeedPhysicalAddresses
;
5132 ConfigInfo
->MapBuffers
= HwInitData
->MapBuffers
;
5133 ConfigInfo
->AutoRequestSense
= HwInitData
->AutoRequestSense
;
5134 ConfigInfo
->ReceiveEvent
= HwInitData
->ReceiveEvent
;
5135 ConfigInfo
->TaggedQueuing
= HwInitData
->TaggedQueuing
;
5136 ConfigInfo
->MultipleRequestPerLu
= HwInitData
->MultipleRequestPerLu
;
5138 /* Get the disk usage */
5139 DdkConfigInformation
= IoGetConfigurationInformation();
5140 ConfigInfo
->AtdiskPrimaryClaimed
= DdkConfigInformation
->AtDiskPrimaryAddressClaimed
;
5141 ConfigInfo
->AtdiskSecondaryClaimed
= DdkConfigInformation
->AtDiskSecondaryAddressClaimed
;
5143 /* Initiator bus id is not set */
5144 for (Bus
= 0; Bus
< 8; Bus
++)
5145 ConfigInfo
->InitiatorBusId
[Bus
] = (CCHAR
)SP_UNINITIALIZED_VALUE
;
5148 ConfigInfo
->NumberOfPhysicalBreaks
= 17;
5150 /* Clear this information */
5151 InternalConfigInfo
->DisableTaggedQueueing
= FALSE
;
5152 InternalConfigInfo
->DisableMultipleLun
= FALSE
;
5154 /* Store Bus Number */
5155 ConfigInfo
->SystemIoBusNumber
= InternalConfigInfo
->BusNumber
;
5159 if (ConfigInfo
->AdapterInterfaceType
== Internal
)
5161 /* Open registry key for HW database */
5162 InitializeObjectAttributes(&ObjectAttributes
,
5163 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
5164 OBJ_CASE_INSENSITIVE
,
5168 Status
= ZwOpenKey(&RootKey
,
5172 if (NT_SUCCESS(Status
))
5174 /* Create name for it */
5175 swprintf(StrBuffer
, L
"ScsiAdapter\\%lu",
5176 InternalConfigInfo
->AdapterNumber
);
5178 RtlInitUnicodeString(&UnicodeString
, StrBuffer
);
5180 /* Open device key */
5181 InitializeObjectAttributes(&ObjectAttributes
,
5183 OBJ_CASE_INSENSITIVE
,
5187 Status
= ZwOpenKey(&Key
,
5193 if (NT_SUCCESS(Status
))
5195 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5197 DPRINT("Hardware info found at %S\n", StrBuffer
);
5200 SpiParseDeviceInfo(DeviceExtension
,
5206 InternalConfigInfo
->BusNumber
= 0;
5210 /* Try the next adapter */
5211 InternalConfigInfo
->AdapterNumber
++;
5217 /* Info was not found, exit */
5218 return STATUS_DEVICE_DOES_NOT_EXIST
;
5224 /* Look at device params */
5226 if (InternalConfigInfo
->Parameter
)
5228 ExFreePool(InternalConfigInfo
->Parameter
);
5229 InternalConfigInfo
->Parameter
= NULL
;
5232 if (InternalConfigInfo
->ServiceKey
!= NULL
)
5234 swprintf(DeviceBuffer
, L
"Device%lu", InternalConfigInfo
->AdapterNumber
);
5235 RtlInitUnicodeString(&UnicodeString
, DeviceBuffer
);
5237 /* Open the service key */
5238 InitializeObjectAttributes(&ObjectAttributes
,
5240 OBJ_CASE_INSENSITIVE
,
5241 InternalConfigInfo
->ServiceKey
,
5244 Status
= ZwOpenKey(&Key
,
5249 /* Parse device key */
5250 if (InternalConfigInfo
->DeviceKey
!= NULL
)
5252 SpiParseDeviceInfo(DeviceExtension
,
5253 InternalConfigInfo
->DeviceKey
,
5259 /* Then parse hw info */
5262 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5264 SpiParseDeviceInfo(DeviceExtension
,
5275 /* Adapter not found, go try the next one */
5276 InternalConfigInfo
->AdapterNumber
++;
5285 /* Update the last adapter number */
5286 InternalConfigInfo
->LastAdapterNumber
= InternalConfigInfo
->AdapterNumber
;
5288 /* Do we have this kind of bus at all? */
5290 Status
= IoQueryDeviceDescription(&HwInitData
->AdapterInterfaceType
,
5291 &InternalConfigInfo
->BusNumber
,
5296 SpQueryDeviceCallout
,
5299 /* This bus was not found */
5302 INTERFACE_TYPE InterfaceType
= Eisa
;
5304 /* Check for EISA */
5305 if (HwInitData
->AdapterInterfaceType
== Isa
)
5307 Status
= IoQueryDeviceDescription(&InterfaceType
,
5308 &InternalConfigInfo
->BusNumber
,
5313 SpQueryDeviceCallout
,
5316 /* Return respectively */
5318 return STATUS_SUCCESS
;
5320 return STATUS_DEVICE_DOES_NOT_EXIST
;
5324 return STATUS_DEVICE_DOES_NOT_EXIST
;
5329 return STATUS_SUCCESS
;
5334 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5336 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5337 IN PCONFIGURATION_INFO InternalConfigInfo
,
5340 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
5341 PCM_FULL_RESOURCE_DESCRIPTOR FullResource
;
5342 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
5343 PCM_SCSI_DEVICE_DATA ScsiDeviceData
;
5344 ULONG Length
, Count
;
5345 ULONG Index
= 0, RangeCount
= 0;
5346 UNICODE_STRING UnicodeString
;
5347 ANSI_STRING AnsiString
;
5348 NTSTATUS Status
= STATUS_SUCCESS
;
5351 KeyValueInformation
= (PKEY_VALUE_FULL_INFORMATION
) Buffer
;
5353 /* Loop through all values in the device node */
5356 Status
= ZwEnumerateValueKey(Key
,
5358 KeyValueFullInformation
,
5363 if (!NT_SUCCESS(Status
))
5368 /* Length for DWORD is ok? */
5369 if (KeyValueInformation
->Type
== REG_DWORD
&&
5370 KeyValueInformation
->DataLength
!= sizeof(ULONG
))
5375 /* Get MaximumLogicalUnit */
5376 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumLogicalUnit",
5377 KeyValueInformation
->NameLength
/2) == 0)
5380 if (KeyValueInformation
->Type
!= REG_DWORD
)
5382 DPRINT("Bad data type for MaximumLogicalUnit\n");
5386 DeviceExtension
->MaxLunCount
= *((PUCHAR
)
5387 (Buffer
+ KeyValueInformation
->DataOffset
));
5389 /* Check / reset if needed */
5390 if (DeviceExtension
->MaxLunCount
> SCSI_MAXIMUM_LOGICAL_UNITS
)
5391 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
5393 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension
->MaxLunCount
);
5396 /* Get InitiatorTargetId */
5397 if (_wcsnicmp(KeyValueInformation
->Name
, L
"InitiatorTargetId",
5398 KeyValueInformation
->NameLength
/ 2) == 0)
5401 if (KeyValueInformation
->Type
!= REG_DWORD
)
5403 DPRINT("Bad data type for InitiatorTargetId\n");
5407 ConfigInfo
->InitiatorBusId
[0] = *((PUCHAR
)
5408 (Buffer
+ KeyValueInformation
->DataOffset
));
5410 /* Check / reset if needed */
5411 if (ConfigInfo
->InitiatorBusId
[0] > ConfigInfo
->MaximumNumberOfTargets
- 1)
5412 ConfigInfo
->InitiatorBusId
[0] = (CCHAR
)-1;
5414 DPRINT("InitiatorTargetId = %d\n", ConfigInfo
->InitiatorBusId
[0]);
5418 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ScsiDebug",
5419 KeyValueInformation
->NameLength
/2) == 0)
5421 DPRINT("ScsiDebug key not supported\n");
5424 /* Check for a breakpoint */
5425 if (_wcsnicmp(KeyValueInformation
->Name
, L
"BreakPointOnEntry",
5426 KeyValueInformation
->NameLength
/2) == 0)
5428 DPRINT1("Breakpoint on entry requested!\n");
5432 /* Get DisableSynchronousTransfers */
5433 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableSynchronousTransfers",
5434 KeyValueInformation
->NameLength
/2) == 0)
5436 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5437 DPRINT("Synch transfers disabled\n");
5440 /* Get DisableDisconnects */
5441 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableDisconnects",
5442 KeyValueInformation
->NameLength
/2) == 0)
5444 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
5445 DPRINT("Disconnects disabled\n");
5448 /* Get DisableTaggedQueuing */
5449 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableTaggedQueuing",
5450 KeyValueInformation
->NameLength
/2) == 0)
5452 InternalConfigInfo
->DisableTaggedQueueing
= TRUE
;
5453 DPRINT("Tagged queueing disabled\n");
5456 /* Get DisableMultipleRequests */
5457 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableMultipleRequests",
5458 KeyValueInformation
->NameLength
/2) == 0)
5460 InternalConfigInfo
->DisableMultipleLun
= TRUE
;
5461 DPRINT("Multiple requests disabled\n");
5464 /* Get DriverParameters */
5465 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DriverParameters",
5466 KeyValueInformation
->NameLength
/2) == 0)
5468 /* Skip if nothing */
5469 if (KeyValueInformation
->DataLength
== 0)
5472 /* If there was something previously allocated - free it */
5473 if (InternalConfigInfo
->Parameter
!= NULL
)
5474 ExFreePool(InternalConfigInfo
->Parameter
);
5477 InternalConfigInfo
->Parameter
= ExAllocatePool(NonPagedPool
,
5478 KeyValueInformation
->DataLength
);
5480 if (InternalConfigInfo
->Parameter
!= NULL
)
5482 if (KeyValueInformation
->Type
!= REG_SZ
)
5486 InternalConfigInfo
->Parameter
,
5487 (PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
,
5488 KeyValueInformation
->DataLength
);
5492 /* If it's a unicode string, convert it to ansi */
5493 UnicodeString
.Length
= (USHORT
)KeyValueInformation
->DataLength
;
5494 UnicodeString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
5495 UnicodeString
.Buffer
=
5496 (PWSTR
)((PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
5498 AnsiString
.Length
= 0;
5499 AnsiString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
5500 AnsiString
.Buffer
= (PCHAR
)InternalConfigInfo
->Parameter
;
5502 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
5506 /* In case of error, free the allocated space */
5507 if (!NT_SUCCESS(Status
))
5509 ExFreePool(InternalConfigInfo
->Parameter
);
5510 InternalConfigInfo
->Parameter
= NULL
;
5516 DPRINT("Found driver parameter\n");
5519 /* Get MaximumSGList */
5520 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumSGList",
5521 KeyValueInformation
->NameLength
/2) == 0)
5523 if (KeyValueInformation
->Type
!= REG_DWORD
)
5525 DPRINT("Bad data type for MaximumSGList\n");
5529 ConfigInfo
->NumberOfPhysicalBreaks
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
5532 if (ConfigInfo
->NumberOfPhysicalBreaks
> SCSI_MAXIMUM_PHYSICAL_BREAKS
)
5534 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MAXIMUM_PHYSICAL_BREAKS
;
5536 else if (ConfigInfo
->NumberOfPhysicalBreaks
< SCSI_MINIMUM_PHYSICAL_BREAKS
)
5538 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MINIMUM_PHYSICAL_BREAKS
;
5541 DPRINT("MaximumSGList = %d\n", ConfigInfo
->NumberOfPhysicalBreaks
);
5544 /* Get NumberOfRequests */
5545 if (_wcsnicmp(KeyValueInformation
->Name
, L
"NumberOfRequests",
5546 KeyValueInformation
->NameLength
/2) == 0)
5548 if (KeyValueInformation
->Type
!= REG_DWORD
)
5550 DPRINT("NumberOfRequests has wrong data type\n");
5554 DeviceExtension
->RequestsNumber
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
5557 if (DeviceExtension
->RequestsNumber
< 16)
5559 DeviceExtension
->RequestsNumber
= 16;
5561 else if (DeviceExtension
->RequestsNumber
> 512)
5563 DeviceExtension
->RequestsNumber
= 512;
5566 DPRINT("Number Of Requests = %d\n", DeviceExtension
->RequestsNumber
);
5569 /* Get resource list */
5570 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ResourceList",
5571 KeyValueInformation
->NameLength
/2) == 0 ||
5572 _wcsnicmp(KeyValueInformation
->Name
, L
"Configuration Data",
5573 KeyValueInformation
->NameLength
/2) == 0 )
5575 if (KeyValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
||
5576 KeyValueInformation
->DataLength
< sizeof(REG_FULL_RESOURCE_DESCRIPTOR
))
5578 DPRINT("Bad data type for ResourceList\n");
5583 DPRINT("Found ResourceList\n");
5586 FullResource
= (PCM_FULL_RESOURCE_DESCRIPTOR
)(Buffer
+ KeyValueInformation
->DataOffset
);
5588 /* Copy some info from it */
5589 InternalConfigInfo
->BusNumber
= FullResource
->BusNumber
;
5590 ConfigInfo
->SystemIoBusNumber
= FullResource
->BusNumber
;
5592 /* Loop through it */
5593 for (Count
= 0; Count
< FullResource
->PartialResourceList
.Count
; Count
++)
5595 /* Get partial descriptor */
5597 &FullResource
->PartialResourceList
.PartialDescriptors
[Count
];
5599 /* Check datalength */
5600 if ((ULONG
)((PCHAR
)(PartialDescriptor
+ 1) -
5601 (PCHAR
)FullResource
) > KeyValueInformation
->DataLength
)
5603 DPRINT("Resource data is of incorrect size\n");
5607 switch (PartialDescriptor
->Type
)
5609 case CmResourceTypePort
:
5610 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
5612 DPRINT("Too many access ranges\n");
5616 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= FALSE
;
5617 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Port
.Start
;
5618 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Port
.Length
;
5623 case CmResourceTypeMemory
:
5624 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
5626 DPRINT("Too many access ranges\n");
5630 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= TRUE
;
5631 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Memory
.Start
;
5632 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Memory
.Length
;
5637 case CmResourceTypeInterrupt
:
5638 ConfigInfo
->BusInterruptLevel
=
5639 PartialDescriptor
->u
.Interrupt
.Level
;
5641 ConfigInfo
->BusInterruptVector
=
5642 PartialDescriptor
->u
.Interrupt
.Vector
;
5645 case CmResourceTypeDma
:
5646 ConfigInfo
->DmaChannel
= PartialDescriptor
->u
.Dma
.Channel
;
5647 ConfigInfo
->DmaPort
= PartialDescriptor
->u
.Dma
.Port
;
5650 case CmResourceTypeDeviceSpecific
:
5651 if (PartialDescriptor
->u
.DeviceSpecificData
.DataSize
<
5652 sizeof(CM_SCSI_DEVICE_DATA
) ||
5653 (PCHAR
) (PartialDescriptor
+ 1) - (PCHAR
)FullResource
+
5654 PartialDescriptor
->u
.DeviceSpecificData
.DataSize
>
5655 KeyValueInformation
->DataLength
)
5657 DPRINT("Resource data length is incorrect");
5661 /* Set only one field from it */
5662 ScsiDeviceData
= (PCM_SCSI_DEVICE_DATA
) (PartialDescriptor
+1);
5663 ConfigInfo
->InitiatorBusId
[0] = ScsiDeviceData
->HostIdentifier
;
5674 SpQueryDeviceCallout(IN PVOID Context
,
5675 IN PUNICODE_STRING PathName
,
5676 IN INTERFACE_TYPE BusType
,
5678 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
5679 IN CONFIGURATION_TYPE ControllerType
,
5680 IN ULONG ControllerNumber
,
5681 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
5682 IN CONFIGURATION_TYPE PeripheralType
,
5683 IN ULONG PeripheralNumber
,
5684 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
5686 PBOOLEAN Found
= (PBOOLEAN
)Context
;
5687 /* We just set our Found variable to TRUE */
5690 return STATUS_SUCCESS
;
5697 SpiStatusSrbToNt(UCHAR SrbStatus
)
5699 switch (SRB_STATUS(SrbStatus
))
5701 case SRB_STATUS_TIMEOUT
:
5702 case SRB_STATUS_COMMAND_TIMEOUT
:
5703 return STATUS_IO_TIMEOUT
;
5705 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH
:
5706 case SRB_STATUS_BAD_FUNCTION
:
5707 return STATUS_INVALID_DEVICE_REQUEST
;
5709 case SRB_STATUS_NO_DEVICE
:
5710 case SRB_STATUS_INVALID_LUN
:
5711 case SRB_STATUS_INVALID_TARGET_ID
:
5712 case SRB_STATUS_NO_HBA
:
5713 return STATUS_DEVICE_DOES_NOT_EXIST
;
5715 case SRB_STATUS_DATA_OVERRUN
:
5716 return STATUS_BUFFER_OVERFLOW
;
5718 case SRB_STATUS_SELECTION_TIMEOUT
:
5719 return STATUS_DEVICE_NOT_CONNECTED
;
5722 return STATUS_IO_DEVICE_ERROR
;
5725 return STATUS_IO_DEVICE_ERROR
;
5729 #undef ScsiPortConvertPhysicalAddressToUlong
5734 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
5736 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
5737 return(Address
.u
.LowPart
);