3 * Copyright (C) 2001, 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS Storage Stack
23 * FILE: drivers/storage/scsiport/scsiport.c
24 * PURPOSE: SCSI port driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
26 * Aleksey Bragin (aleksey reactos org)
29 /* INCLUDES *****************************************************************/
45 #include "scsiport_int.h"
52 ULONG InternalDebugLevel
= 0x00;
54 /* TYPES *********************************************************************/
56 /* GLOBALS *******************************************************************/
59 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
60 IN PDEVICE_OBJECT DeviceObject
,
61 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
62 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
63 IN PUNICODE_STRING RegistryPath
,
65 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
);
67 static NTSTATUS STDCALL
68 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
71 static DRIVER_DISPATCH ScsiPortDispatchScsi
;
72 static NTSTATUS STDCALL
73 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
76 static NTSTATUS STDCALL
77 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
80 static DRIVER_STARTIO ScsiPortStartIo
;
82 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
85 static BOOLEAN STDCALL
86 ScsiPortStartPacket(IN OUT PVOID Context
);
90 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
91 PVOID MapRegisterBase
, PVOID Context
);
93 static PSCSI_PORT_LUN_EXTENSION
94 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
96 static PSCSI_PORT_LUN_EXTENSION
97 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
102 static PSCSI_REQUEST_BLOCK_INFO
103 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
104 PSCSI_PORT_LUN_EXTENSION LunExtension
,
105 PSCSI_REQUEST_BLOCK Srb
);
108 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
109 IN PSCSI_LUN_INFO LunInfo
);
112 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
115 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
118 static PSCSI_REQUEST_BLOCK_INFO
119 SpiGetSrbData(IN PVOID DeviceExtension
,
125 static KSERVICE_ROUTINE ScsiPortIsr
;
126 static BOOLEAN STDCALL
127 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
128 IN PVOID ServiceContext
);
131 ScsiPortDpcForIsr(IN PKDPC Dpc
,
132 IN PDEVICE_OBJECT DpcDeviceObject
,
134 IN PVOID DpcContext
);
137 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
141 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
142 PUNICODE_STRING RegistryPath
);
145 SpiStatusSrbToNt(UCHAR SrbStatus
);
148 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
149 IN PSCSI_REQUEST_BLOCK Srb
);
151 static IO_COMPLETION_ROUTINE SpiCompletionRoutine
;
153 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
159 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
160 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
161 OUT PBOOLEAN NeedToCallStartIo
);
164 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
165 IN PSCSI_PORT_LUN_EXTENSION LunExtension
);
168 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
169 IN PVOID DeviceObject
,
170 IN PVOID SystemArgument1
,
171 IN PVOID SystemArgument2
);
174 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
175 PHW_INITIALIZATION_DATA HwInitData
,
176 PCONFIGURATION_INFO InternalConfigInfo
,
177 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
181 SpQueryDeviceCallout(IN PVOID Context
,
182 IN PUNICODE_STRING PathName
,
183 IN INTERFACE_TYPE BusType
,
185 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
186 IN CONFIGURATION_TYPE ControllerType
,
187 IN ULONG ControllerNumber
,
188 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
189 IN CONFIGURATION_TYPE PeripheralType
,
190 IN ULONG PeripheralNumber
,
191 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
);
194 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
196 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
197 IN PCONFIGURATION_INFO InternalConfigInfo
,
201 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
202 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
203 IN PPORT_CONFIGURATION_INFORMATION PortConfig
);
205 static PCM_RESOURCE_LIST
206 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
207 PPORT_CONFIGURATION_INFORMATION PortConfig
);
210 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
213 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
217 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
);
221 /* FUNCTIONS *****************************************************************/
223 /**********************************************************************
228 * This function initializes the driver.
235 * System allocated Driver Object for this driver.
238 * Name of registry driver service key.
245 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
246 IN PUNICODE_STRING RegistryPath
)
248 DPRINT("ScsiPort Driver %s\n", VERSION
);
249 return(STATUS_SUCCESS
);
253 /**********************************************************************
258 * Prints debugging messages.
265 * Debug level of the given message.
268 * Pointer to printf()-compatible format string.
271 Additional output data (see printf()).
280 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
281 IN PCHAR DebugMessage
,
287 if (DebugPrintLevel
> InternalDebugLevel
)
290 va_start(ap
, DebugMessage
);
291 vsprintf(Buffer
, DebugMessage
, ap
);
302 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
308 DPRINT("ScsiPortCompleteRequest()\n");
316 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
318 DPRINT("ScsiPortFlushDma()\n");
327 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
328 IN PVOID MappedAddress
)
330 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
331 PMAPPED_ADDRESS NextMa
, LastMa
;
333 //DPRINT("ScsiPortFreeDeviceBase() called\n");
335 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
336 SCSI_PORT_DEVICE_EXTENSION
,
337 MiniPortDeviceExtension
);
340 /* Initialize our pointers */
341 NextMa
= DeviceExtension
->MappedAddressList
;
346 if (NextMa
->MappedAddress
== MappedAddress
)
349 MmUnmapIoSpace(MappedAddress
, NextMa
->NumberOfBytes
);
351 /* Remove it from the list */
352 if (NextMa
== DeviceExtension
->MappedAddressList
)
354 /* Remove the first entry */
355 DeviceExtension
->MappedAddressList
= NextMa
->NextMappedAddress
;
359 LastMa
->NextMappedAddress
= NextMa
->NextMappedAddress
;
362 /* Free the resources and quit */
370 NextMa
= NextMa
->NextMappedAddress
;
380 ScsiPortGetBusData(IN PVOID DeviceExtension
,
381 IN ULONG BusDataType
,
382 IN ULONG SystemIoBusNumber
,
387 return(HalGetBusData(BusDataType
,
399 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
400 IN INTERFACE_TYPE BusType
,
401 IN ULONG SystemIoBusNumber
,
402 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
403 IN ULONG NumberOfBytes
,
404 IN BOOLEAN InIoSpace
)
406 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
407 PHYSICAL_ADDRESS TranslatedAddress
;
408 PMAPPED_ADDRESS DeviceBase
;
412 //DPRINT ("ScsiPortGetDeviceBase() called\n");
414 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
415 SCSI_PORT_DEVICE_EXTENSION
,
416 MiniPortDeviceExtension
);
418 AddressSpace
= (ULONG
)InIoSpace
;
419 if (HalTranslateBusAddress(BusType
,
423 &TranslatedAddress
) == FALSE
)
429 if (AddressSpace
!= 0)
430 return((PVOID
)TranslatedAddress
.u
.LowPart
);
432 MappedAddress
= MmMapIoSpace(TranslatedAddress
,
436 DeviceBase
= ExAllocatePoolWithTag(NonPagedPool
,
437 sizeof(MAPPED_ADDRESS
), TAG_SCSIPORT
);
439 if (DeviceBase
== NULL
)
440 return MappedAddress
;
442 DeviceBase
->MappedAddress
= MappedAddress
;
443 DeviceBase
->NumberOfBytes
= NumberOfBytes
;
444 DeviceBase
->IoAddress
= IoAddress
;
445 DeviceBase
->BusNumber
= SystemIoBusNumber
;
447 /* Link it to the Device Extension list */
448 DeviceBase
->NextMappedAddress
= DeviceExtension
->MappedAddressList
;
449 DeviceExtension
->MappedAddressList
= DeviceBase
;
451 return MappedAddress
;
458 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
465 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
466 PSCSI_PORT_LUN_EXTENSION LunExtension
;
469 DPRINT("ScsiPortGetLogicalUnit() called\n");
471 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
472 SCSI_PORT_DEVICE_EXTENSION
,
473 MiniPortDeviceExtension
);
474 if (IsListEmpty(&DeviceExtension
->LunExtensionListHead
))
477 Entry
= DeviceExtension
->LunExtensionListHead
.Flink
;
478 while (Entry
!= &DeviceExtension
->LunExtensionListHead
)
480 LunExtension
= CONTAINING_RECORD(Entry
,
481 SCSI_PORT_LUN_EXTENSION
,
483 if (LunExtension
->PathId
== PathId
&&
484 LunExtension
->TargetId
== TargetId
&&
485 LunExtension
->Lun
== Lun
)
487 return (PVOID
)&LunExtension
->MiniportLunExtension
;
490 Entry
= Entry
->Flink
;
500 SCSI_PHYSICAL_ADDRESS STDCALL
501 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
502 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
503 IN PVOID VirtualAddress
,
506 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
507 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
508 ULONG BufferLength
= 0;
510 PSCSI_SG_ADDRESS SGList
;
511 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
513 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
514 HwDeviceExtension
, Srb
, VirtualAddress
, Length
);
516 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
517 SCSI_PORT_DEVICE_EXTENSION
,
518 MiniPortDeviceExtension
);
520 if (Srb
== NULL
|| Srb
->SenseInfoBuffer
== VirtualAddress
)
522 /* Simply look it up in the allocated common buffer */
523 Offset
= (PUCHAR
)VirtualAddress
- (PUCHAR
)DeviceExtension
->SrbExtensionBuffer
;
525 BufferLength
= DeviceExtension
->CommonBufferLength
- Offset
;
526 PhysicalAddress
.QuadPart
= DeviceExtension
->PhysicalAddress
.QuadPart
+ Offset
;
528 else if (DeviceExtension
->MapRegisters
)
530 /* Scatter-gather list must be used */
531 SrbInfo
= SpiGetSrbData(DeviceExtension
,
537 SGList
= SrbInfo
->ScatterGather
;
539 /* Find needed item in the SG list */
540 Offset
= (PCHAR
)VirtualAddress
- (PCHAR
)Srb
->DataBuffer
;
541 while (Offset
>= SGList
->Length
)
543 Offset
-= SGList
->Length
;
547 /* We're done, store length and physical address */
548 BufferLength
= SGList
->Length
- Offset
;
549 PhysicalAddress
.QuadPart
= SGList
->PhysicalAddress
.QuadPart
+ Offset
;
555 PhysicalAddress
.QuadPart
= (LONGLONG
)(SP_UNINITIALIZED_VALUE
);
558 *Length
= BufferLength
;
559 return PhysicalAddress
;
566 PSCSI_REQUEST_BLOCK STDCALL
567 ScsiPortGetSrb(IN PVOID DeviceExtension
,
573 DPRINT1("ScsiPortGetSrb() unimplemented\n");
583 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
584 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
585 IN ULONG NumberOfBytes
)
587 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
588 DEVICE_DESCRIPTION DeviceDescription
;
589 ULONG MapRegistersCount
;
592 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
593 HwDeviceExtension
, ConfigInfo
, NumberOfBytes
);
595 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
596 SCSI_PORT_DEVICE_EXTENSION
,
597 MiniPortDeviceExtension
);
599 /* Check for allocated common DMA buffer */
600 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
)
602 DPRINT1("The HBA has already got a common DMA buffer!\n");
606 /* Check for DMA adapter object */
607 if (DeviceExtension
->AdapterObject
== NULL
)
609 /* Initialize DMA adapter description */
610 RtlZeroMemory(&DeviceDescription
, sizeof(DEVICE_DESCRIPTION
));
612 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
613 DeviceDescription
.Master
= ConfigInfo
->Master
;
614 DeviceDescription
.ScatterGather
= ConfigInfo
->ScatterGather
;
615 DeviceDescription
.DemandMode
= ConfigInfo
->DemandMode
;
616 DeviceDescription
.Dma32BitAddresses
= ConfigInfo
->Dma32BitAddresses
;
617 DeviceDescription
.BusNumber
= ConfigInfo
->SystemIoBusNumber
;
618 DeviceDescription
.DmaChannel
= ConfigInfo
->DmaChannel
;
619 DeviceDescription
.InterfaceType
= ConfigInfo
->AdapterInterfaceType
;
620 DeviceDescription
.DmaWidth
= ConfigInfo
->DmaWidth
;
621 DeviceDescription
.DmaSpeed
= ConfigInfo
->DmaSpeed
;
622 DeviceDescription
.MaximumLength
= ConfigInfo
->MaximumTransferLength
;
623 DeviceDescription
.DmaPort
= ConfigInfo
->DmaPort
;
625 /* Get a DMA adapter object */
626 DeviceExtension
->AdapterObject
=
627 HalGetAdapter(&DeviceDescription
, &MapRegistersCount
);
629 /* Fail in case of error */
630 if (DeviceExtension
->AdapterObject
== NULL
)
632 DPRINT1("HalGetAdapter() failed\n");
636 /* Set number of physical breaks */
637 if (ConfigInfo
->NumberOfPhysicalBreaks
!= 0 &&
638 MapRegistersCount
> ConfigInfo
->NumberOfPhysicalBreaks
)
640 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
=
641 ConfigInfo
->NumberOfPhysicalBreaks
;
645 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
= MapRegistersCount
;
649 /* Update auto request sense feature */
650 DeviceExtension
->SupportsAutoSense
= ConfigInfo
->AutoRequestSense
;
652 /* Update Srb extension size */
653 if (DeviceExtension
->SrbExtensionSize
!= ConfigInfo
->SrbExtensionSize
)
654 DeviceExtension
->SrbExtensionSize
= ConfigInfo
->SrbExtensionSize
;
656 /* Update Srb extension alloc flag */
657 if (ConfigInfo
->AutoRequestSense
|| DeviceExtension
->SrbExtensionSize
)
658 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
660 /* Allocate a common DMA buffer */
661 Status
= SpiAllocateCommonBuffer(DeviceExtension
, NumberOfBytes
);
663 if (!NT_SUCCESS(Status
))
665 DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status
);
669 return DeviceExtension
->NonCachedExtension
;
673 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
)
675 PVOID
*SrbExtension
, CommonBuffer
;
676 ULONG CommonBufferLength
, BufSize
;
678 /* If size is 0, set it to 16 */
679 if (!DeviceExtension
->SrbExtensionSize
)
680 DeviceExtension
->SrbExtensionSize
= 16;
683 BufSize
= DeviceExtension
->SrbExtensionSize
;
685 /* Add autosense data size if needed */
686 if (DeviceExtension
->SupportsAutoSense
)
687 BufSize
+= sizeof(SENSE_DATA
);
691 BufSize
= (BufSize
+ sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
693 /* Sum up into the total common buffer length, and round it to page size */
695 ROUND_TO_PAGES(NonCachedSize
+ BufSize
* DeviceExtension
->RequestsNumber
);
698 if (!DeviceExtension
->AdapterObject
)
700 /* From nonpaged pool if there is no DMA */
701 CommonBuffer
= ExAllocatePoolWithTag(NonPagedPool
, CommonBufferLength
, TAG_SCSIPORT
);
705 /* Perform a full request since we have a DMA adapter*/
706 CommonBuffer
= HalAllocateCommonBuffer(DeviceExtension
->AdapterObject
,
708 &DeviceExtension
->PhysicalAddress
,
712 /* Fail in case of error */
714 return STATUS_INSUFFICIENT_RESOURCES
;
717 RtlZeroMemory(CommonBuffer
, CommonBufferLength
);
719 /* Store its size in Device Extension */
720 DeviceExtension
->CommonBufferLength
= CommonBufferLength
;
722 /* SrbExtension buffer is located at the beginning of the buffer */
723 DeviceExtension
->SrbExtensionBuffer
= CommonBuffer
;
725 /* Non-cached extension buffer is located at the end of
729 CommonBufferLength
-= NonCachedSize
;
730 DeviceExtension
->NonCachedExtension
= (PUCHAR
)CommonBuffer
+ CommonBufferLength
;
734 DeviceExtension
->NonCachedExtension
= NULL
;
737 if (DeviceExtension
->NeedSrbExtensionAlloc
)
739 /* Look up how many SRB data structures we need */
740 DeviceExtension
->SrbDataCount
= CommonBufferLength
/ BufSize
;
742 /* Initialize the free SRB extensions list */
743 SrbExtension
= (PVOID
*)CommonBuffer
;
744 DeviceExtension
->FreeSrbExtensions
= SrbExtension
;
746 /* Fill the remainding pointers (if we have more than 1 SRB) */
747 while (CommonBufferLength
>= 2 * BufSize
)
749 *SrbExtension
= (PVOID
*)((PCHAR
)SrbExtension
+ BufSize
);
750 SrbExtension
= *SrbExtension
;
752 CommonBufferLength
-= BufSize
;
756 return STATUS_SUCCESS
;
765 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
766 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
768 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
771 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
772 HwDeviceExtension
, PhysicalAddress
.QuadPart
);
774 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
775 SCSI_PORT_DEVICE_EXTENSION
,
776 MiniPortDeviceExtension
);
778 if (DeviceExtension
->PhysicalAddress
.QuadPart
> PhysicalAddress
.QuadPart
)
781 Offset
= (ULONG
)(PhysicalAddress
.QuadPart
- DeviceExtension
->PhysicalAddress
.QuadPart
);
783 if (Offset
>= DeviceExtension
->CommonBufferLength
)
786 return (PVOID
)((ULONG_PTR
)DeviceExtension
->SrbExtensionBuffer
+ Offset
);
790 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo
, PUNICODE_STRING RegistryPath
)
792 OBJECT_ATTRIBUTES ObjectAttributes
;
793 UNICODE_STRING KeyName
;
796 /* Open the service key */
797 InitializeObjectAttributes(&ObjectAttributes
,
799 OBJ_CASE_INSENSITIVE
,
803 Status
= ZwOpenKey(&ConfigInfo
->ServiceKey
,
807 if (!NT_SUCCESS(Status
))
809 DPRINT1("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath
, Status
);
810 ConfigInfo
->ServiceKey
= NULL
;
813 /* If we could open driver's service key, then proceed to the Parameters key */
814 if (ConfigInfo
->ServiceKey
!= NULL
)
816 RtlInitUnicodeString(&KeyName
, L
"Parameters");
817 InitializeObjectAttributes(&ObjectAttributes
,
819 OBJ_CASE_INSENSITIVE
,
820 ConfigInfo
->ServiceKey
,
821 (PSECURITY_DESCRIPTOR
) NULL
);
824 Status
= ZwOpenKey(&ConfigInfo
->DeviceKey
,
828 if (NT_SUCCESS(Status
))
830 /* Yes, Parameters key exist, and it must be used instead of
832 ZwClose(ConfigInfo
->ServiceKey
);
833 ConfigInfo
->ServiceKey
= ConfigInfo
->DeviceKey
;
834 ConfigInfo
->DeviceKey
= NULL
;
838 /* Open the Device key */
839 RtlInitUnicodeString(&KeyName
, L
"Device");
840 InitializeObjectAttributes(&ObjectAttributes
,
842 OBJ_CASE_INSENSITIVE
,
843 ConfigInfo
->ServiceKey
,
846 /* We don't check for failure here - not needed */
847 ZwOpenKey(&ConfigInfo
->DeviceKey
,
853 /**********************************************************************
858 * Initializes SCSI port driver specific data.
865 * Pointer to the miniport driver's driver object.
868 * Pointer to the miniport driver's registry path.
870 * HwInitializationData
871 * Pointer to port driver specific configuration data.
874 Miniport driver specific context.
883 ScsiPortInitialize(IN PVOID Argument1
,
885 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
888 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
889 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
890 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
891 PCONFIGURATION_INFORMATION SystemConfig
;
892 PPORT_CONFIGURATION_INFORMATION PortConfig
;
893 PORT_CONFIGURATION_INFORMATION InitialPortConfig
;
894 CONFIGURATION_INFO ConfigInfo
;
895 ULONG DeviceExtensionSize
;
896 ULONG PortConfigSize
;
898 BOOLEAN DeviceFound
= FALSE
;
899 BOOLEAN FirstConfigCall
= TRUE
;
904 PCI_SLOT_NUMBER SlotNumber
;
906 PDEVICE_OBJECT PortDeviceObject
;
907 WCHAR NameBuffer
[80];
908 UNICODE_STRING DeviceName
;
909 WCHAR DosNameBuffer
[80];
910 UNICODE_STRING DosDeviceName
;
911 PIO_SCSI_CAPABILITIES PortCapabilities
;
916 PCM_RESOURCE_LIST ResourceList
;
920 DPRINT ("ScsiPortInitialize() called!\n");
922 /* Check params for validity */
923 if ((HwInitializationData
->HwInitialize
== NULL
) ||
924 (HwInitializationData
->HwStartIo
== NULL
) ||
925 (HwInitializationData
->HwInterrupt
== NULL
) ||
926 (HwInitializationData
->HwFindAdapter
== NULL
) ||
927 (HwInitializationData
->HwResetBus
== NULL
))
929 return STATUS_INVALID_PARAMETER
;
933 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
934 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
935 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
936 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
937 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
938 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
940 /* Obtain configuration information */
941 SystemConfig
= IoGetConfigurationInformation();
943 /* Zero the internal configuration info structure */
944 RtlZeroMemory(&ConfigInfo
, sizeof(CONFIGURATION_INFO
));
946 /* Zero starting slot number */
947 SlotNumber
.u
.AsULONG
= 0;
949 /* Allocate space for access ranges */
950 if (HwInitializationData
->NumberOfAccessRanges
)
952 ConfigInfo
.AccessRanges
=
953 ExAllocatePoolWithTag(PagedPool
,
954 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
), TAG_SCSIPORT
);
957 if (ConfigInfo
.AccessRanges
== NULL
)
958 return STATUS_INSUFFICIENT_RESOURCES
;
961 /* Open registry keys */
962 SpiInitOpenKeys(&ConfigInfo
, (PUNICODE_STRING
)Argument2
);
964 /* Last adapter number = not known */
965 ConfigInfo
.LastAdapterNumber
= SP_UNINITIALIZED_VALUE
;
967 /* Calculate sizes of DeviceExtension and PortConfig */
968 DeviceExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
969 HwInitializationData
->DeviceExtensionSize
;
971 MaxBus
= (HwInitializationData
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
972 DPRINT("MaxBus: %lu\n", MaxBus
);
976 /* Create a unicode device name */
978 L
"\\Device\\ScsiPort%lu",
979 SystemConfig
->ScsiPortCount
);
980 RtlInitUnicodeString(&DeviceName
, NameBuffer
);
982 DPRINT("Creating device: %wZ\n", &DeviceName
);
984 /* Create the port device */
985 Status
= IoCreateDevice(DriverObject
,
988 FILE_DEVICE_CONTROLLER
,
993 if (!NT_SUCCESS(Status
))
995 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
996 PortDeviceObject
= NULL
;
1000 DPRINT ("Created device: %wZ (%p)\n", &DeviceName
, PortDeviceObject
);
1002 /* Set the buffering strategy here... */
1003 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1004 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
; /* FIXME: Is this really needed? */
1006 /* Fill Device Extension */
1007 DeviceExtension
= PortDeviceObject
->DeviceExtension
;
1008 DeviceExtension
->Length
= DeviceExtensionSize
;
1009 DeviceExtension
->DeviceObject
= PortDeviceObject
;
1010 DeviceExtension
->PortNumber
= SystemConfig
->ScsiPortCount
;
1012 /* Driver's routines... */
1013 DeviceExtension
->HwInitialize
= HwInitializationData
->HwInitialize
;
1014 DeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
1015 DeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
1016 DeviceExtension
->HwResetBus
= HwInitializationData
->HwResetBus
;
1017 DeviceExtension
->HwDmaStarted
= HwInitializationData
->HwDmaStarted
;
1019 /* Extensions sizes */
1020 DeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
1021 DeviceExtension
->LunExtensionSize
= HwInitializationData
->SpecificLuExtensionSize
;
1022 DeviceExtension
->SrbExtensionSize
= HwInitializationData
->SrbExtensionSize
;
1024 /* Round Srb extension size to the quadword */
1025 DeviceExtension
->SrbExtensionSize
=
1026 ~(sizeof(LONGLONG
) - 1) & (DeviceExtension
->SrbExtensionSize
+
1027 sizeof(LONGLONG
) - 1);
1029 /* Fill some numbers (bus count, lun count, etc) */
1030 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
1031 DeviceExtension
->RequestsNumber
= 16;
1033 /* Initialize the spin lock in the controller extension */
1034 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1035 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
1037 /* Initialize the DPC object */
1038 IoInitializeDpcRequest(PortDeviceObject
,
1041 /* Initialize the device timer */
1042 DeviceExtension
->TimerCount
= -1;
1043 IoInitializeTimer(PortDeviceObject
,
1047 /* Initialize miniport timer */
1048 KeInitializeTimer(&DeviceExtension
->MiniportTimer
);
1049 KeInitializeDpc(&DeviceExtension
->MiniportTimerDpc
,
1050 SpiMiniportTimerDpc
,
1055 Status
= SpiCreatePortConfig(DeviceExtension
,
1056 HwInitializationData
,
1061 if (!NT_SUCCESS(Status
))
1064 /* Allocate and initialize port configuration info */
1065 PortConfigSize
= (sizeof(PORT_CONFIGURATION_INFORMATION
) +
1066 HwInitializationData
->NumberOfAccessRanges
*
1067 sizeof(ACCESS_RANGE
) + 7) & ~7;
1068 DeviceExtension
->PortConfig
= ExAllocatePoolWithTag(NonPagedPool
, PortConfigSize
, TAG_SCSIPORT
);
1070 /* Fail if failed */
1071 if (DeviceExtension
->PortConfig
== NULL
)
1073 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1077 PortConfig
= DeviceExtension
->PortConfig
;
1079 /* Copy information here */
1080 RtlCopyMemory(PortConfig
,
1082 sizeof(PORT_CONFIGURATION_INFORMATION
));
1085 /* Copy extension sizes into the PortConfig */
1086 PortConfig
->SpecificLuExtensionSize
= DeviceExtension
->LunExtensionSize
;
1087 PortConfig
->SrbExtensionSize
= DeviceExtension
->SrbExtensionSize
;
1089 /* Initialize Access ranges */
1090 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1092 PortConfig
->AccessRanges
= (PVOID
)(PortConfig
+1);
1094 /* Align to LONGLONG */
1095 PortConfig
->AccessRanges
= (PVOID
)((ULONG
)(PortConfig
->AccessRanges
) + 7);
1096 PortConfig
->AccessRanges
= (PVOID
)((ULONG
)(PortConfig
->AccessRanges
) & ~7);
1099 RtlCopyMemory(PortConfig
->AccessRanges
,
1100 ConfigInfo
.AccessRanges
,
1101 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
1104 /* Search for matching PCI device */
1105 if ((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1106 (HwInitializationData
->VendorIdLength
> 0) &&
1107 (HwInitializationData
->VendorId
!= NULL
) &&
1108 (HwInitializationData
->DeviceIdLength
> 0) &&
1109 (HwInitializationData
->DeviceId
!= NULL
))
1111 PortConfig
->BusInterruptLevel
= 0;
1113 /* Get PCI device data */
1114 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1115 HwInitializationData
->VendorIdLength
,
1116 HwInitializationData
->VendorId
,
1117 HwInitializationData
->DeviceIdLength
,
1118 HwInitializationData
->DeviceId
);
1120 if (!SpiGetPciConfigData(DriverObject
,
1122 HwInitializationData
,
1125 ConfigInfo
.BusNumber
,
1128 /* Continue to the next bus, nothing here */
1129 ConfigInfo
.BusNumber
++;
1130 DeviceExtension
->PortConfig
= NULL
;
1131 ExFreePool(PortConfig
);
1133 goto CreatePortConfig
;
1136 if (!PortConfig
->BusInterruptLevel
)
1138 /* Bypass this slot, because no interrupt was assigned */
1139 DeviceExtension
->PortConfig
= NULL
;
1140 ExFreePool(PortConfig
);
1141 goto CreatePortConfig
;
1146 DPRINT("Non-pci bus\n");
1149 /* Note: HwFindAdapter is called once for each bus */
1151 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
1152 Result
= (HwInitializationData
->HwFindAdapter
)(&DeviceExtension
->MiniPortDeviceExtension
,
1154 0, /* BusInformation */
1155 ConfigInfo
.Parameter
, /* ArgumentString */
1159 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1160 Result
, (Again
) ? "True" : "False");
1162 /* Free MapRegisterBase, it's not needed anymore */
1163 if (DeviceExtension
->MapRegisterBase
!= NULL
)
1165 ExFreePool(DeviceExtension
->MapRegisterBase
);
1166 DeviceExtension
->MapRegisterBase
= NULL
;
1169 /* If result is nothing good... */
1170 if (Result
!= SP_RETURN_FOUND
)
1172 DPRINT("HwFindAdapter() Result: %lu\n", Result
);
1174 if (Result
== SP_RETURN_NOT_FOUND
)
1176 /* We can continue on the next bus */
1177 ConfigInfo
.BusNumber
++;
1180 DeviceExtension
->PortConfig
= NULL
;
1181 ExFreePool(PortConfig
);
1182 goto CreatePortConfig
;
1185 /* Otherwise, break */
1186 Status
= STATUS_INTERNAL_ERROR
;
1190 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1191 PortConfig
->BusInterruptVector
, PortConfig
->InitiatorBusId
[0]);
1193 /* If the SRB extension size was updated */
1194 if (!DeviceExtension
->NonCachedExtension
&&
1195 (PortConfig
->SrbExtensionSize
!= DeviceExtension
->SrbExtensionSize
))
1197 /* Set it (rounding to LONGLONG again) */
1198 DeviceExtension
->SrbExtensionSize
=
1199 (PortConfig
->SrbExtensionSize
+
1200 sizeof(LONGLONG
)) & ~(sizeof(LONGLONG
) - 1);
1203 /* The same with LUN extension size */
1204 if (PortConfig
->SpecificLuExtensionSize
!= DeviceExtension
->LunExtensionSize
)
1205 DeviceExtension
->LunExtensionSize
= PortConfig
->SpecificLuExtensionSize
;
1208 if (!((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1209 (HwInitializationData
->VendorIdLength
> 0) &&
1210 (HwInitializationData
->VendorId
!= NULL
) &&
1211 (HwInitializationData
->DeviceIdLength
> 0) &&
1212 (HwInitializationData
->DeviceId
!= NULL
)))
1214 /* Construct a resource list */
1215 ResourceList
= SpiConfigToResource(DeviceExtension
,
1220 UNICODE_STRING UnicodeString
;
1221 RtlInitUnicodeString(&UnicodeString
, L
"ScsiAdapter");
1222 DPRINT("Reporting resources\n");
1223 Status
= IoReportResourceUsage(&UnicodeString
,
1229 FIELD_OFFSET(CM_RESOURCE_LIST
,
1230 List
[0].PartialResourceList
.PartialDescriptors
) +
1231 ResourceList
->List
[0].PartialResourceList
.Count
1232 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
1235 ExFreePool(ResourceList
);
1237 /* In case of a failure or a conflict, break */
1238 if (Conflict
|| (!NT_SUCCESS(Status
)))
1241 Status
= STATUS_CONFLICTING_ADDRESSES
;
1247 /* Reset the Conflict var */
1250 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1251 if (PortConfig
->MaximumNumberOfTargets
> SCSI_MAXIMUM_TARGETS_PER_BUS
)
1252 DeviceExtension
->MaxTargedIds
= SCSI_MAXIMUM_TARGETS_PER_BUS
;
1254 DeviceExtension
->MaxTargedIds
= PortConfig
->MaximumNumberOfTargets
;
1256 DeviceExtension
->BusNum
= PortConfig
->NumberOfBuses
;
1257 DeviceExtension
->CachesData
= PortConfig
->CachesData
;
1258 DeviceExtension
->ReceiveEvent
= PortConfig
->ReceiveEvent
;
1259 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->TaggedQueuing
;
1260 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
;
1262 /* If something was disabled via registry - apply it */
1263 if (ConfigInfo
.DisableMultipleLun
)
1264 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1266 if (ConfigInfo
.DisableTaggedQueueing
)
1267 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1269 /* Check if we need to alloc SRB data */
1270 if (DeviceExtension
->SupportsTaggedQueuing
||
1271 DeviceExtension
->MultipleReqsPerLun
)
1273 DeviceExtension
->NeedSrbDataAlloc
= TRUE
;
1277 DeviceExtension
->NeedSrbDataAlloc
= FALSE
;
1280 /* Get a pointer to the port capabilities */
1281 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1283 /* Copy one field there */
1284 DeviceExtension
->MapBuffers
= PortConfig
->MapBuffers
;
1285 PortCapabilities
->AdapterUsesPio
= PortConfig
->MapBuffers
;
1287 if (DeviceExtension
->AdapterObject
== NULL
&&
1288 (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
|| PortConfig
->Master
))
1290 DPRINT1("DMA is not supported yet\n");
1294 if (DeviceExtension
->SrbExtensionBuffer
== NULL
&&
1295 (DeviceExtension
->SrbExtensionSize
!= 0 ||
1296 PortConfig
->AutoRequestSense
))
1298 DeviceExtension
->SupportsAutoSense
= PortConfig
->AutoRequestSense
;
1299 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
1301 /* Allocate common buffer */
1302 Status
= SpiAllocateCommonBuffer(DeviceExtension
, 0);
1304 /* Check for failure */
1305 if (!NT_SUCCESS(Status
))
1309 /* Allocate SrbData, if needed */
1310 if (DeviceExtension
->NeedSrbDataAlloc
)
1313 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1315 if (DeviceExtension
->SrbDataCount
!= 0)
1316 Count
= DeviceExtension
->SrbDataCount
;
1318 Count
= DeviceExtension
->RequestsNumber
* 2;
1320 /* Allocate the data */
1321 SrbData
= ExAllocatePoolWithTag(NonPagedPool
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
), TAG_SCSIPORT
);
1322 if (SrbData
== NULL
)
1323 return STATUS_INSUFFICIENT_RESOURCES
;
1325 RtlZeroMemory(SrbData
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
));
1327 DeviceExtension
->SrbInfo
= SrbData
;
1328 DeviceExtension
->FreeSrbInfo
= SrbData
;
1329 DeviceExtension
->SrbDataCount
= Count
;
1331 /* Link it to the list */
1334 SrbData
->Requests
.Flink
= (PLIST_ENTRY
)(SrbData
+ 1);
1339 /* Mark the last entry of the list */
1341 SrbData
->Requests
.Flink
= NULL
;
1344 /* Initialize port capabilities */
1345 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1346 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1347 PortCapabilities
->MaximumTransferLength
= PortConfig
->MaximumTransferLength
;
1349 if (PortConfig
->ReceiveEvent
)
1350 PortCapabilities
->SupportedAsynchronousEvents
|= SRBEV_SCSI_ASYNC_NOTIFICATION
;
1352 PortCapabilities
->TaggedQueuing
= DeviceExtension
->SupportsTaggedQueuing
;
1353 PortCapabilities
->AdapterScansDown
= PortConfig
->AdapterScansDown
;
1355 if (PortConfig
->AlignmentMask
> PortDeviceObject
->AlignmentRequirement
)
1356 PortDeviceObject
->AlignmentRequirement
= PortConfig
->AlignmentMask
;
1358 PortCapabilities
->AlignmentMask
= PortDeviceObject
->AlignmentRequirement
;
1360 if (PortCapabilities
->MaximumPhysicalPages
== 0)
1362 PortCapabilities
->MaximumPhysicalPages
=
1363 BYTES_TO_PAGES(PortCapabilities
->MaximumTransferLength
);
1365 /* Apply miniport's limits */
1366 if (PortConfig
->NumberOfPhysicalBreaks
< PortCapabilities
->MaximumPhysicalPages
)
1368 PortCapabilities
->MaximumPhysicalPages
= PortConfig
->NumberOfPhysicalBreaks
;
1372 /* Deal with interrupts */
1373 if (DeviceExtension
->HwInterrupt
== NULL
||
1374 (PortConfig
->BusInterruptLevel
== 0 && PortConfig
->BusInterruptVector
== 0))
1377 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1379 /* FIXME: Use synchronization routine */
1380 ASSERT("No interrupts branch requires changes in synchronization\n");
1382 DeviceExtension
->Interrupt
= (PVOID
)DeviceExtension
;
1383 DPRINT("No interrupts\n");
1388 /* Are 2 interrupts needed? */
1389 if (DeviceExtension
->HwInterrupt
!= NULL
&&
1390 (PortConfig
->BusInterruptLevel
!= 0 || PortConfig
->BusInterruptVector
!= 0) &&
1391 (PortConfig
->BusInterruptLevel2
!= 0 || PortConfig
->BusInterruptVector2
!= 0))
1393 DPRINT1("2 interrupts requested! Not yet supported\n");
1398 BOOLEAN InterruptShareable
;
1400 /* No, only 1 interrupt */
1401 DPRINT("1 interrupt, IRQ is %d\n", PortConfig
->BusInterruptLevel
);
1403 DeviceExtension
->InterruptLevel
= PortConfig
->BusInterruptLevel
;
1405 /* Register an interrupt handler for this device */
1406 MappedIrq
= HalGetInterruptVector(PortConfig
->AdapterInterfaceType
,
1407 PortConfig
->SystemIoBusNumber
,
1408 PortConfig
->BusInterruptLevel
,
1409 PortConfig
->BusInterruptVector
,
1413 /* Determing IRQ sharability as usual */
1414 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1415 PortConfig
->InterruptMode
== LevelSensitive
)
1417 InterruptShareable
= TRUE
;
1421 InterruptShareable
= FALSE
;
1424 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
,
1425 (PKSERVICE_ROUTINE
)ScsiPortIsr
,
1431 PortConfig
->InterruptMode
,
1436 if (!(NT_SUCCESS(Status
)))
1438 DPRINT1("Could not connect interrupt %d\n",
1439 PortConfig
->BusInterruptVector
);
1440 DeviceExtension
->Interrupt
= NULL
;
1447 /* Save IoAddress (from access ranges) */
1448 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1450 DeviceExtension
->IoAddress
=
1451 ((*(PortConfig
->AccessRanges
))[0]).RangeStart
.LowPart
;
1453 DPRINT("Io Address %x\n", DeviceExtension
->IoAddress
);
1456 /* Set flag that it's allowed to disconnect during this command */
1457 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
1459 /* Initialize counter of active requests (-1 means there are none) */
1460 DeviceExtension
->ActiveRequestCounter
= -1;
1462 /* Analyze what we have about DMA */
1463 if (DeviceExtension
->AdapterObject
!= NULL
&&
1464 PortConfig
->Master
&&
1465 PortConfig
->NeedPhysicalAddresses
)
1467 DeviceExtension
->MapRegisters
= TRUE
;
1471 DeviceExtension
->MapRegisters
= FALSE
;
1474 /* Call HwInitialize at DISPATCH_LEVEL */
1475 KeRaiseIrql(DISPATCH_LEVEL
, &Dirql
);
1477 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1478 DeviceExtension
->HwInitialize
,
1479 DeviceExtension
->MiniPortDeviceExtension
))
1481 DPRINT1("HwInitialize() failed!\n");
1483 Status
= STATUS_ADAPTER_HARDWARE_ERROR
;
1487 /* Check if a notification is needed */
1488 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
1490 /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1491 ScsiPortDpcForIsr(NULL
,
1492 DeviceExtension
->DeviceObject
,
1497 /* Lower irql back to what it was */
1500 /* Start our timer */
1501 IoStartTimer(PortDeviceObject
);
1503 /* Initialize bus scanning information */
1504 DeviceExtension
->BusesConfig
= ExAllocatePoolWithTag(PagedPool
,
1505 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1506 + sizeof(ULONG
), TAG_SCSIPORT
);
1508 if (!DeviceExtension
->BusesConfig
)
1510 DPRINT1("Out of resources!\n");
1511 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1516 RtlZeroMemory(DeviceExtension
->BusesConfig
,
1517 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1520 /* Store number of buses there */
1521 DeviceExtension
->BusesConfig
->NumberOfBuses
= (UCHAR
)DeviceExtension
->BusNum
;
1523 /* Scan the adapter for devices */
1524 SpiScanAdapter(DeviceExtension
);
1526 /* Build the registry device map */
1527 SpiBuildDeviceMap(DeviceExtension
,
1528 (PUNICODE_STRING
)Argument2
);
1530 /* Create the dos device link */
1531 swprintf(DosNameBuffer
,
1533 SystemConfig
->ScsiPortCount
);
1534 RtlInitUnicodeString(&DosDeviceName
, DosNameBuffer
);
1535 IoCreateSymbolicLink(&DosDeviceName
, &DeviceName
);
1537 /* Increase the port count */
1538 SystemConfig
->ScsiPortCount
++;
1539 FirstConfigCall
= FALSE
;
1541 /* Increase adapter number and bus number respectively */
1542 ConfigInfo
.AdapterNumber
++;
1545 ConfigInfo
.BusNumber
++;
1547 DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber
, MaxBus
);
1552 /* Clean up the mess */
1553 SpiCleanupAfterInit(DeviceExtension
);
1555 /* Close registry keys */
1556 if (ConfigInfo
.ServiceKey
!= NULL
)
1557 ZwClose(ConfigInfo
.ServiceKey
);
1559 if (ConfigInfo
.DeviceKey
!= NULL
)
1560 ZwClose(ConfigInfo
.DeviceKey
);
1562 if (ConfigInfo
.BusKey
!= NULL
)
1563 ZwClose(ConfigInfo
.BusKey
);
1565 if (ConfigInfo
.AccessRanges
!= NULL
)
1566 ExFreePool(ConfigInfo
.AccessRanges
);
1568 if (ConfigInfo
.Parameter
!= NULL
)
1569 ExFreePool(ConfigInfo
.Parameter
);
1571 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %b!\n",
1572 Status
, DeviceFound
);
1574 return (DeviceFound
== FALSE
) ? Status
: STATUS_SUCCESS
;
1578 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1580 PSCSI_LUN_INFO LunInfo
;
1584 /* Check if we have something to clean up */
1585 if (DeviceExtension
== NULL
)
1588 /* Stop the timer and disconnect the interrupt */
1589 if (DeviceExtension
->Interrupt
)
1591 IoStopTimer(DeviceExtension
->DeviceObject
);
1592 IoDisconnectInterrupt(DeviceExtension
->Interrupt
);
1595 /* Delete ConfigInfo */
1596 if (DeviceExtension
->BusesConfig
)
1598 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
1600 if (!DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
])
1603 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
1607 /* Free current, but save pointer to the next one */
1608 Ptr
= LunInfo
->Next
;
1609 ExFreePool(LunInfo
);
1613 ExFreePool(DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]);
1616 ExFreePool(DeviceExtension
->BusesConfig
);
1619 /* Free PortConfig */
1620 if (DeviceExtension
->PortConfig
)
1621 ExFreePool(DeviceExtension
->PortConfig
);
1624 for(Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
1626 while (DeviceExtension
->LunExtensionList
[Lun
])
1628 Ptr
= DeviceExtension
->LunExtensionList
[Lun
];
1629 DeviceExtension
->LunExtensionList
[Lun
] = DeviceExtension
->LunExtensionList
[Lun
]->Next
;
1635 /* Free common buffer (if it exists) */
1636 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
&&
1637 DeviceExtension
->CommonBufferLength
!= 0)
1639 if (!DeviceExtension
->AdapterObject
)
1641 ExFreePool(DeviceExtension
->SrbExtensionBuffer
);
1646 HalFreeCommonBuffer(DeviceExtension
->AdapterObject
,
1647 DeviceExtension
->CommonBufferLength
,
1648 DeviceExtension
->PhysicalCommonBuffer
,
1649 DeviceExtension
->SrbExtensionBuffer
,
1656 if (DeviceExtension
->SrbInfo
!= NULL
)
1657 ExFreePool(DeviceExtension
->SrbInfo
);
1659 /* Unmap mapped addresses */
1660 while (DeviceExtension
->MappedAddressList
!= NULL
)
1662 MmUnmapIoSpace(DeviceExtension
->MappedAddressList
->MappedAddress
,
1663 DeviceExtension
->MappedAddressList
->NumberOfBytes
);
1665 Ptr
= DeviceExtension
->MappedAddressList
;
1666 DeviceExtension
->MappedAddressList
= DeviceExtension
->MappedAddressList
->NextMappedAddress
;
1671 /* Finally delete the device object */
1672 DPRINT("Deleting device %p\n", DeviceExtension
->DeviceObject
);
1673 IoDeleteDevice(DeviceExtension
->DeviceObject
);
1682 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
1683 IN PSCSI_REQUEST_BLOCK Srb
,
1684 IN PVOID LogicalAddress
,
1687 DPRINT1("ScsiPortIoMapTransfer()\n");
1696 ScsiPortLogError(IN PVOID HwDeviceExtension
,
1697 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
1704 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1706 DPRINT1("ScsiPortLogError() called\n");
1708 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1709 SCSI_PORT_DEVICE_EXTENSION
,
1710 MiniPortDeviceExtension
);
1713 DPRINT("ScsiPortLogError() done\n");
1721 ScsiPortMoveMemory(OUT PVOID Destination
,
1725 RtlMoveMemory(Destination
,
1735 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
1736 IN PVOID HwDeviceExtension
,
1739 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1742 DPRINT("ScsiPortNotification() called\n");
1744 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1745 SCSI_PORT_DEVICE_EXTENSION
,
1746 MiniPortDeviceExtension
);
1748 DPRINT("DeviceExtension %p\n", DeviceExtension
);
1750 va_start(ap
, HwDeviceExtension
);
1752 switch (NotificationType
)
1754 case RequestComplete
:
1756 PSCSI_REQUEST_BLOCK Srb
;
1757 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1759 Srb
= (PSCSI_REQUEST_BLOCK
) va_arg (ap
, PSCSI_REQUEST_BLOCK
);
1761 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb
);
1763 /* Make sure Srb is allright */
1764 ASSERT(Srb
->SrbStatus
!= SRB_STATUS_PENDING
);
1765 ASSERT(Srb
->Function
!= SRB_FUNCTION_EXECUTE_SCSI
|| Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
|| Srb
->ScsiStatus
== SCSISTAT_GOOD
);
1767 if (!(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
1769 /* It's been already completed */
1774 /* It's not active anymore */
1775 Srb
->SrbFlags
&= ~SRB_FLAGS_IS_ACTIVE
;
1777 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
1779 /* TODO: Treat it specially */
1784 /* Get the SRB data */
1785 SrbData
= SpiGetSrbData(DeviceExtension
,
1791 /* Make sure there are no CompletedRequests and there is a Srb */
1792 ASSERT(SrbData
->CompletedRequests
== NULL
&& SrbData
->Srb
!= NULL
);
1794 /* If it's a read/write request, make sure it has data inside it */
1795 if ((Srb
->SrbStatus
== SRB_STATUS_SUCCESS
) &&
1796 ((Srb
->Cdb
[0] == SCSIOP_READ
) || (Srb
->Cdb
[0] == SCSIOP_WRITE
)))
1798 ASSERT(Srb
->DataTransferLength
);
1801 SrbData
->CompletedRequests
= DeviceExtension
->InterruptData
.CompletedRequests
;
1802 DeviceExtension
->InterruptData
.CompletedRequests
= SrbData
;
1808 DPRINT("Notify: NextRequest\n");
1809 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1818 PathId
= (UCHAR
) va_arg (ap
, int);
1819 TargetId
= (UCHAR
) va_arg (ap
, int);
1820 Lun
= (UCHAR
) va_arg (ap
, int);
1822 DPRINT1 ("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1823 PathId
, TargetId
, Lun
);
1824 /* FIXME: Implement it! */
1827 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
1828 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT_LU;
1831 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
1836 DPRINT1("Notify: ResetDetected\n");
1841 DPRINT1 ("Unsupported notification %lu\n", NotificationType
);
1847 /* Request a DPC after we're done with the interrupt */
1848 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NOTIFICATION_NEEDED
;
1856 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
1857 IN ULONG BusDataType
,
1858 IN ULONG SystemIoBusNumber
,
1859 IN ULONG SlotNumber
,
1864 DPRINT("ScsiPortSetBusDataByOffset()\n");
1865 return(HalSetBusDataByOffset(BusDataType
,
1878 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
1879 IN INTERFACE_TYPE BusType
,
1880 IN ULONG SystemIoBusNumber
,
1881 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
1882 IN ULONG NumberOfBytes
,
1883 IN BOOLEAN InIoSpace
)
1885 DPRINT("ScsiPortValidateRange()\n");
1890 /* INTERNAL FUNCTIONS ********************************************************/
1893 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
1894 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
1895 IN PPORT_CONFIGURATION_INFORMATION PortConfig
)
1897 PACCESS_RANGE AccessRange
;
1898 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData
;
1904 /* Loop through all entries */
1905 for (Index
= 0; Index
< ResourceDescriptor
->PartialResourceList
.Count
; Index
++)
1907 PartialData
= &ResourceDescriptor
->PartialResourceList
.PartialDescriptors
[Index
];
1909 switch (PartialData
->Type
)
1911 case CmResourceTypePort
:
1912 /* Copy access ranges */
1913 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
1915 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
1917 AccessRange
->RangeStart
= PartialData
->u
.Port
.Start
;
1918 AccessRange
->RangeLength
= PartialData
->u
.Port
.Length
;
1920 AccessRange
->RangeInMemory
= FALSE
;
1925 case CmResourceTypeMemory
:
1926 /* Copy access ranges */
1927 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
1929 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
1931 AccessRange
->RangeStart
= PartialData
->u
.Memory
.Start
;
1932 AccessRange
->RangeLength
= PartialData
->u
.Memory
.Length
;
1934 AccessRange
->RangeInMemory
= TRUE
;
1939 case CmResourceTypeInterrupt
:
1940 /* Copy interrupt data */
1941 PortConfig
->BusInterruptLevel
= PartialData
->u
.Interrupt
.Level
;
1942 PortConfig
->BusInterruptVector
= PartialData
->u
.Interrupt
.Vector
;
1944 /* Set interrupt mode accordingly to the resource */
1945 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
1947 PortConfig
->InterruptMode
= Latched
;
1949 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
1951 PortConfig
->InterruptMode
= LevelSensitive
;
1955 case CmResourceTypeDma
:
1956 PortConfig
->DmaChannel
= PartialData
->u
.Dma
.Channel
;
1957 PortConfig
->DmaPort
= PartialData
->u
.Dma
.Port
;
1963 static PCM_RESOURCE_LIST
1964 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1965 PPORT_CONFIGURATION_INFORMATION PortConfig
)
1967 PCONFIGURATION_INFORMATION ConfigInfo
;
1968 PCM_RESOURCE_LIST ResourceList
;
1969 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
1970 PACCESS_RANGE AccessRange
;
1972 ULONG ListLength
= 0, i
, FullSize
;
1975 /* Get current Atdisk usage from the system */
1976 ConfigInfo
= IoGetConfigurationInformation();
1978 if (PortConfig
->AtdiskPrimaryClaimed
)
1979 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
1981 if (PortConfig
->AtdiskSecondaryClaimed
)
1982 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
1984 /* Do we use DMA? */
1985 if (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
||
1986 PortConfig
->DmaPort
!= SP_UNINITIALIZED_VALUE
)
1996 /* How many interrupts to we have? */
1997 if (DeviceExtension
->HwInterrupt
== NULL
||
1998 (PortConfig
->BusInterruptLevel
== 0 &&
1999 PortConfig
->BusInterruptVector
== 0))
2009 if (DeviceExtension
->HwInterrupt
!= NULL
&&
2010 (PortConfig
->BusInterruptLevel2
!= 0 ||
2011 PortConfig
->BusInterruptVector2
!= 0))
2017 /* How many access ranges do we use? */
2018 AccessRange
= &((*(PortConfig
->AccessRanges
))[0]);
2019 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2021 if (AccessRange
->RangeLength
!= 0)
2027 /* Allocate the resource list, since we know its size now */
2028 FullSize
= sizeof(CM_RESOURCE_LIST
) + (ListLength
- 1) *
2029 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
2031 ResourceList
= (PCM_RESOURCE_LIST
)ExAllocatePoolWithTag(PagedPool
, FullSize
, TAG_SCSIPORT
);
2037 RtlZeroMemory(ResourceList
, FullSize
);
2040 ResourceList
->Count
= 1;
2041 ResourceList
->List
[0].InterfaceType
= PortConfig
->AdapterInterfaceType
;
2042 ResourceList
->List
[0].BusNumber
= PortConfig
->SystemIoBusNumber
;
2043 ResourceList
->List
[0].PartialResourceList
.Count
= ListLength
;
2044 ResourceDescriptor
= ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
;
2046 /* Copy access ranges array over */
2047 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2049 AccessRange
= &((*(PortConfig
->AccessRanges
))[i
]);
2051 /* If the range is empty - skip it */
2052 if (AccessRange
->RangeLength
== 0)
2055 if (AccessRange
->RangeInMemory
)
2057 ResourceDescriptor
->Type
= CmResourceTypeMemory
;
2058 ResourceDescriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
;
2062 ResourceDescriptor
->Type
= CmResourceTypePort
;
2063 ResourceDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
2066 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2068 ResourceDescriptor
->u
.Memory
.Start
= AccessRange
->RangeStart
;
2069 ResourceDescriptor
->u
.Memory
.Length
= AccessRange
->RangeLength
;
2071 ResourceDescriptor
++;
2074 /* If we use interrupt(s), copy them */
2077 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2079 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2080 PortConfig
->InterruptMode
== LevelSensitive
)
2082 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2083 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2087 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2088 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2091 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
2092 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
2093 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2095 ResourceDescriptor
++;
2099 /* Copy 2nd interrupt
2100 FIXME: Stupid code duplication, remove */
2103 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2105 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2106 PortConfig
->InterruptMode
== LevelSensitive
)
2108 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2109 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2113 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2114 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2117 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
2118 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
2119 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2121 ResourceDescriptor
++;
2127 ResourceDescriptor
->Type
= CmResourceTypeDma
;
2128 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2129 ResourceDescriptor
->u
.Dma
.Channel
= PortConfig
->DmaChannel
;
2130 ResourceDescriptor
->u
.Dma
.Port
= PortConfig
->DmaPort
;
2131 ResourceDescriptor
->Flags
= 0;
2133 if (PortConfig
->DmaChannel
== SP_UNINITIALIZED_VALUE
)
2134 ResourceDescriptor
->u
.Dma
.Channel
= 0;
2136 if (PortConfig
->DmaPort
== SP_UNINITIALIZED_VALUE
)
2137 ResourceDescriptor
->u
.Dma
.Port
= 0;
2140 return ResourceList
;
2145 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
2146 IN PDEVICE_OBJECT DeviceObject
,
2147 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
2148 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
2149 IN PUNICODE_STRING RegistryPath
,
2151 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
)
2153 PCI_COMMON_CONFIG PciConfig
;
2154 PCI_SLOT_NUMBER SlotNumber
;
2157 ULONG FunctionNumber
;
2158 CHAR VendorIdString
[8];
2159 CHAR DeviceIdString
[8];
2160 UNICODE_STRING UnicodeStr
;
2161 PCM_RESOURCE_LIST ResourceList
;
2164 DPRINT ("SpiGetPciConfiguration() called\n");
2166 RtlZeroMemory(&ResourceList
, sizeof(PCM_RESOURCE_LIST
));
2167 SlotNumber
.u
.AsULONG
= 0;
2169 /* Loop through all devices */
2170 for (DeviceNumber
= NextSlotNumber
->u
.bits
.DeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
2172 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
2174 /* Loop through all functions */
2175 for (FunctionNumber
= NextSlotNumber
->u
.bits
.FunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
2177 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
2179 /* Get PCI config bytes */
2180 DataSize
= HalGetBusData(PCIConfiguration
,
2182 SlotNumber
.u
.AsULONG
,
2186 /* If result of HalGetBusData is 0, then the bus is wrong */
2190 /* If result is PCI_INVALID_VENDORID, then this device has no more
2192 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
2195 sprintf (VendorIdString
, "%04hx", PciConfig
.VendorID
);
2196 sprintf (DeviceIdString
, "%04hx", PciConfig
.DeviceID
);
2198 if (_strnicmp(VendorIdString
, HwInitializationData
->VendorId
, HwInitializationData
->VendorIdLength
) ||
2199 _strnicmp(DeviceIdString
, HwInitializationData
->DeviceId
, HwInitializationData
->DeviceIdLength
))
2201 /* It is not our device */
2205 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2209 SlotNumber
.u
.bits
.DeviceNumber
,
2210 SlotNumber
.u
.bits
.FunctionNumber
);
2213 RtlInitUnicodeString(&UnicodeStr
, L
"ScsiAdapter");
2214 Status
= HalAssignSlotResources(RegistryPath
,
2220 SlotNumber
.u
.AsULONG
,
2223 if (!NT_SUCCESS(Status
))
2226 /* Create configuration information */
2227 SpiResourceToConfig(HwInitializationData
,
2231 /* Free the resource list */
2232 ExFreePool(ResourceList
);
2234 /* Set dev & fn numbers */
2235 NextSlotNumber
->u
.bits
.DeviceNumber
= DeviceNumber
;
2236 NextSlotNumber
->u
.bits
.FunctionNumber
= FunctionNumber
+ 1;
2238 /* Save the slot number */
2239 PortConfig
->SlotNumber
= SlotNumber
.u
.AsULONG
;
2243 NextSlotNumber
->u
.bits
.FunctionNumber
= 0;
2246 NextSlotNumber
->u
.bits
.DeviceNumber
= 0;
2247 DPRINT ("No device found\n");
2254 /**********************************************************************
2256 * ScsiPortCreateClose
2259 * Answer requests for Create/Close calls: a null operation.
2266 * Pointer to a device object.
2269 * Pointer to an IRP.
2275 static NTSTATUS STDCALL
2276 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
2279 DPRINT("ScsiPortCreateClose()\n");
2281 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2282 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2284 return STATUS_SUCCESS
;
2288 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2291 PSCSI_LUN_INFO LunInfo
;
2292 PIO_STACK_LOCATION IrpStack
;
2293 PDEVICE_OBJECT DeviceObject
;
2294 PSCSI_REQUEST_BLOCK Srb
;
2297 /* Get pointer to the SRB */
2298 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2299 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
2301 /* Check if PathId matches number of buses */
2302 if (DeviceExtension
->BusesConfig
== NULL
||
2303 DeviceExtension
->BusesConfig
->NumberOfBuses
<= Srb
->PathId
)
2305 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2306 return STATUS_DEVICE_DOES_NOT_EXIST
;
2309 /* Get pointer to LunInfo */
2310 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Srb
->PathId
]->LunInfo
;
2312 /* Find matching LunInfo */
2315 if (LunInfo
->PathId
== Srb
->PathId
&&
2316 LunInfo
->TargetId
== Srb
->TargetId
&&
2317 LunInfo
->Lun
== Srb
->Lun
)
2322 LunInfo
= LunInfo
->Next
;
2325 /* If we couldn't find it - exit */
2326 if (LunInfo
== NULL
)
2327 return STATUS_DEVICE_DOES_NOT_EXIST
;
2331 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2333 /* Release, if asked */
2334 if (Srb
->Function
== SRB_FUNCTION_RELEASE_DEVICE
)
2336 LunInfo
->DeviceClaimed
= FALSE
;
2337 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2338 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2340 return STATUS_SUCCESS
;
2343 /* Attach, if not already claimed */
2344 if (LunInfo
->DeviceClaimed
)
2346 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2347 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
2349 return STATUS_DEVICE_BUSY
;
2352 /* Save the device object */
2353 DeviceObject
= LunInfo
->DeviceObject
;
2355 if (Srb
->Function
== SRB_FUNCTION_CLAIM_DEVICE
)
2356 LunInfo
->DeviceClaimed
= TRUE
;
2358 if (Srb
->Function
== SRB_FUNCTION_ATTACH_DEVICE
)
2359 LunInfo
->DeviceObject
= Srb
->DataBuffer
;
2361 Srb
->DataBuffer
= DeviceObject
;
2363 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2364 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2366 return STATUS_SUCCESS
;
2370 /**********************************************************************
2372 * ScsiPortDispatchScsi
2375 * Answer requests for SCSI calls
2381 * Standard dispatch arguments
2387 static NTSTATUS STDCALL
2388 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
2391 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2392 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2393 PIO_STACK_LOCATION Stack
;
2394 PSCSI_REQUEST_BLOCK Srb
;
2396 NTSTATUS Status
= STATUS_SUCCESS
;
2397 PIRP NextIrp
, IrpList
;
2398 PKDEVICE_QUEUE_ENTRY Entry
;
2400 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2403 DeviceExtension
= DeviceObject
->DeviceExtension
;
2404 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2406 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2409 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2410 Status
= STATUS_UNSUCCESSFUL
;
2412 Irp
->IoStatus
.Status
= Status
;
2413 Irp
->IoStatus
.Information
= 0;
2415 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2420 DPRINT("Srb: %p\n", Srb
);
2421 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
2422 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
2424 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2428 if (LunExtension
== NULL
)
2430 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2431 Status
= STATUS_NO_SUCH_DEVICE
;
2433 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2434 Irp
->IoStatus
.Status
= Status
;
2435 Irp
->IoStatus
.Information
= 0;
2437 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2442 switch (Srb
->Function
)
2444 case SRB_FUNCTION_SHUTDOWN
:
2445 case SRB_FUNCTION_FLUSH
:
2446 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2447 if (DeviceExtension
->CachesData
== FALSE
)
2449 /* All success here */
2450 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2451 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2452 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2453 return STATUS_SUCCESS
;
2455 /* Fall through to a usual execute operation */
2457 case SRB_FUNCTION_EXECUTE_SCSI
:
2458 case SRB_FUNCTION_IO_CONTROL
:
2459 /* Mark IRP as pending in all cases */
2460 IoMarkIrpPending(Irp
);
2462 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2464 /* Start IO directly */
2465 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2471 /* We need to be at DISPATCH_LEVEL */
2472 KeRaiseIrql (DISPATCH_LEVEL
, &oldIrql
);
2474 /* Insert IRP into the queue */
2475 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
2476 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
2479 /* It means the queue is empty, and we just start this request */
2480 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2483 /* Back to the old IRQL */
2484 KeLowerIrql (oldIrql
);
2486 return STATUS_PENDING
;
2488 case SRB_FUNCTION_CLAIM_DEVICE
:
2489 case SRB_FUNCTION_ATTACH_DEVICE
:
2490 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2492 /* Reference device object and keep the device object */
2493 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2496 case SRB_FUNCTION_RELEASE_DEVICE
:
2497 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2499 /* Dereference device object and clear the device object */
2500 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2503 case SRB_FUNCTION_RELEASE_QUEUE
:
2504 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2506 /* Guard with the spinlock */
2507 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2509 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2511 DPRINT("Queue is not frozen really\n");
2513 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2514 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2515 Status
= STATUS_SUCCESS
;
2520 /* Unfreeze the queue */
2521 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2523 if (LunExtension
->SrbInfo
.Srb
== NULL
)
2525 /* Get next logical unit request */
2526 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
2528 /* SpiGetNextRequestFromLun() releases the spinlock */
2533 DPRINT("The queue has active request\n");
2534 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2538 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2539 Status
= STATUS_SUCCESS
;
2542 case SRB_FUNCTION_FLUSH_QUEUE
:
2543 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2545 /* Guard with the spinlock */
2546 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2548 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2550 DPRINT("Queue is not frozen really\n");
2552 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2553 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2557 /* Make sure there is no active request */
2558 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
2560 /* Compile a list from the device queue */
2562 while ((Entry
= KeRemoveDeviceQueue(&LunExtension
->DeviceQueue
)) != NULL
)
2564 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
2567 Stack
= IoGetCurrentIrpStackLocation(NextIrp
);
2568 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2571 Srb
->SrbStatus
= SRB_STATUS_REQUEST_FLUSHED
;
2572 NextIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2574 /* Add then to the list */
2575 NextIrp
->Tail
.Overlay
.ListEntry
.Flink
= (PLIST_ENTRY
)IrpList
;
2579 /* Unfreeze the queue */
2580 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2582 /* Release the spinlock */
2583 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2585 /* Complete those requests */
2589 IrpList
= (PIRP
)NextIrp
->Tail
.Overlay
.ListEntry
.Flink
;
2591 IoCompleteRequest(NextIrp
, 0);
2594 Status
= STATUS_SUCCESS
;
2598 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
2599 Status
= STATUS_NOT_IMPLEMENTED
;
2603 Irp
->IoStatus
.Status
= Status
;
2605 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2611 /**********************************************************************
2613 * ScsiPortDeviceControl
2616 * Answer requests for device control calls
2622 * Standard dispatch arguments
2628 static NTSTATUS STDCALL
2629 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
2632 PIO_STACK_LOCATION Stack
;
2633 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2634 NTSTATUS Status
= STATUS_SUCCESS
;;
2636 DPRINT("ScsiPortDeviceControl()\n");
2638 Irp
->IoStatus
.Information
= 0;
2640 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2641 DeviceExtension
= DeviceObject
->DeviceExtension
;
2643 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
2645 case IOCTL_SCSI_GET_DUMP_POINTERS
:
2647 PDUMP_POINTERS DumpPointers
;
2648 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2649 DumpPointers
= (PDUMP_POINTERS
)Irp
->AssociatedIrp
.SystemBuffer
;
2650 DumpPointers
->DeviceObject
= DeviceObject
;
2652 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2656 case IOCTL_SCSI_GET_CAPABILITIES
:
2657 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2658 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
== sizeof(PVOID
))
2660 *((PVOID
*)Irp
->AssociatedIrp
.SystemBuffer
) = &DeviceExtension
->PortCapabilities
;
2662 Irp
->IoStatus
.Information
= sizeof(PVOID
);
2663 Status
= STATUS_SUCCESS
;
2667 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(IO_SCSI_CAPABILITIES
))
2669 Status
= STATUS_BUFFER_TOO_SMALL
;
2673 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2674 &DeviceExtension
->PortCapabilities
,
2675 sizeof(IO_SCSI_CAPABILITIES
));
2677 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
2678 Status
= STATUS_SUCCESS
;
2681 case IOCTL_SCSI_GET_INQUIRY_DATA
:
2682 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2684 /* Copy inquiry data to the port device extension */
2685 Status
= SpiGetInquiryData(DeviceExtension
, Irp
);
2689 DPRINT1(" unknown ioctl code: 0x%lX\n",
2690 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2694 /* Complete the request with the given status */
2695 Irp
->IoStatus
.Status
= Status
;
2696 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2703 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
2706 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2707 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2708 PIO_STACK_LOCATION IrpStack
;
2709 PSCSI_REQUEST_BLOCK Srb
;
2710 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2714 DPRINT("ScsiPortStartIo() called!\n");
2716 DeviceExtension
= DeviceObject
->DeviceExtension
;
2717 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2719 DPRINT("DeviceExtension %p\n", DeviceExtension
);
2721 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2723 /* Apply "default" flags */
2724 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
2726 /* Get LUN extension */
2727 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2732 if (DeviceExtension
->NeedSrbDataAlloc
||
2733 DeviceExtension
->NeedSrbExtensionAlloc
)
2736 SrbInfo
= SpiAllocateSrbStructures(DeviceExtension
,
2740 /* Couldn't alloc one or both data structures, return */
2741 if (SrbInfo
== NULL
)
2743 /* We have to call IoStartNextPacket, because this request
2745 if (LunExtension
->Flags
& LUNEX_REQUEST_PENDING
)
2746 IoStartNextPacket(DeviceObject
, FALSE
);
2753 /* No allocations are needed */
2754 SrbInfo
= &LunExtension
->SrbInfo
;
2755 Srb
->SrbExtension
= NULL
;
2756 Srb
->QueueTag
= SP_UNTAGGED
;
2759 /* Increase sequence number of SRB */
2760 if (!SrbInfo
->SequenceNumber
)
2762 /* Increase global sequence number */
2763 DeviceExtension
->SequenceNumber
++;
2766 SrbInfo
->SequenceNumber
= DeviceExtension
->SequenceNumber
;
2769 /* Check some special SRBs */
2770 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2772 /* Some special handling */
2773 DPRINT1("Abort command! Unimplemented now\n");
2780 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
)
2782 // Store the MDL virtual address in SrbInfo structure
2783 SrbInfo
->DataOffset
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2785 if (DeviceExtension
->MapBuffers
&& Irp
->MdlAddress
)
2787 /* Calculate offset within DataBuffer */
2788 SrbInfo
->DataOffset
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
2789 Srb
->DataBuffer
= SrbInfo
->DataOffset
+
2790 (ULONG
)((PUCHAR
)Srb
->DataBuffer
-
2791 (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2794 if (DeviceExtension
->AdapterObject
)
2797 KeFlushIoBuffers(Irp
->MdlAddress
,
2798 Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? TRUE
: FALSE
,
2802 if (DeviceExtension
->MapRegisters
)
2804 /* Calculate number of needed map registers */
2805 SrbInfo
->NumberOfMapRegisters
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
2807 Srb
->DataTransferLength
);
2809 /* Allocate adapter channel */
2810 Status
= IoAllocateAdapterChannel(DeviceExtension
->AdapterObject
,
2811 DeviceExtension
->DeviceObject
,
2812 SrbInfo
->NumberOfMapRegisters
,
2816 if (!NT_SUCCESS(Status
))
2818 DPRINT1("IoAllocateAdapterChannel() failed!\n");
2820 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
2821 ScsiPortNotification(RequestComplete
,
2822 DeviceExtension
+ 1,
2825 ScsiPortNotification(NextRequest
,
2826 DeviceExtension
+ 1);
2828 /* Request DPC for that work */
2829 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2832 /* Control goes to SpiAdapterControl */
2837 /* Increase active request counter */
2838 CounterResult
= InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
2840 if (CounterResult
== 0 &&
2841 DeviceExtension
->AdapterObject
!= NULL
&&
2842 !DeviceExtension
->MapRegisters
)
2845 IoAllocateAdapterChannel(
2846 DeviceExtension
->AdapterObject
,
2848 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
,
2849 ScsiPortAllocationRoutine
,
2855 /* TODO: DMA is not implemented yet */
2861 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
2863 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
2864 ScsiPortStartPacket
,
2867 DPRINT("Synchronization failed!\n");
2869 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2870 Irp
->IoStatus
.Information
= 0;
2871 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
2873 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2876 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
2878 DPRINT("ScsiPortStartIo() done\n");
2882 static BOOLEAN STDCALL
2883 ScsiPortStartPacket(IN OUT PVOID Context
)
2885 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2886 PIO_STACK_LOCATION IrpStack
;
2887 PSCSI_REQUEST_BLOCK Srb
;
2888 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)Context
;
2889 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2893 DPRINT("ScsiPortStartPacket() called\n");
2895 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
2897 IrpStack
= IoGetCurrentIrpStackLocation(DeviceObject
->CurrentIrp
);
2898 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2900 /* Get LUN extension */
2901 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2906 /* Check if we are in a reset state */
2907 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
2909 /* Mark the we've got requests while being in the reset state */
2910 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET_REQUEST
;
2914 /* Set the time out value */
2915 DeviceExtension
->TimerCount
= Srb
->TimeOutValue
;
2918 DeviceExtension
->Flags
|= SCSI_PORT_DEVICE_BUSY
;
2920 if (LunExtension
->RequestTimeout
!= -1)
2922 /* Timer already active */
2927 /* It hasn't been initialized yet */
2928 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
2932 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2934 /* Handle bypass-requests */
2936 /* Is this an abort request? */
2937 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2939 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2941 /* Get pointer to SRB info structure */
2942 SrbInfo
= SpiGetSrbData(DeviceExtension
,
2948 /* Check if the request is still "active" */
2949 if (SrbInfo
== NULL
||
2950 SrbInfo
->Srb
== NULL
||
2951 !(SrbInfo
->Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
2953 /* It's not, mark it as active then */
2954 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
2957 LunExtension
->RequestTimeout
= -1;
2959 DPRINT("Request has been already completed, but abort request came\n");
2960 Srb
->SrbStatus
= SRB_STATUS_ABORT_FAILED
;
2962 /* Notify about request complete */
2963 ScsiPortNotification(RequestComplete
,
2964 DeviceExtension
->MiniPortDeviceExtension
,
2967 /* and about readiness for the next request */
2968 ScsiPortNotification(NextRequest
,
2969 DeviceExtension
->MiniPortDeviceExtension
);
2971 /* They might ask for some work, so queue the DPC for them */
2972 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2974 /* We're done in this branch */
2980 /* Add number of queued requests */
2981 LunExtension
->QueueCount
++;
2984 /* Bypass requests don't need request sense */
2985 LunExtension
->Flags
&= ~LUNEX_NEED_REQUEST_SENSE
;
2987 /* Is disconnect disabled for this request? */
2988 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
2990 /* Set the corresponding flag */
2991 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
2994 /* Transfer timeout value from Srb to Lun */
2995 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
2999 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3001 /* It's a disconnect, so no more requests can go */
3002 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3005 LunExtension
->Flags
|= SCSI_PORT_LU_ACTIVE
;
3007 /* Increment queue count */
3008 LunExtension
->QueueCount
++;
3010 /* If it's tagged - special thing */
3011 if (Srb
->QueueTag
!= SP_UNTAGGED
)
3013 /* TODO: Support tagged requests */
3018 /* Mark this Srb active */
3019 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
3021 /* Call HwStartIo routine */
3022 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
3025 /* If notification is needed, then request a DPC */
3026 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
3027 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3032 IO_ALLOCATION_ACTION
3034 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
,
3036 PVOID MapRegisterBase
,
3039 PSCSI_REQUEST_BLOCK Srb
;
3040 PSCSI_SG_ADDRESS ScatterGatherList
;
3042 PIO_STACK_LOCATION IrpStack
;
3043 ULONG TotalLength
= 0;
3044 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3045 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3047 BOOLEAN WriteToDevice
;
3049 /* Get pointers to SrbInfo and DeviceExtension */
3050 SrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)Context
;
3051 DeviceExtension
= DeviceObject
->DeviceExtension
;
3053 /* Get pointer to SRB */
3054 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3055 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
3057 /* Depending on the map registers number, we allocate
3058 either from NonPagedPool, or from our static list */
3059 if (SrbInfo
->NumberOfMapRegisters
> MAX_SG_LIST
)
3061 SrbInfo
->ScatterGather
= ExAllocatePoolWithTag(
3062 NonPagedPool
, SrbInfo
->NumberOfMapRegisters
* sizeof(SCSI_SG_ADDRESS
), TAG_SCSIPORT
);
3064 if (SrbInfo
->ScatterGather
== NULL
)
3067 Srb
->SrbFlags
|= SRB_FLAGS_SGLIST_FROM_POOL
;
3071 SrbInfo
->ScatterGather
= SrbInfo
->ScatterGatherList
;
3074 /* Use chosen SG list source */
3075 ScatterGatherList
= SrbInfo
->ScatterGather
;
3077 /* Save map registers base */
3078 SrbInfo
->BaseOfMapRegister
= MapRegisterBase
;
3080 /* Determine WriteToDevice flag */
3081 WriteToDevice
= Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
? TRUE
: FALSE
;
3083 /* Get virtual address of the data buffer */
3084 DataVA
= (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
3085 ((PCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
3087 /* Build the actual SG list */
3088 while (TotalLength
< Srb
->DataTransferLength
)
3090 if (!ScatterGatherList
)
3093 ScatterGatherList
->Length
= Srb
->DataTransferLength
- TotalLength
;
3094 ScatterGatherList
->PhysicalAddress
= IoMapTransfer(DeviceExtension
->AdapterObject
,
3097 DataVA
+ TotalLength
,
3098 &ScatterGatherList
->Length
,
3101 TotalLength
+= ScatterGatherList
->Length
;
3102 ScatterGatherList
++;
3105 /* Schedule an active request */
3106 InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
3107 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &CurrentIrql
);
3108 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
3109 ScsiPortStartPacket
,
3111 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, CurrentIrql
);
3113 return DeallocateObjectKeepRegisters
;
3116 static PSCSI_PORT_LUN_EXTENSION
3117 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3119 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3120 ULONG LunExtensionSize
;
3122 DPRINT("SpiAllocateLunExtension (%p)\n",
3125 /* Round LunExtensionSize first to the sizeof LONGLONG */
3126 LunExtensionSize
= (DeviceExtension
->LunExtensionSize
+
3127 sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
3129 LunExtensionSize
+= sizeof(SCSI_PORT_LUN_EXTENSION
);
3130 DPRINT("LunExtensionSize %lu\n", LunExtensionSize
);
3132 LunExtension
= ExAllocatePoolWithTag(NonPagedPool
, LunExtensionSize
, TAG_SCSIPORT
);
3133 if (LunExtension
== NULL
)
3135 DPRINT1("Out of resources!\n");
3139 /* Zero everything */
3140 RtlZeroMemory(LunExtension
, LunExtensionSize
);
3142 /* Initialize a list of requests */
3143 InitializeListHead(&LunExtension
->SrbInfo
.Requests
);
3145 /* Initialize timeout counter */
3146 LunExtension
->RequestTimeout
= -1;
3148 /* Set maximum queue size */
3149 LunExtension
->MaxQueueCount
= 256;
3151 /* Initialize request queue */
3152 KeInitializeDeviceQueue (&LunExtension
->DeviceQueue
);
3154 return LunExtension
;
3157 static PSCSI_PORT_LUN_EXTENSION
3158 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3163 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3165 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3166 DeviceExtension
, PathId
, TargetId
, Lun
);
3168 /* Get appropriate list */
3169 LunExtension
= DeviceExtension
->LunExtensionList
[(TargetId
+ Lun
) % LUS_NUMBER
];
3171 /* Iterate it until we find what we need */
3172 while (LunExtension
)
3174 if (LunExtension
->TargetId
== TargetId
&&
3175 LunExtension
->Lun
== Lun
&&
3176 LunExtension
->PathId
== PathId
)
3178 /* All matches, return */
3179 return LunExtension
;
3182 /* Advance to the next item */
3183 LunExtension
= LunExtension
->Next
;
3186 /* We did not find anything */
3187 DPRINT("Nothing found\n");
3191 static PSCSI_REQUEST_BLOCK_INFO
3192 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3193 PSCSI_PORT_LUN_EXTENSION LunExtension
,
3194 PSCSI_REQUEST_BLOCK Srb
)
3197 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3199 /* Spinlock must be held while this function executes */
3200 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3202 /* Allocate SRB data structure */
3203 if (DeviceExtension
->NeedSrbDataAlloc
)
3205 /* Treat the abort request in a special way */
3206 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
3208 SrbInfo
= SpiGetSrbData(DeviceExtension
,
3214 else if (Srb
->SrbFlags
&
3215 (SRB_FLAGS_QUEUE_ACTION_ENABLE
| SRB_FLAGS_NO_QUEUE_FREEZE
) &&
3216 !(Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3219 /* Do not process tagged commands if need request sense is set */
3220 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
3222 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3224 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3225 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3227 /* Relese the spinlock and return */
3228 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3232 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
3233 SrbInfo
= DeviceExtension
->FreeSrbInfo
;
3235 if (SrbInfo
== NULL
)
3237 /* No SRB structures left in the list. We have to leave
3238 and wait while we are called again */
3240 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3241 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3245 DeviceExtension
->FreeSrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)SrbInfo
->Requests
.Flink
;
3247 /* QueueTag must never be 0, so +1 to it */
3248 Srb
->QueueTag
= (UCHAR
)(SrbInfo
- DeviceExtension
->SrbInfo
) + 1;
3252 /* Usual untagged command */
3254 (!IsListEmpty(&LunExtension
->SrbInfo
.Requests
) ||
3255 LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
) &&
3256 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
3259 /* Mark it as pending and leave */
3260 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3261 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3262 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3264 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3268 Srb
->QueueTag
= SP_UNTAGGED
;
3269 SrbInfo
= &LunExtension
->SrbInfo
;
3274 Srb
->QueueTag
= SP_UNTAGGED
;
3275 SrbInfo
= &LunExtension
->SrbInfo
;
3278 /* Allocate SRB extension structure */
3279 if (DeviceExtension
->NeedSrbExtensionAlloc
)
3281 /* Check the list of free extensions */
3282 SrbExtension
= DeviceExtension
->FreeSrbExtensions
;
3284 /* If no free extensions... */
3285 if (SrbExtension
== NULL
)
3288 if (Srb
->Function
!= SRB_FUNCTION_ABORT_COMMAND
&&
3289 Srb
->QueueTag
!= SP_UNTAGGED
)
3291 SrbInfo
->Requests
.Blink
= NULL
;
3292 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
3293 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
3296 /* Return, in order to be called again later */
3297 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3298 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3302 /* Remove that free SRB extension from the list (since
3303 we're going to use it) */
3304 DeviceExtension
->FreeSrbExtensions
= *((PVOID
*)SrbExtension
);
3306 /* Spinlock can be released now */
3307 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3309 Srb
->SrbExtension
= SrbExtension
;
3311 if (Srb
->SenseInfoBuffer
!= NULL
&&
3312 DeviceExtension
->SupportsAutoSense
)
3314 /* Store pointer to the SenseInfo buffer */
3315 SrbInfo
->SaveSenseRequest
= Srb
->SenseInfoBuffer
;
3317 /* Does data fit the buffer? */
3318 if (Srb
->SenseInfoBufferLength
> sizeof(SENSE_DATA
))
3320 /* No, disabling autosense at all */
3321 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_AUTOSENSE
;
3325 /* Yes, update the buffer pointer */
3326 Srb
->SenseInfoBuffer
= SrbExtension
+ DeviceExtension
->SrbExtensionSize
;
3333 Srb
->SrbExtension
= NULL
;
3334 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3342 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
3343 IN PSCSI_LUN_INFO LunInfo
)
3345 IO_STATUS_BLOCK IoStatusBlock
;
3346 PIO_STACK_LOCATION IrpStack
;
3351 PINQUIRYDATA InquiryBuffer
;
3352 PSENSE_DATA SenseBuffer
;
3353 BOOLEAN KeepTrying
= TRUE
;
3354 ULONG RetryCount
= 0;
3355 SCSI_REQUEST_BLOCK Srb
;
3357 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3358 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3360 DPRINT ("SpiSendInquiry() called\n");
3362 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3364 InquiryBuffer
= ExAllocatePoolWithTag (NonPagedPool
, INQUIRYDATABUFFERSIZE
, TAG_SCSIPORT
);
3365 if (InquiryBuffer
== NULL
)
3366 return STATUS_INSUFFICIENT_RESOURCES
;
3368 SenseBuffer
= ExAllocatePoolWithTag (NonPagedPool
, SENSE_BUFFER_SIZE
, TAG_SCSIPORT
);
3369 if (SenseBuffer
== NULL
)
3371 ExFreePool(InquiryBuffer
);
3372 return STATUS_INSUFFICIENT_RESOURCES
;
3377 /* Initialize event for waiting */
3378 KeInitializeEvent(&Event
,
3383 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN
,
3388 INQUIRYDATABUFFERSIZE
,
3394 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3395 return STATUS_INSUFFICIENT_RESOURCES
;
3399 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3401 Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
3402 Srb
.OriginalRequest
= Irp
;
3403 Srb
.PathId
= LunInfo
->PathId
;
3404 Srb
.TargetId
= LunInfo
->TargetId
;
3405 Srb
.Lun
= LunInfo
->Lun
;
3406 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3407 Srb
.SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3408 Srb
.TimeOutValue
= 4;
3411 Srb
.SenseInfoBuffer
= SenseBuffer
;
3412 Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3414 Srb
.DataBuffer
= InquiryBuffer
;
3415 Srb
.DataTransferLength
= INQUIRYDATABUFFERSIZE
;
3417 /* Attach Srb to the Irp */
3418 IrpStack
= IoGetNextIrpStackLocation (Irp
);
3419 IrpStack
->Parameters
.Scsi
.Srb
= &Srb
;
3422 Cdb
= (PCDB
)Srb
.Cdb
;
3423 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_INQUIRY
;
3424 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= LunInfo
->Lun
;
3425 Cdb
->CDB6INQUIRY
.AllocationLength
= INQUIRYDATABUFFERSIZE
;
3427 /* Call the driver */
3428 Status
= IoCallDriver(DeviceObject
, Irp
);
3430 /* Wait for it to complete */
3431 if (Status
== STATUS_PENDING
)
3433 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3434 KeWaitForSingleObject(&Event
,
3439 Status
= IoStatusBlock
.Status
;
3442 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status
);
3444 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_SUCCESS
)
3446 /* All fine, copy data over */
3447 RtlCopyMemory(LunInfo
->InquiryData
,
3449 INQUIRYDATABUFFERSIZE
);
3451 Status
= STATUS_SUCCESS
;
3456 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb
.SrbStatus
);
3457 /* Check if the queue is frozen */
3458 if (Srb
.SrbStatus
& SRB_STATUS_QUEUE_FROZEN
)
3460 /* Something weird happened, deal with it (unfreeze the queue) */
3463 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb
.TargetId
);
3465 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3470 /* Clear frozen flag */
3471 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
3473 /* Acquire the spinlock */
3474 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
3476 /* Process the request */
3477 SpiGetNextRequestFromLun(DeviceObject
->DeviceExtension
, LunExtension
);
3479 /* SpiGetNextRequestFromLun() releases the spinlock,
3480 so we just lower irql back to what it was before */
3484 /* Check if data overrun happened */
3485 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
3487 DPRINT("Data overrun at TargetId %d\n", LunInfo
->TargetId
);
3488 /* Nothing dramatic, just copy data, but limiting the size */
3489 RtlCopyMemory(LunInfo
->InquiryData
,
3491 (Srb
.DataTransferLength
> INQUIRYDATABUFFERSIZE
) ?
3492 INQUIRYDATABUFFERSIZE
: Srb
.DataTransferLength
);
3494 Status
= STATUS_SUCCESS
;
3497 else if ((Srb
.SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3498 SenseBuffer
->SenseKey
== SCSI_SENSE_ILLEGAL_REQUEST
)
3500 /* LUN is not valid, but some device responds there.
3501 Mark it as invalid anyway */
3503 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3508 /* Retry a couple of times if no timeout happened */
3509 if ((RetryCount
< 2) &&
3510 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_NO_DEVICE
) &&
3511 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_SELECTION_TIMEOUT
))
3518 /* That's all, go to exit */
3521 /* Set status according to SRB status */
3522 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_FUNCTION
||
3523 SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH
)
3525 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3529 Status
= STATUS_IO_DEVICE_ERROR
;
3537 ExFreePool(InquiryBuffer
);
3538 ExFreePool(SenseBuffer
);
3540 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status
);
3546 /* Scans all SCSI buses */
3548 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3550 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3554 PSCSI_BUS_SCAN_INFO BusScanInfo
;
3555 PSCSI_LUN_INFO LastLunInfo
, LunInfo
, LunInfoExists
;
3556 BOOLEAN DeviceExists
;
3561 DPRINT("SpiScanAdapter() called\n");
3563 /* Scan all buses */
3564 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
3566 DPRINT(" Scanning bus %d\n", Bus
);
3569 /* Get pointer to the scan information */
3570 BusScanInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
];
3574 /* Find the last LUN info in the list */
3575 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3576 LastLunInfo
= LunInfo
;
3578 while (LunInfo
!= NULL
)
3580 LastLunInfo
= LunInfo
;
3581 LunInfo
= LunInfo
->Next
;
3586 /* We need to allocate this buffer */
3587 BusScanInfo
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_BUS_SCAN_INFO
), TAG_SCSIPORT
);
3591 DPRINT1("Out of resources!\n");
3595 /* Store the pointer in the BusScanInfo array */
3596 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
] = BusScanInfo
;
3598 /* Fill this struct (length and bus ids for now) */
3599 BusScanInfo
->Length
= sizeof(SCSI_BUS_SCAN_INFO
);
3600 BusScanInfo
->LogicalUnitsCount
= 0;
3601 BusScanInfo
->BusIdentifier
= DeviceExtension
->PortConfig
->InitiatorBusId
[Bus
];
3602 BusScanInfo
->LunInfo
= NULL
;
3604 /* Set pointer to the last LUN info to NULL */
3608 /* Create LUN information structure */
3609 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3611 if (LunInfo
== NULL
)
3613 DPRINT1("Out of resources!\n");
3617 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3619 /* Create LunExtension */
3620 LunExtension
= SpiAllocateLunExtension (DeviceExtension
);
3622 /* And send INQUIRY to every target */
3623 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
3625 /* TODO: Support scan bottom-up */
3627 /* Skip if it's the same address */
3628 if (Target
== BusScanInfo
->BusIdentifier
)
3631 /* Try to find an existing device here */
3632 DeviceExists
= FALSE
;
3633 LunInfoExists
= BusScanInfo
->LunInfo
;
3635 /* Find matching address on this bus */
3636 while (LunInfoExists
)
3638 if (LunInfoExists
->TargetId
== Target
)
3640 DeviceExists
= TRUE
;
3644 /* Advance to the next one */
3645 LunInfoExists
= LunInfoExists
->Next
;
3648 /* No need to bother rescanning, since we already did that before */
3652 /* Scan all logical units */
3653 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
3655 if ((!LunExtension
) || (!LunInfo
))
3658 /* Add extension to the list */
3659 Hint
= (Target
+ Lun
) % LUS_NUMBER
;
3660 LunExtension
->Next
= DeviceExtension
->LunExtensionList
[Hint
];
3661 DeviceExtension
->LunExtensionList
[Hint
] = LunExtension
;
3663 /* Fill Path, Target, Lun fields */
3664 LunExtension
->PathId
= LunInfo
->PathId
= (UCHAR
)Bus
;
3665 LunExtension
->TargetId
= LunInfo
->TargetId
= (UCHAR
) Target
;
3666 LunExtension
->Lun
= LunInfo
->Lun
= (UCHAR
)Lun
;
3668 /* Set flag to prevent race conditions */
3669 LunExtension
->Flags
|= SCSI_PORT_SCAN_IN_PROGRESS
;
3671 /* Zero LU extension contents */
3672 if (DeviceExtension
->LunExtensionSize
)
3674 RtlZeroMemory(LunExtension
+ 1,
3675 DeviceExtension
->LunExtensionSize
);
3678 /* Finally send the inquiry command */
3679 Status
= SpiSendInquiry(DeviceExtension
->DeviceObject
, LunInfo
);
3681 if (NT_SUCCESS(Status
))
3683 /* Let's see if we really found a device */
3684 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3686 /* Check if this device is unsupported */
3687 if (InquiryData
->DeviceTypeQualifier
== DEVICE_QUALIFIER_NOT_SUPPORTED
)
3689 DeviceExtension
->LunExtensionList
[Hint
] =
3690 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3695 /* Clear the "in scan" flag */
3696 LunExtension
->Flags
&= ~SCSI_PORT_SCAN_IN_PROGRESS
;
3698 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3699 InquiryData
->DeviceType
, Bus
, Target
, Lun
);
3701 /* Add this info to the linked list */
3702 LunInfo
->Next
= NULL
;
3704 LastLunInfo
->Next
= LunInfo
;
3706 BusScanInfo
->LunInfo
= LunInfo
;
3708 /* Store the last LUN info */
3709 LastLunInfo
= LunInfo
;
3711 /* Store DeviceObject */
3712 LunInfo
->DeviceObject
= DeviceExtension
->DeviceObject
;
3714 /* Allocate another buffer */
3715 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3719 DPRINT1("Out of resources!\n");
3723 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3725 /* Create a new LU extension */
3726 LunExtension
= SpiAllocateLunExtension(DeviceExtension
);
3732 /* Remove this LUN from the list */
3733 DeviceExtension
->LunExtensionList
[Hint
] =
3734 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3736 /* Decide whether we are continuing or not */
3737 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
3745 /* Free allocated buffers */
3747 ExFreePool(LunExtension
);
3750 ExFreePool(LunInfo
);
3752 /* Sum what we found */
3753 BusScanInfo
->LogicalUnitsCount
+= (UCHAR
) DevicesFound
;
3754 DPRINT(" Found %d devices on bus %d\n", DevicesFound
, Bus
);
3757 DPRINT ("SpiScanAdapter() done\n");
3762 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3765 ULONG InquiryDataSize
;
3766 PSCSI_LUN_INFO LunInfo
;
3767 ULONG BusCount
, LunCount
, Length
;
3768 PIO_STACK_LOCATION IrpStack
;
3769 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
3770 PSCSI_INQUIRY_DATA InquiryData
;
3771 PSCSI_BUS_DATA BusData
;
3775 DPRINT("SpiGetInquiryData() called\n");
3777 /* Get pointer to the buffer */
3778 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3779 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3781 /* Initialize bus and LUN counters */
3782 BusCount
= DeviceExtension
->BusesConfig
->NumberOfBuses
;
3785 /* Calculate total number of LUNs */
3786 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3787 LunCount
+= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3789 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
3791 ((sizeof(SCSI_INQUIRY_DATA
) - 1 + INQUIRYDATABUFFERSIZE
+
3792 sizeof(ULONG
) - 1) & ~(sizeof(ULONG
) - 1));
3794 /* Calculate data size */
3795 Length
= sizeof(SCSI_ADAPTER_BUS_INFO
) + (BusCount
- 1) *
3796 sizeof(SCSI_BUS_DATA
);
3798 Length
+= InquiryDataSize
* LunCount
;
3800 /* Check, if all data is going to fit into provided buffer */
3801 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< Length
)
3803 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3804 return STATUS_BUFFER_TOO_SMALL
;
3807 /* Store data size in the IRP */
3808 Irp
->IoStatus
.Information
= Length
;
3810 DPRINT("Data size: %lu\n", Length
);
3812 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
3814 AdapterBusInfo
->NumberOfBuses
= (UCHAR
)BusCount
;
3816 /* Point InquiryData to the corresponding place inside Buffer */
3817 InquiryData
= (PSCSI_INQUIRY_DATA
)(Buffer
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
3818 (BusCount
- 1) * sizeof(SCSI_BUS_DATA
));
3821 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3823 BusData
= &AdapterBusInfo
->BusData
[Bus
];
3825 /* Calculate and save an offset of the inquiry data */
3826 BusData
->InquiryDataOffset
= (PUCHAR
)InquiryData
- Buffer
;
3828 /* Get a pointer to the LUN information structure */
3829 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3831 /* Store Initiator Bus Id */
3832 BusData
->InitiatorBusId
=
3833 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->BusIdentifier
;
3835 /* Store LUN count */
3836 BusData
->NumberOfLogicalUnits
=
3837 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3840 while (LunInfo
!= NULL
)
3842 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
3843 Bus
, LunInfo
->TargetId
, LunInfo
->Lun
);
3845 /* Fill InquiryData with values */
3846 InquiryData
->PathId
= LunInfo
->PathId
;
3847 InquiryData
->TargetId
= LunInfo
->TargetId
;
3848 InquiryData
->Lun
= LunInfo
->Lun
;
3849 InquiryData
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
3850 InquiryData
->DeviceClaimed
= LunInfo
->DeviceClaimed
;
3851 InquiryData
->NextInquiryDataOffset
=
3852 (PUCHAR
)InquiryData
+ InquiryDataSize
- Buffer
;
3854 /* Copy data in it */
3855 RtlCopyMemory(InquiryData
->InquiryData
,
3856 LunInfo
->InquiryData
,
3857 INQUIRYDATABUFFERSIZE
);
3859 /* Move to the next LUN */
3860 LunInfo
= LunInfo
->Next
;
3861 InquiryData
= (PSCSI_INQUIRY_DATA
) ((PCHAR
)InquiryData
+ InquiryDataSize
);
3864 /* Either mark the end, or set offset to 0 */
3865 if (BusData
->NumberOfLogicalUnits
!= 0)
3866 ((PSCSI_INQUIRY_DATA
) ((PCHAR
) InquiryData
- InquiryDataSize
))->NextInquiryDataOffset
= 0;
3868 BusData
->InquiryDataOffset
= 0;
3871 /* Finish with success */
3872 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3873 return STATUS_SUCCESS
;
3876 static PSCSI_REQUEST_BLOCK_INFO
3877 SpiGetSrbData(IN PVOID DeviceExtension
,
3883 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3885 if (QueueTag
== SP_UNTAGGED
)
3887 /* Untagged request, get LU and return pointer to SrbInfo */
3888 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3893 /* Return NULL in case of error */
3897 /* Return the pointer to SrbInfo */
3898 return &LunExtension
->SrbInfo
;
3902 /* TODO: Implement when we have it */
3909 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3910 IN PSCSI_REQUEST_BLOCK InitialSrb
)
3912 PSCSI_REQUEST_BLOCK Srb
;
3915 PIO_STACK_LOCATION IrpStack
;
3916 LARGE_INTEGER LargeInt
;
3919 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb
);
3922 Srb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
) + sizeof(PVOID
), TAG_SCSIPORT
);
3923 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3926 LargeInt
.QuadPart
= (LONGLONG
) 1;
3927 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_READ
,
3928 DeviceExtension
->DeviceObject
,
3929 InitialSrb
->SenseInfoBuffer
,
3930 InitialSrb
->SenseInfoBufferLength
,
3934 IoSetCompletionRoutine(Irp
,
3935 (PIO_COMPLETION_ROUTINE
)SpiCompletionRoutine
,
3943 DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb
);
3947 IrpStack
= IoGetNextIrpStackLocation(Irp
);
3948 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3950 /* Put Srb address into Irp... */
3951 IrpStack
->Parameters
.Others
.Argument1
= (PVOID
)Srb
;
3953 /* ...and vice versa */
3954 Srb
->OriginalRequest
= Irp
;
3957 Ptr
= (PVOID
*)(Srb
+1);
3960 /* Build CDB for REQUEST SENSE */
3962 Cdb
= (PCDB
)Srb
->Cdb
;
3964 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
3965 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= 0;
3966 Cdb
->CDB6INQUIRY
.Reserved1
= 0;
3967 Cdb
->CDB6INQUIRY
.PageCode
= 0;
3968 Cdb
->CDB6INQUIRY
.IReserved
= 0;
3969 Cdb
->CDB6INQUIRY
.AllocationLength
= (UCHAR
)InitialSrb
->SenseInfoBufferLength
;
3970 Cdb
->CDB6INQUIRY
.Control
= 0;
3973 Srb
->TargetId
= InitialSrb
->TargetId
;
3974 Srb
->Lun
= InitialSrb
->Lun
;
3975 Srb
->PathId
= InitialSrb
->PathId
;
3977 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3978 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
3980 /* Timeout will be 2 seconds */
3981 Srb
->TimeOutValue
= 2;
3983 /* No auto request sense */
3984 Srb
->SenseInfoBufferLength
= 0;
3985 Srb
->SenseInfoBuffer
= NULL
;
3987 /* Set necessary flags */
3988 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_BYPASS_FROZEN_QUEUE
|
3989 SRB_FLAGS_DISABLE_DISCONNECT
;
3991 /* Transfer disable synch transfer flag */
3992 if (InitialSrb
->SrbFlags
& SRB_FLAGS_DISABLE_SYNCH_TRANSFER
)
3993 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3995 Srb
->DataBuffer
= InitialSrb
->SenseInfoBuffer
;
3997 /* Fill the transfer length */
3998 Srb
->DataTransferLength
= InitialSrb
->SenseInfoBufferLength
;
4000 /* Clear statuses */
4001 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
4004 /* Call the driver */
4005 (VOID
)IoCallDriver(DeviceExtension
->DeviceObject
, Irp
);
4007 DPRINT("SpiSendRequestSense() done\n");
4014 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4015 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
4016 OUT PBOOLEAN NeedToCallStartIo
)
4018 PSCSI_REQUEST_BLOCK Srb
;
4019 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4022 ULONG SequenceNumber
;
4025 Irp
= Srb
->OriginalRequest
;
4027 /* Get Lun extension */
4028 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4033 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
&&
4034 DeviceExtension
->MapBuffers
&&
4037 /* MDL is shared if transfer is broken into smaller parts */
4038 Srb
->DataBuffer
= (PCCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
4039 ((PCCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
4041 /* In case of data going in, flush the buffers */
4042 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
4044 KeFlushIoBuffers(Irp
->MdlAddress
,
4051 /* Flush adapter if needed */
4052 if (SrbInfo
->BaseOfMapRegister
)
4054 /* TODO: Implement */
4058 /* Clear the request */
4059 SrbInfo
->Srb
= NULL
;
4061 /* If disconnect is disabled... */
4062 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
4064 /* Acquire the spinlock since we mess with flags */
4065 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4067 /* Set corresponding flag */
4068 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
4070 /* Clear the timer if needed */
4071 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
))
4072 DeviceExtension
->TimerCount
= -1;
4074 /* Spinlock is not needed anymore */
4075 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4077 if (!(DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
) &&
4078 !(DeviceExtension
->Flags
& SCSI_PORT_DEVICE_BUSY
) &&
4079 !(*NeedToCallStartIo
))
4081 /* We're not busy, but we have a request pending */
4082 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4086 /* Scatter/gather */
4087 if (Srb
->SrbFlags
& SRB_FLAGS_SGLIST_FROM_POOL
)
4089 /* TODO: Implement */
4093 /* Acquire spinlock (we're freeing SrbExtension) */
4094 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4096 /* Free it (if needed) */
4097 if (Srb
->SrbExtension
)
4099 if (Srb
->SenseInfoBuffer
!= NULL
&& DeviceExtension
->SupportsAutoSense
)
4101 ASSERT(Srb
->SenseInfoBuffer
== NULL
|| SrbInfo
->SaveSenseRequest
!= NULL
);
4103 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)
4105 /* Copy sense data to the buffer */
4106 RtlCopyMemory(SrbInfo
->SaveSenseRequest
,
4107 Srb
->SenseInfoBuffer
,
4108 Srb
->SenseInfoBufferLength
);
4111 /* And restore the pointer */
4112 Srb
->SenseInfoBuffer
= SrbInfo
->SaveSenseRequest
;
4115 /* Put it into the free srb extensions list */
4116 *((PVOID
*)Srb
->SrbExtension
) = DeviceExtension
->FreeSrbExtensions
;
4117 DeviceExtension
->FreeSrbExtensions
= Srb
->SrbExtension
;
4120 /* Save transfer length in the IRP */
4121 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
4123 SequenceNumber
= SrbInfo
->SequenceNumber
;
4124 SrbInfo
->SequenceNumber
= 0;
4126 /* Decrement the queue count */
4127 LunExtension
->QueueCount
--;
4129 /* Free Srb, if needed*/
4130 if (Srb
->QueueTag
!= SP_UNTAGGED
)
4132 /* Put it into the free list */
4133 SrbInfo
->Requests
.Blink
= NULL
;
4134 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
4135 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
4138 /* SrbInfo is not used anymore */
4141 if (DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
)
4143 /* Clear the flag */
4144 DeviceExtension
->Flags
&= ~SCSI_PORT_REQUEST_PENDING
;
4146 /* Note the caller about StartIo */
4147 *NeedToCallStartIo
= TRUE
;
4150 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
4152 /* Start the packet */
4153 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4155 if (!(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
) &&
4156 LunExtension
->RequestTimeout
== -1)
4158 /* Start the next packet */
4159 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4163 /* Release the spinlock */
4164 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4167 DPRINT("IoCompleting request IRP 0x%08X\n", Irp
);
4169 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4171 /* Decrement number of active requests, and analyze the result */
4172 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4175 !DeviceExtension
->MapRegisters
&&
4176 DeviceExtension
->AdapterObject
!= NULL
)
4178 /* Nullify map registers */
4179 DeviceExtension
->MapRegisterBase
= NULL
;
4180 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4183 /* Exit, we're done */
4187 /* Decrement number of active requests, and analyze the result */
4188 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4191 !DeviceExtension
->MapRegisters
&&
4192 DeviceExtension
->AdapterObject
!= NULL
)
4194 /* Result is negative, so this is a slave, free map registers */
4195 DeviceExtension
->MapRegisterBase
= NULL
;
4196 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4199 /* Convert status */
4200 Irp
->IoStatus
.Status
= SpiStatusSrbToNt(Srb
->SrbStatus
);
4202 /* It's not a bypass, it's busy or the queue is full? */
4203 if ((Srb
->ScsiStatus
== SCSISTAT_BUSY
||
4204 Srb
->SrbStatus
== SRB_STATUS_BUSY
||
4205 Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
) &&
4206 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
))
4209 DPRINT("Busy SRB status %x\n", Srb
->SrbStatus
);
4211 /* Requeu, if needed */
4212 if (LunExtension
->Flags
& (LUNEX_FROZEN_QUEUE
| LUNEX_BUSY
))
4214 DPRINT("it's being requeued\n");
4216 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4217 Srb
->ScsiStatus
= 0;
4219 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4220 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
4223 /* It's a big f.ck up if we got here */
4224 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
4225 Srb
->ScsiStatus
= SCSISTAT_BUSY
;
4231 /* Release the spinlock */
4232 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4235 else if (LunExtension
->AttemptCount
++ < 20)
4237 /* LUN is still busy */
4238 Srb
->ScsiStatus
= 0;
4239 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4241 LunExtension
->BusyRequest
= Irp
;
4242 LunExtension
->Flags
|= LUNEX_BUSY
;
4244 /* Release the spinlock */
4245 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4250 /* Freeze the queue*/
4251 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4252 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4254 /* "Unfull" the queue */
4255 LunExtension
->Flags
&= ~LUNEX_FULL_QUEUE
;
4257 /* Release the spinlock */
4258 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4260 /* Return status that the device is not ready */
4261 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
4262 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4268 /* Start the next request, if LUN is idle, and this is sense request */
4269 if (((Srb
->ScsiStatus
!= SCSISTAT_CHECK_CONDITION
) ||
4270 (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) ||
4271 !Srb
->SenseInfoBuffer
|| !Srb
->SenseInfoBufferLength
)
4272 && (Srb
->SrbFlags
& SRB_FLAGS_NO_QUEUE_FREEZE
))
4274 if (LunExtension
->RequestTimeout
== -1)
4275 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4277 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4281 /* Freeze the queue */
4282 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4283 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4285 /* Do we need a request sense? */
4286 if (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4287 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
4288 Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
)
4290 /* If LUN is busy, we have to requeue it in order to allow request sense */
4291 if (LunExtension
->Flags
& LUNEX_BUSY
)
4293 DPRINT("Requeueing busy request to allow request sense\n");
4295 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4296 &LunExtension
->BusyRequest
->Tail
.Overlay
.DeviceQueueEntry
,
4299 /* We should never get here */
4302 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4303 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4308 /* Clear busy flags */
4309 LunExtension
->Flags
&= ~(LUNEX_FULL_QUEUE
| LUNEX_BUSY
);
4312 /* Release the spinlock */
4313 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4315 /* Send RequestSense */
4316 SpiSendRequestSense(DeviceExtension
, Srb
);
4322 /* Release the spinlock */
4323 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4326 /* Complete the request */
4327 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4332 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
4336 PSCSI_REQUEST_BLOCK Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
4337 PSCSI_REQUEST_BLOCK InitialSrb
;
4340 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp
);
4342 if ((Srb
->Function
== SRB_FUNCTION_RESET_BUS
) ||
4343 (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
))
4345 /* Deallocate SRB and IRP and exit */
4349 return STATUS_MORE_PROCESSING_REQUIRED
;
4352 /* Get a pointer to the SRB and IRP which were initially sent */
4353 InitialSrb
= *((PVOID
*)(Srb
+1));
4354 InitialIrp
= InitialSrb
->OriginalRequest
;
4356 if ((SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
) ||
4357 (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_DATA_OVERRUN
))
4359 /* Sense data is OK */
4360 InitialSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
4362 /* Set length to be the same */
4363 InitialSrb
->SenseInfoBufferLength
= (UCHAR
)Srb
->DataTransferLength
;
4366 /* Make sure initial SRB's queue is frozen */
4367 ASSERT(InitialSrb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
);
4369 /* Complete this request */
4370 IoCompleteRequest(InitialIrp
, IO_DISK_INCREMENT
);
4372 /* Deallocate everything (internal) */
4375 if (Irp
->MdlAddress
!= NULL
)
4377 MmUnlockPages(Irp
->MdlAddress
);
4378 IoFreeMdl(Irp
->MdlAddress
);
4379 Irp
->MdlAddress
= NULL
;
4383 return STATUS_MORE_PROCESSING_REQUIRED
;
4388 static BOOLEAN STDCALL
4389 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
4390 IN PVOID ServiceContext
)
4392 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4395 DPRINT("ScsiPortIsr() called!\n");
4397 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
4399 /* If interrupts are disabled - we don't expect any */
4400 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_DISABLE_INTERRUPTS
)
4403 /* Call miniport's HwInterrupt routine */
4404 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
4406 /* If flag of notification is set - queue a DPC */
4407 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4409 IoRequestDpc(DeviceExtension
->DeviceObject
,
4410 DeviceExtension
->CurrentIrp
,
4419 SpiSaveInterruptData(IN PVOID Context
)
4421 PSCSI_PORT_SAVE_INTERRUPT InterruptContext
= Context
;
4422 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4423 PSCSI_REQUEST_BLOCK Srb
;
4424 PSCSI_REQUEST_BLOCK_INFO SrbInfo
, NextSrbInfo
;
4425 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4428 /* Get pointer to the device extension */
4429 DeviceExtension
= InterruptContext
->DeviceExtension
;
4431 /* If we don't have anything pending - return */
4432 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
))
4435 /* Actually save the interrupt data */
4436 *InterruptContext
->InterruptData
= DeviceExtension
->InterruptData
;
4438 /* Clear the data stored in the device extension */
4439 DeviceExtension
->InterruptData
.Flags
&=
4440 (SCSI_PORT_RESET
| SCSI_PORT_RESET_REQUEST
| SCSI_PORT_DISABLE_INTERRUPTS
);
4441 DeviceExtension
->InterruptData
.CompletedAbort
= NULL
;
4442 DeviceExtension
->InterruptData
.ReadyLun
= NULL
;
4443 DeviceExtension
->InterruptData
.CompletedRequests
= NULL
;
4445 /* Loop through the list of completed requests */
4446 SrbInfo
= InterruptContext
->InterruptData
->CompletedRequests
;
4450 /* Make sure we have SRV */
4451 ASSERT(SrbInfo
->Srb
);
4453 /* Get SRB and LunExtension */
4456 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4461 /* We have to check special cases if request is unsuccessfull*/
4462 if (Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
)
4464 /* Check if we need request sense by a few conditions */
4465 if (Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
&&
4466 Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4467 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
))
4469 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
4471 /* It means: we tried to send REQUEST SENSE, but failed */
4473 Srb
->ScsiStatus
= 0;
4474 Srb
->SrbStatus
= SRB_STATUS_REQUEST_SENSE_FAILED
;
4478 /* Set the corresponding flag, so that REQUEST SENSE
4480 LunExtension
->Flags
|= LUNEX_NEED_REQUEST_SENSE
;
4485 /* Check for a full queue */
4486 if (Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
)
4488 /* TODO: Implement when it's encountered */
4493 /* Let's decide if we need to watch timeout or not */
4494 if (Srb
->QueueTag
== SP_UNTAGGED
)
4500 if (LunExtension
->SrbInfo
.Requests
.Flink
== &SrbInfo
->Requests
)
4505 /* Remove it from the queue */
4506 RemoveEntryList(&SrbInfo
->Requests
);
4511 /* We have to maintain timeout counter */
4512 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
))
4514 LunExtension
->RequestTimeout
= -1;
4518 NextSrbInfo
= CONTAINING_RECORD(LunExtension
->SrbInfo
.Requests
.Flink
,
4519 SCSI_REQUEST_BLOCK_INFO
,
4522 Srb
= NextSrbInfo
->Srb
;
4524 /* Update timeout counter */
4525 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
4529 SrbInfo
= SrbInfo
->CompletedRequests
;
4537 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4538 IN PSCSI_PORT_LUN_EXTENSION LunExtension
)
4540 PIO_STACK_LOCATION IrpStack
;
4542 PKDEVICE_QUEUE_ENTRY Entry
;
4543 PSCSI_REQUEST_BLOCK Srb
;
4546 /* If LUN is not active or queue is more than maximum allowed */
4547 if (LunExtension
->QueueCount
>= LunExtension
->MaxQueueCount
||
4548 !(LunExtension
->Flags
& SCSI_PORT_LU_ACTIVE
))
4550 /* Release the spinlock and exit */
4551 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4555 /* Check if we can get a next request */
4556 if (LunExtension
->Flags
&
4557 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_BUSY
|
4558 LUNEX_FULL_QUEUE
| LUNEX_FROZEN_QUEUE
| LUNEX_REQUEST_PENDING
))
4560 /* Pending requests can only be started if the queue is empty */
4561 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
) &&
4562 !(LunExtension
->Flags
&
4563 (LUNEX_BUSY
| LUNEX_FROZEN_QUEUE
| LUNEX_FULL_QUEUE
| LUNEX_NEED_REQUEST_SENSE
)))
4565 /* Make sure we have SRB */
4566 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
4568 /* Clear active and pending flags */
4569 LunExtension
->Flags
&= ~(LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
);
4571 /* Get next Irp, and clear pending requests list */
4572 NextIrp
= LunExtension
->PendingRequest
;
4573 LunExtension
->PendingRequest
= NULL
;
4575 /* Set attempt counter to zero */
4576 LunExtension
->AttemptCount
= 0;
4578 /* Release the spinlock */
4579 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4581 /* Start the next pending request */
4582 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4588 /* Release the spinlock, without clearing any flags and exit */
4589 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4595 /* Reset active flag */
4596 LunExtension
->Flags
&= ~SCSI_PORT_LU_ACTIVE
;
4598 /* Set attempt counter to zero */
4599 LunExtension
->AttemptCount
= 0;
4601 /* Remove packet from the device queue */
4602 Entry
= KeRemoveByKeyDeviceQueue(&LunExtension
->DeviceQueue
, LunExtension
->SortKey
);
4606 /* Get pointer to the next irp */
4607 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
4609 /* Get point to the SRB */
4610 IrpStack
= IoGetCurrentIrpStackLocation(NextIrp
);
4611 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
4614 LunExtension
->SortKey
= Srb
->QueueSortKey
;
4615 LunExtension
->SortKey
++;
4617 /* Release the spinlock */
4618 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4620 /* Start the next pending request */
4621 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4625 /* Release the spinlock */
4626 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4632 // ScsiPortDpcForIsr
4639 // IN PDEVICE_OBJECT DpcDeviceObject
4641 // IN PVOID DpcContext
4644 ScsiPortDpcForIsr(IN PKDPC Dpc
,
4645 IN PDEVICE_OBJECT DpcDeviceObject
,
4647 IN PVOID DpcContext
)
4649 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DpcDeviceObject
->DeviceExtension
;
4650 SCSI_PORT_INTERRUPT_DATA InterruptData
;
4651 SCSI_PORT_SAVE_INTERRUPT Context
;
4652 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4653 BOOLEAN NeedToStartIo
;
4654 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
4656 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4657 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
4659 /* We need to acquire spinlock */
4660 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4662 RtlZeroMemory(&InterruptData
, sizeof(SCSI_PORT_INTERRUPT_DATA
));
4666 /* Interrupt structure must be snapshotted, and only then analyzed */
4667 Context
.InterruptData
= &InterruptData
;
4668 Context
.DeviceExtension
= DeviceExtension
;
4670 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4671 SpiSaveInterruptData
,
4674 /* Nothing - just return (don't forget to release the spinlock */
4675 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4676 DPRINT("ScsiPortDpcForIsr() done\n");
4680 /* If flush of adapters is needed - do it */
4681 if (InterruptData
.Flags
& SCSI_PORT_FLUSH_ADAPTERS
)
4683 /* TODO: Implement */
4687 /* Check for IoMapTransfer */
4688 if (InterruptData
.Flags
& SCSI_PORT_MAP_TRANSFER
)
4690 /* TODO: Implement */
4694 /* Check if timer is needed */
4695 if (InterruptData
.Flags
& SCIS_PORT_TIMER_NEEDED
)
4697 /* TODO: Implement */
4701 /* If it's ready for the next request */
4702 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4704 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4705 if ((DeviceExtension
->Flags
&
4706 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
)) ==
4707 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
))
4709 /* Clear busy flag set by ScsiPortStartPacket() */
4710 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4712 if (!(InterruptData
.Flags
& SCSI_PORT_RESET
))
4714 /* Ready for next, and no reset is happening */
4715 DeviceExtension
->TimerCount
= -1;
4720 /* Not busy, but not ready for the next request */
4721 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4722 InterruptData
.Flags
&= ~SCSI_PORT_NEXT_REQUEST_READY
;
4727 if (InterruptData
.Flags
& SCSI_PORT_RESET_REPORTED
)
4729 /* Hold for a bit */
4730 DeviceExtension
->TimerCount
= 4;
4733 /* Any ready LUN? */
4734 if (InterruptData
.ReadyLun
!= NULL
)
4737 /* Process all LUNs from the list*/
4740 /* Remove it from the list first (as processed) */
4741 LunExtension
= InterruptData
.ReadyLun
;
4742 InterruptData
.ReadyLun
= LunExtension
->ReadyLun
;
4743 LunExtension
->ReadyLun
= NULL
;
4745 /* Get next request for this LUN */
4746 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4748 /* Still ready requests exist?
4749 If yes - get spinlock, if no - stop here */
4750 if (InterruptData
.ReadyLun
!= NULL
)
4751 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4758 /* Release the spinlock */
4759 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4762 /* If we ready for next packet, start it */
4763 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4764 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4766 NeedToStartIo
= FALSE
;
4768 /* Loop the completed request list */
4769 while (InterruptData
.CompletedRequests
)
4771 /* Remove the request */
4772 SrbInfo
= InterruptData
.CompletedRequests
;
4773 InterruptData
.CompletedRequests
= SrbInfo
->CompletedRequests
;
4774 SrbInfo
->CompletedRequests
= NULL
;
4777 SpiProcessCompletedRequest(DeviceExtension
,
4782 /* Loop abort request list */
4783 while (InterruptData
.CompletedAbort
)
4785 LunExtension
= InterruptData
.CompletedAbort
;
4787 /* Remove the request */
4788 InterruptData
.CompletedAbort
= LunExtension
->CompletedAbortRequests
;
4790 /* Get spinlock since we're going to change flags */
4791 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4793 /* TODO: Put SrbExtension to the list of free extensions */
4797 /* If we need - call StartIo routine */
4800 /* Make sure CurrentIrp is not null! */
4801 ASSERT(DpcDeviceObject
->CurrentIrp
!= NULL
);
4802 ScsiPortStartIo(DpcDeviceObject
, DpcDeviceObject
->CurrentIrp
);
4805 /* Everything has been done, check */
4806 if (InterruptData
.Flags
& SCSI_PORT_ENABLE_INT_REQUEST
)
4808 /* Synchronize using spinlock */
4809 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4811 /* Request an interrupt */
4812 DeviceExtension
->HwInterrupt(DeviceExtension
->MiniPortDeviceExtension
);
4814 ASSERT(DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
);
4816 /* Should interrupts be enabled again? */
4817 if (DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
)
4819 /* Clear this flag */
4820 DeviceExtension
->Flags
&= ~SCSI_PORT_DISABLE_INT_REQUESET
;
4822 /* Call a special routine to do this */
4825 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4826 SpiEnableInterrupts
,
4831 /* If we need a notification again - loop */
4832 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4835 /* Release the spinlock */
4836 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4839 DPRINT("ScsiPortDpcForIsr() done\n");
4844 SpiProcessTimeout(PVOID ServiceContext
)
4846 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
4847 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
4850 DPRINT("SpiProcessTimeout() entered\n");
4852 DeviceExtension
->TimerCount
= -1;
4854 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
4856 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET
;
4858 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET_REQUEST
)
4860 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET_REQUEST
;
4861 ScsiPortStartPacket(ServiceContext
);
4868 DPRINT("Resetting the bus\n");
4870 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
4872 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
, Bus
);
4874 /* Reset flags and set reset timeout to 4 seconds */
4875 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
4876 DeviceExtension
->TimerCount
= 4;
4879 /* If miniport requested - request a dpc for it */
4880 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4881 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
4890 SpiResetBus(PVOID ServiceContext
)
4892 PRESETBUS_PARAMS ResetParams
= (PRESETBUS_PARAMS
)ServiceContext
;
4893 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4895 /* Perform the bus reset */
4896 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ResetParams
->DeviceExtension
;
4897 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
,
4898 ResetParams
->PathId
);
4900 /* Set flags and start the timer */
4901 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
4902 DeviceExtension
->TimerCount
= 4;
4904 /* If miniport requested - give him a DPC */
4905 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4906 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
4913 // This function handles timeouts and other time delayed processing
4918 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
4919 // IN PVOID Context the Controller extension for the
4920 // controller the device is on
4923 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
4926 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4927 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4931 DPRINT("ScsiPortIoTimer()\n");
4933 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
4935 /* Protect with the spinlock */
4936 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4938 /* Check timeouts */
4939 if (DeviceExtension
->TimerCount
> 0)
4941 /* Decrease the timeout counter */
4942 DeviceExtension
->TimerCount
--;
4944 if (DeviceExtension
->TimerCount
== 0)
4946 /* Timeout, process it */
4947 if (KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4949 DeviceExtension
->DeviceObject
))
4951 DPRINT("Error happened during processing timeout, but nothing critical\n");
4955 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4957 /* We should exit now, since timeout is processed */
4961 /* Per-Lun scanning of timeouts is needed... */
4962 for (Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
4964 LunExtension
= DeviceExtension
->LunExtensionList
[Lun
];
4966 while (LunExtension
)
4968 if (LunExtension
->Flags
& LUNEX_BUSY
)
4970 if (!(LunExtension
->Flags
&
4971 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_FROZEN_QUEUE
)))
4973 DPRINT("Retrying busy request\n");
4975 /* Clear flags, and retry busy request */
4976 LunExtension
->Flags
&= ~(LUNEX_BUSY
| LUNEX_FULL_QUEUE
);
4977 Irp
= LunExtension
->BusyRequest
;
4979 /* Clearing busy request */
4980 LunExtension
->BusyRequest
= NULL
;
4982 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4984 IoStartPacket(DeviceObject
, Irp
, (PULONG
)NULL
, NULL
);
4986 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4989 else if (LunExtension
->RequestTimeout
== 0)
4991 RESETBUS_PARAMS ResetParams
;
4993 LunExtension
->RequestTimeout
= -1;
4995 DPRINT("Request timed out, resetting bus\n");
4997 /* Pass params to the bus reset routine */
4998 ResetParams
.PathId
= LunExtension
->PathId
;
4999 ResetParams
.DeviceExtension
= DeviceExtension
;
5001 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
5005 DPRINT1("Reset failed\n");
5008 else if (LunExtension
->RequestTimeout
> 0)
5010 /* Decrement the timeout counter */
5011 LunExtension
->RequestTimeout
--;
5014 LunExtension
= LunExtension
->Next
;
5018 /* Release the spinlock */
5019 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5022 /**********************************************************************
5027 * Builds the registry device map of all device which are attached
5028 * to the given SCSI HBA port. The device map is located at:
5029 * \Registry\Machine\DeviceMap\Scsi
5039 * Name of registry driver service key.
5046 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5047 PUNICODE_STRING RegistryPath
)
5049 PSCSI_PORT_LUN_EXTENSION LunExtension
;
5050 OBJECT_ATTRIBUTES ObjectAttributes
;
5051 UNICODE_STRING KeyName
;
5052 UNICODE_STRING ValueName
;
5053 WCHAR NameBuffer
[64];
5056 HANDLE ScsiPortKey
= NULL
;
5057 HANDLE ScsiBusKey
= NULL
;
5058 HANDLE ScsiInitiatorKey
= NULL
;
5059 HANDLE ScsiTargetKey
= NULL
;
5060 HANDLE ScsiLunKey
= NULL
;
5063 ULONG CurrentTarget
;
5070 DPRINT("SpiBuildDeviceMap() called\n");
5072 if (DeviceExtension
== NULL
|| RegistryPath
== NULL
)
5074 DPRINT1("Invalid parameter\n");
5075 return(STATUS_INVALID_PARAMETER
);
5078 /* Open or create the 'Scsi' subkey */
5079 RtlInitUnicodeString(&KeyName
,
5080 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
5081 InitializeObjectAttributes(&ObjectAttributes
,
5083 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
5086 Status
= ZwCreateKey(&ScsiKey
,
5091 REG_OPTION_VOLATILE
,
5093 if (!NT_SUCCESS(Status
))
5095 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5099 /* Create new 'Scsi Port X' subkey */
5100 DPRINT("Scsi Port %lu\n",
5101 DeviceExtension
->PortNumber
);
5103 swprintf(NameBuffer
,
5105 DeviceExtension
->PortNumber
);
5106 RtlInitUnicodeString(&KeyName
,
5108 InitializeObjectAttributes(&ObjectAttributes
,
5113 Status
= ZwCreateKey(&ScsiPortKey
,
5118 REG_OPTION_VOLATILE
,
5121 if (!NT_SUCCESS(Status
))
5123 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5128 * Create port-specific values
5131 /* Set 'DMA Enabled' (REG_DWORD) value */
5132 UlongData
= (ULONG
)!DeviceExtension
->PortCapabilities
.AdapterUsesPio
;
5133 DPRINT(" DMA Enabled = %s\n", (UlongData
) ? "TRUE" : "FALSE");
5134 RtlInitUnicodeString(&ValueName
,
5136 Status
= ZwSetValueKey(ScsiPortKey
,
5142 if (!NT_SUCCESS(Status
))
5144 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status
);
5145 ZwClose(ScsiPortKey
);
5149 /* Set 'Driver' (REG_SZ) value */
5150 DriverName
= wcsrchr(RegistryPath
->Buffer
, L
'\\') + 1;
5151 RtlInitUnicodeString(&ValueName
,
5153 Status
= ZwSetValueKey(ScsiPortKey
,
5158 (wcslen(DriverName
) + 1) * sizeof(WCHAR
));
5159 if (!NT_SUCCESS(Status
))
5161 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status
);
5162 ZwClose(ScsiPortKey
);
5166 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
5167 UlongData
= (ULONG
)DeviceExtension
->PortConfig
->BusInterruptLevel
;
5168 DPRINT(" Interrupt = %lu\n", UlongData
);
5169 RtlInitUnicodeString(&ValueName
,
5171 Status
= ZwSetValueKey(ScsiPortKey
,
5177 if (!NT_SUCCESS(Status
))
5179 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status
);
5180 ZwClose(ScsiPortKey
);
5184 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
5185 UlongData
= ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension
->PortConfig
->AccessRanges
)[0].RangeStart
);
5186 DPRINT(" IOAddress = %lx\n", UlongData
);
5187 RtlInitUnicodeString(&ValueName
,
5189 Status
= ZwSetValueKey(ScsiPortKey
,
5195 if (!NT_SUCCESS(Status
))
5197 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status
);
5198 ZwClose(ScsiPortKey
);
5202 /* Enumerate buses */
5203 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
->NumberOfBuses
; BusNumber
++)
5205 /* Create 'Scsi Bus X' key */
5206 DPRINT(" Scsi Bus %lu\n", BusNumber
);
5207 swprintf(NameBuffer
,
5210 RtlInitUnicodeString(&KeyName
,
5212 InitializeObjectAttributes(&ObjectAttributes
,
5217 Status
= ZwCreateKey(&ScsiBusKey
,
5222 REG_OPTION_VOLATILE
,
5224 if (!NT_SUCCESS(Status
))
5226 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5230 /* Create 'Initiator Id X' key */
5231 DPRINT(" Initiator Id %u\n",
5232 DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5233 swprintf(NameBuffer
,
5235 (unsigned int)(UCHAR
)DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5236 RtlInitUnicodeString(&KeyName
,
5238 InitializeObjectAttributes(&ObjectAttributes
,
5243 Status
= ZwCreateKey(&ScsiInitiatorKey
,
5248 REG_OPTION_VOLATILE
,
5250 if (!NT_SUCCESS(Status
))
5252 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5256 /* FIXME: Are there any initiator values (??) */
5258 ZwClose(ScsiInitiatorKey
);
5259 ScsiInitiatorKey
= NULL
;
5262 /* Enumerate targets */
5263 CurrentTarget
= (ULONG
)-1;
5264 ScsiTargetKey
= NULL
;
5265 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
5267 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
5269 LunExtension
= SpiGetLunExtension(DeviceExtension
,
5273 if (LunExtension
!= NULL
)
5275 if (Target
!= CurrentTarget
)
5277 /* Close old target key */
5278 if (ScsiTargetKey
!= NULL
)
5280 ZwClose(ScsiTargetKey
);
5281 ScsiTargetKey
= NULL
;
5284 /* Create 'Target Id X' key */
5285 DPRINT(" Target Id %lu\n", Target
);
5286 swprintf(NameBuffer
,
5289 RtlInitUnicodeString(&KeyName
,
5291 InitializeObjectAttributes(&ObjectAttributes
,
5296 Status
= ZwCreateKey(&ScsiTargetKey
,
5301 REG_OPTION_VOLATILE
,
5303 if (!NT_SUCCESS(Status
))
5305 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5309 CurrentTarget
= Target
;
5312 /* Create 'Logical Unit Id X' key */
5313 DPRINT(" Logical Unit Id %lu\n", Lun
);
5314 swprintf(NameBuffer
,
5315 L
"Logical Unit Id %lu",
5317 RtlInitUnicodeString(&KeyName
,
5319 InitializeObjectAttributes(&ObjectAttributes
,
5324 Status
= ZwCreateKey(&ScsiLunKey
,
5329 REG_OPTION_VOLATILE
,
5331 if (!NT_SUCCESS(Status
))
5333 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5337 /* Set 'Identifier' (REG_SZ) value */
5338 swprintf(NameBuffer
,
5340 LunExtension
->InquiryData
.VendorId
,
5341 LunExtension
->InquiryData
.ProductId
,
5342 LunExtension
->InquiryData
.ProductRevisionLevel
);
5343 DPRINT(" Identifier = '%S'\n", NameBuffer
);
5344 RtlInitUnicodeString(&ValueName
,
5346 Status
= ZwSetValueKey(ScsiLunKey
,
5351 (wcslen(NameBuffer
) + 1) * sizeof(WCHAR
));
5352 if (!NT_SUCCESS(Status
))
5354 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status
);
5358 /* Set 'Type' (REG_SZ) value */
5359 switch (LunExtension
->InquiryData
.DeviceType
)
5362 TypeName
= L
"DiskPeripheral";
5365 TypeName
= L
"TapePeripheral";
5368 TypeName
= L
"PrinterPeripheral";
5371 TypeName
= L
"WormPeripheral";
5374 TypeName
= L
"CdRomPeripheral";
5377 TypeName
= L
"ScannerPeripheral";
5380 TypeName
= L
"OpticalDiskPeripheral";
5383 TypeName
= L
"MediumChangerPeripheral";
5386 TypeName
= L
"CommunicationPeripheral";
5389 TypeName
= L
"OtherPeripheral";
5392 DPRINT(" Type = '%S'\n", TypeName
);
5393 RtlInitUnicodeString(&ValueName
,
5395 Status
= ZwSetValueKey(ScsiLunKey
,
5400 (wcslen(TypeName
) + 1) * sizeof(WCHAR
));
5401 if (!NT_SUCCESS(Status
))
5403 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status
);
5407 ZwClose(ScsiLunKey
);
5412 /* Close old target key */
5413 if (ScsiTargetKey
!= NULL
)
5415 ZwClose(ScsiTargetKey
);
5416 ScsiTargetKey
= NULL
;
5420 ZwClose(ScsiBusKey
);
5425 if (ScsiLunKey
!= NULL
)
5426 ZwClose (ScsiLunKey
);
5428 if (ScsiInitiatorKey
!= NULL
)
5429 ZwClose (ScsiInitiatorKey
);
5431 if (ScsiTargetKey
!= NULL
)
5432 ZwClose (ScsiTargetKey
);
5434 if (ScsiBusKey
!= NULL
)
5435 ZwClose (ScsiBusKey
);
5437 if (ScsiPortKey
!= NULL
)
5438 ZwClose (ScsiPortKey
);
5440 DPRINT("SpiBuildDeviceMap() done\n");
5447 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
5448 IN PVOID DeviceObject
,
5449 IN PVOID SystemArgument1
,
5450 IN PVOID SystemArgument2
)
5452 DPRINT1("Miniport timer DPC\n");
5456 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5457 PHW_INITIALIZATION_DATA HwInitData
,
5458 PCONFIGURATION_INFO InternalConfigInfo
,
5459 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5462 UNICODE_STRING UnicodeString
;
5463 OBJECT_ATTRIBUTES ObjectAttributes
;
5464 PCONFIGURATION_INFORMATION DdkConfigInformation
;
5465 HANDLE RootKey
, Key
;
5467 WCHAR DeviceBuffer
[16];
5468 WCHAR StrBuffer
[512];
5472 /* Zero out the struct if told so */
5475 /* First zero the portconfig */
5476 RtlZeroMemory(ConfigInfo
, sizeof(PORT_CONFIGURATION_INFORMATION
));
5478 /* Then access ranges */
5479 RtlZeroMemory(InternalConfigInfo
->AccessRanges
,
5480 HwInitData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
5482 /* Initialize the struct */
5483 ConfigInfo
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
5484 ConfigInfo
->AdapterInterfaceType
= HwInitData
->AdapterInterfaceType
;
5485 ConfigInfo
->InterruptMode
= Latched
;
5486 ConfigInfo
->DmaChannel
= SP_UNINITIALIZED_VALUE
;
5487 ConfigInfo
->DmaPort
= SP_UNINITIALIZED_VALUE
;
5488 ConfigInfo
->MaximumTransferLength
= SP_UNINITIALIZED_VALUE
;
5489 ConfigInfo
->NumberOfAccessRanges
= HwInitData
->NumberOfAccessRanges
;
5490 ConfigInfo
->MaximumNumberOfTargets
= 8;
5492 /* Store parameters */
5493 ConfigInfo
->NeedPhysicalAddresses
= HwInitData
->NeedPhysicalAddresses
;
5494 ConfigInfo
->MapBuffers
= HwInitData
->MapBuffers
;
5495 ConfigInfo
->AutoRequestSense
= HwInitData
->AutoRequestSense
;
5496 ConfigInfo
->ReceiveEvent
= HwInitData
->ReceiveEvent
;
5497 ConfigInfo
->TaggedQueuing
= HwInitData
->TaggedQueuing
;
5498 ConfigInfo
->MultipleRequestPerLu
= HwInitData
->MultipleRequestPerLu
;
5500 /* Get the disk usage */
5501 DdkConfigInformation
= IoGetConfigurationInformation();
5502 ConfigInfo
->AtdiskPrimaryClaimed
= DdkConfigInformation
->AtDiskPrimaryAddressClaimed
;
5503 ConfigInfo
->AtdiskSecondaryClaimed
= DdkConfigInformation
->AtDiskSecondaryAddressClaimed
;
5505 /* Initiator bus id is not set */
5506 for (Bus
= 0; Bus
< 8; Bus
++)
5507 ConfigInfo
->InitiatorBusId
[Bus
] = (CCHAR
)SP_UNINITIALIZED_VALUE
;
5510 ConfigInfo
->NumberOfPhysicalBreaks
= 17;
5512 /* Clear this information */
5513 InternalConfigInfo
->DisableTaggedQueueing
= FALSE
;
5514 InternalConfigInfo
->DisableMultipleLun
= FALSE
;
5516 /* Store Bus Number */
5517 ConfigInfo
->SystemIoBusNumber
= InternalConfigInfo
->BusNumber
;
5521 if (ConfigInfo
->AdapterInterfaceType
== Internal
)
5523 /* Open registry key for HW database */
5524 InitializeObjectAttributes(&ObjectAttributes
,
5525 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
5526 OBJ_CASE_INSENSITIVE
,
5530 Status
= ZwOpenKey(&RootKey
,
5534 if (NT_SUCCESS(Status
))
5536 /* Create name for it */
5537 swprintf(StrBuffer
, L
"ScsiAdapter\\%lu",
5538 InternalConfigInfo
->AdapterNumber
);
5540 RtlInitUnicodeString(&UnicodeString
, StrBuffer
);
5542 /* Open device key */
5543 InitializeObjectAttributes(&ObjectAttributes
,
5545 OBJ_CASE_INSENSITIVE
,
5549 Status
= ZwOpenKey(&Key
,
5555 if (NT_SUCCESS(Status
))
5557 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5559 DPRINT("Hardware info found at %S\n", StrBuffer
);
5562 SpiParseDeviceInfo(DeviceExtension
,
5568 InternalConfigInfo
->BusNumber
= 0;
5572 /* Try the next adapter */
5573 InternalConfigInfo
->AdapterNumber
++;
5579 /* Info was not found, exit */
5580 return STATUS_DEVICE_DOES_NOT_EXIST
;
5586 /* Look at device params */
5588 if (InternalConfigInfo
->Parameter
)
5590 ExFreePool(InternalConfigInfo
->Parameter
);
5591 InternalConfigInfo
->Parameter
= NULL
;
5594 if (InternalConfigInfo
->ServiceKey
!= NULL
)
5596 swprintf(DeviceBuffer
, L
"Device%lu", InternalConfigInfo
->AdapterNumber
);
5597 RtlInitUnicodeString(&UnicodeString
, DeviceBuffer
);
5599 /* Open the service key */
5600 InitializeObjectAttributes(&ObjectAttributes
,
5602 OBJ_CASE_INSENSITIVE
,
5603 InternalConfigInfo
->ServiceKey
,
5606 Status
= ZwOpenKey(&Key
,
5611 /* Parse device key */
5612 if (InternalConfigInfo
->DeviceKey
!= NULL
)
5614 SpiParseDeviceInfo(DeviceExtension
,
5615 InternalConfigInfo
->DeviceKey
,
5621 /* Then parse hw info */
5624 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5626 SpiParseDeviceInfo(DeviceExtension
,
5637 /* Adapter not found, go try the next one */
5638 InternalConfigInfo
->AdapterNumber
++;
5647 /* Update the last adapter number */
5648 InternalConfigInfo
->LastAdapterNumber
= InternalConfigInfo
->AdapterNumber
;
5650 /* Do we have this kind of bus at all? */
5652 Status
= IoQueryDeviceDescription(&HwInitData
->AdapterInterfaceType
,
5653 &InternalConfigInfo
->BusNumber
,
5658 SpQueryDeviceCallout
,
5661 /* This bus was not found */
5664 INTERFACE_TYPE InterfaceType
= Eisa
;
5666 /* Check for EISA */
5667 if (HwInitData
->AdapterInterfaceType
== Isa
)
5669 Status
= IoQueryDeviceDescription(&InterfaceType
,
5670 &InternalConfigInfo
->BusNumber
,
5675 SpQueryDeviceCallout
,
5678 /* Return respectively */
5680 return STATUS_SUCCESS
;
5682 return STATUS_DEVICE_DOES_NOT_EXIST
;
5686 return STATUS_DEVICE_DOES_NOT_EXIST
;
5691 return STATUS_SUCCESS
;
5696 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5698 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5699 IN PCONFIGURATION_INFO InternalConfigInfo
,
5702 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
5703 PCM_FULL_RESOURCE_DESCRIPTOR FullResource
;
5704 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
5705 PCM_SCSI_DEVICE_DATA ScsiDeviceData
;
5706 ULONG Length
, Count
;
5707 ULONG Index
= 0, RangeCount
= 0;
5708 UNICODE_STRING UnicodeString
;
5709 ANSI_STRING AnsiString
;
5710 NTSTATUS Status
= STATUS_SUCCESS
;
5713 KeyValueInformation
= (PKEY_VALUE_FULL_INFORMATION
) Buffer
;
5715 /* Loop through all values in the device node */
5718 Status
= ZwEnumerateValueKey(Key
,
5720 KeyValueFullInformation
,
5725 if (!NT_SUCCESS(Status
))
5730 /* Length for DWORD is ok? */
5731 if (KeyValueInformation
->Type
== REG_DWORD
&&
5732 KeyValueInformation
->DataLength
!= sizeof(ULONG
))
5737 /* Get MaximumLogicalUnit */
5738 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumLogicalUnit",
5739 KeyValueInformation
->NameLength
/2) == 0)
5742 if (KeyValueInformation
->Type
!= REG_DWORD
)
5744 DPRINT("Bad data type for MaximumLogicalUnit\n");
5748 DeviceExtension
->MaxLunCount
= *((PUCHAR
)
5749 (Buffer
+ KeyValueInformation
->DataOffset
));
5751 /* Check / reset if needed */
5752 if (DeviceExtension
->MaxLunCount
> SCSI_MAXIMUM_LOGICAL_UNITS
)
5753 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
5755 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension
->MaxLunCount
);
5758 /* Get InitiatorTargetId */
5759 if (_wcsnicmp(KeyValueInformation
->Name
, L
"InitiatorTargetId",
5760 KeyValueInformation
->NameLength
/ 2) == 0)
5763 if (KeyValueInformation
->Type
!= REG_DWORD
)
5765 DPRINT("Bad data type for InitiatorTargetId\n");
5769 ConfigInfo
->InitiatorBusId
[0] = *((PUCHAR
)
5770 (Buffer
+ KeyValueInformation
->DataOffset
));
5772 /* Check / reset if needed */
5773 if (ConfigInfo
->InitiatorBusId
[0] > ConfigInfo
->MaximumNumberOfTargets
- 1)
5774 ConfigInfo
->InitiatorBusId
[0] = (CCHAR
)-1;
5776 DPRINT("InitiatorTargetId = %d\n", ConfigInfo
->InitiatorBusId
[0]);
5780 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ScsiDebug",
5781 KeyValueInformation
->NameLength
/2) == 0)
5783 DPRINT("ScsiDebug key not supported\n");
5786 /* Check for a breakpoint */
5787 if (_wcsnicmp(KeyValueInformation
->Name
, L
"BreakPointOnEntry",
5788 KeyValueInformation
->NameLength
/2) == 0)
5790 DPRINT1("Breakpoint on entry requested!\n");
5794 /* Get DisableSynchronousTransfers */
5795 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableSynchronousTransfers",
5796 KeyValueInformation
->NameLength
/2) == 0)
5798 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5799 DPRINT("Synch transfers disabled\n");
5802 /* Get DisableDisconnects */
5803 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableDisconnects",
5804 KeyValueInformation
->NameLength
/2) == 0)
5806 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
5807 DPRINT("Disconnects disabled\n");
5810 /* Get DisableTaggedQueuing */
5811 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableTaggedQueuing",
5812 KeyValueInformation
->NameLength
/2) == 0)
5814 InternalConfigInfo
->DisableTaggedQueueing
= TRUE
;
5815 DPRINT("Tagged queueing disabled\n");
5818 /* Get DisableMultipleRequests */
5819 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableMultipleRequests",
5820 KeyValueInformation
->NameLength
/2) == 0)
5822 InternalConfigInfo
->DisableMultipleLun
= TRUE
;
5823 DPRINT("Multiple requests disabled\n");
5826 /* Get DriverParameters */
5827 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DriverParameters",
5828 KeyValueInformation
->NameLength
/2) == 0)
5830 /* Skip if nothing */
5831 if (KeyValueInformation
->DataLength
== 0)
5834 /* If there was something previously allocated - free it */
5835 if (InternalConfigInfo
->Parameter
!= NULL
)
5836 ExFreePool(InternalConfigInfo
->Parameter
);
5839 InternalConfigInfo
->Parameter
= ExAllocatePoolWithTag(NonPagedPool
,
5840 KeyValueInformation
->DataLength
, TAG_SCSIPORT
);
5842 if (InternalConfigInfo
->Parameter
!= NULL
)
5844 if (KeyValueInformation
->Type
!= REG_SZ
)
5848 InternalConfigInfo
->Parameter
,
5849 (PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
,
5850 KeyValueInformation
->DataLength
);
5854 /* If it's a unicode string, convert it to ansi */
5855 UnicodeString
.Length
= (USHORT
)KeyValueInformation
->DataLength
;
5856 UnicodeString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
5857 UnicodeString
.Buffer
=
5858 (PWSTR
)((PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
5860 AnsiString
.Length
= 0;
5861 AnsiString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
5862 AnsiString
.Buffer
= (PCHAR
)InternalConfigInfo
->Parameter
;
5864 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
5868 /* In case of error, free the allocated space */
5869 if (!NT_SUCCESS(Status
))
5871 ExFreePool(InternalConfigInfo
->Parameter
);
5872 InternalConfigInfo
->Parameter
= NULL
;
5878 DPRINT("Found driver parameter\n");
5881 /* Get MaximumSGList */
5882 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumSGList",
5883 KeyValueInformation
->NameLength
/2) == 0)
5885 if (KeyValueInformation
->Type
!= REG_DWORD
)
5887 DPRINT("Bad data type for MaximumSGList\n");
5891 ConfigInfo
->NumberOfPhysicalBreaks
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
5894 if (ConfigInfo
->NumberOfPhysicalBreaks
> SCSI_MAXIMUM_PHYSICAL_BREAKS
)
5896 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MAXIMUM_PHYSICAL_BREAKS
;
5898 else if (ConfigInfo
->NumberOfPhysicalBreaks
< SCSI_MINIMUM_PHYSICAL_BREAKS
)
5900 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MINIMUM_PHYSICAL_BREAKS
;
5903 DPRINT("MaximumSGList = %d\n", ConfigInfo
->NumberOfPhysicalBreaks
);
5906 /* Get NumberOfRequests */
5907 if (_wcsnicmp(KeyValueInformation
->Name
, L
"NumberOfRequests",
5908 KeyValueInformation
->NameLength
/2) == 0)
5910 if (KeyValueInformation
->Type
!= REG_DWORD
)
5912 DPRINT("NumberOfRequests has wrong data type\n");
5916 DeviceExtension
->RequestsNumber
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
5919 if (DeviceExtension
->RequestsNumber
< 16)
5921 DeviceExtension
->RequestsNumber
= 16;
5923 else if (DeviceExtension
->RequestsNumber
> 512)
5925 DeviceExtension
->RequestsNumber
= 512;
5928 DPRINT("Number Of Requests = %d\n", DeviceExtension
->RequestsNumber
);
5931 /* Get resource list */
5932 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ResourceList",
5933 KeyValueInformation
->NameLength
/2) == 0 ||
5934 _wcsnicmp(KeyValueInformation
->Name
, L
"Configuration Data",
5935 KeyValueInformation
->NameLength
/2) == 0 )
5937 if (KeyValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
||
5938 KeyValueInformation
->DataLength
< sizeof(REG_FULL_RESOURCE_DESCRIPTOR
))
5940 DPRINT("Bad data type for ResourceList\n");
5945 DPRINT("Found ResourceList\n");
5948 FullResource
= (PCM_FULL_RESOURCE_DESCRIPTOR
)(Buffer
+ KeyValueInformation
->DataOffset
);
5950 /* Copy some info from it */
5951 InternalConfigInfo
->BusNumber
= FullResource
->BusNumber
;
5952 ConfigInfo
->SystemIoBusNumber
= FullResource
->BusNumber
;
5954 /* Loop through it */
5955 for (Count
= 0; Count
< FullResource
->PartialResourceList
.Count
; Count
++)
5957 /* Get partial descriptor */
5959 &FullResource
->PartialResourceList
.PartialDescriptors
[Count
];
5961 /* Check datalength */
5962 if ((ULONG
)((PCHAR
)(PartialDescriptor
+ 1) -
5963 (PCHAR
)FullResource
) > KeyValueInformation
->DataLength
)
5965 DPRINT("Resource data is of incorrect size\n");
5969 switch (PartialDescriptor
->Type
)
5971 case CmResourceTypePort
:
5972 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
5974 DPRINT("Too many access ranges\n");
5978 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= FALSE
;
5979 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Port
.Start
;
5980 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Port
.Length
;
5985 case CmResourceTypeMemory
:
5986 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
5988 DPRINT("Too many access ranges\n");
5992 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= TRUE
;
5993 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Memory
.Start
;
5994 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Memory
.Length
;
5999 case CmResourceTypeInterrupt
:
6000 ConfigInfo
->BusInterruptLevel
=
6001 PartialDescriptor
->u
.Interrupt
.Level
;
6003 ConfigInfo
->BusInterruptVector
=
6004 PartialDescriptor
->u
.Interrupt
.Vector
;
6007 case CmResourceTypeDma
:
6008 ConfigInfo
->DmaChannel
= PartialDescriptor
->u
.Dma
.Channel
;
6009 ConfigInfo
->DmaPort
= PartialDescriptor
->u
.Dma
.Port
;
6012 case CmResourceTypeDeviceSpecific
:
6013 if (PartialDescriptor
->u
.DeviceSpecificData
.DataSize
<
6014 sizeof(CM_SCSI_DEVICE_DATA
) ||
6015 (PCHAR
) (PartialDescriptor
+ 1) - (PCHAR
)FullResource
+
6016 PartialDescriptor
->u
.DeviceSpecificData
.DataSize
>
6017 KeyValueInformation
->DataLength
)
6019 DPRINT("Resource data length is incorrect");
6023 /* Set only one field from it */
6024 ScsiDeviceData
= (PCM_SCSI_DEVICE_DATA
) (PartialDescriptor
+1);
6025 ConfigInfo
->InitiatorBusId
[0] = ScsiDeviceData
->HostIdentifier
;
6036 SpQueryDeviceCallout(IN PVOID Context
,
6037 IN PUNICODE_STRING PathName
,
6038 IN INTERFACE_TYPE BusType
,
6040 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
6041 IN CONFIGURATION_TYPE ControllerType
,
6042 IN ULONG ControllerNumber
,
6043 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
6044 IN CONFIGURATION_TYPE PeripheralType
,
6045 IN ULONG PeripheralNumber
,
6046 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
6048 PBOOLEAN Found
= (PBOOLEAN
)Context
;
6049 /* We just set our Found variable to TRUE */
6052 return STATUS_SUCCESS
;
6059 SpiStatusSrbToNt(UCHAR SrbStatus
)
6061 switch (SRB_STATUS(SrbStatus
))
6063 case SRB_STATUS_TIMEOUT
:
6064 case SRB_STATUS_COMMAND_TIMEOUT
:
6065 return STATUS_IO_TIMEOUT
;
6067 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH
:
6068 case SRB_STATUS_BAD_FUNCTION
:
6069 return STATUS_INVALID_DEVICE_REQUEST
;
6071 case SRB_STATUS_NO_DEVICE
:
6072 case SRB_STATUS_INVALID_LUN
:
6073 case SRB_STATUS_INVALID_TARGET_ID
:
6074 case SRB_STATUS_NO_HBA
:
6075 return STATUS_DEVICE_DOES_NOT_EXIST
;
6077 case SRB_STATUS_DATA_OVERRUN
:
6078 return STATUS_BUFFER_OVERFLOW
;
6080 case SRB_STATUS_SELECTION_TIMEOUT
:
6081 return STATUS_DEVICE_NOT_CONNECTED
;
6084 return STATUS_IO_DEVICE_ERROR
;
6087 return STATUS_IO_DEVICE_ERROR
;
6091 #undef ScsiPortConvertPhysicalAddressToUlong
6096 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
6098 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
6099 return(Address
.u
.LowPart
);