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.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS Storage Stack
22 * FILE: drivers/storage/scsiport/scsiport.c
23 * PURPOSE: SCSI port driver
24 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
25 * Aleksey Bragin (aleksey reactos org)
28 /* INCLUDES *****************************************************************/
44 #include "scsiport_int.h"
51 ULONG InternalDebugLevel
= 0x00;
53 /* TYPES *********************************************************************/
55 /* GLOBALS *******************************************************************/
58 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
59 IN PDEVICE_OBJECT DeviceObject
,
60 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
61 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
62 IN PUNICODE_STRING RegistryPath
,
64 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
);
66 static NTSTATUS STDCALL
67 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
70 static DRIVER_DISPATCH ScsiPortDispatchScsi
;
71 static NTSTATUS STDCALL
72 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
75 static NTSTATUS STDCALL
76 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
79 static DRIVER_STARTIO ScsiPortStartIo
;
81 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
84 static BOOLEAN STDCALL
85 ScsiPortStartPacket(IN OUT PVOID Context
);
89 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
90 PVOID MapRegisterBase
, PVOID Context
);
92 static PSCSI_PORT_LUN_EXTENSION
93 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
95 static PSCSI_PORT_LUN_EXTENSION
96 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
101 static PSCSI_REQUEST_BLOCK_INFO
102 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
103 PSCSI_PORT_LUN_EXTENSION LunExtension
,
104 PSCSI_REQUEST_BLOCK Srb
);
107 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
108 IN PSCSI_LUN_INFO LunInfo
);
111 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
114 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
117 static PSCSI_REQUEST_BLOCK_INFO
118 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
124 static BOOLEAN STDCALL
125 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
126 IN PVOID ServiceContext
);
129 ScsiPortDpcForIsr(IN PKDPC Dpc
,
130 IN PDEVICE_OBJECT DpcDeviceObject
,
132 IN PVOID DpcContext
);
135 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
140 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject
,
142 IN PVOID MapRegisterBase
,
146 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
147 PUNICODE_STRING RegistryPath
);
150 SpiStatusSrbToNt(UCHAR SrbStatus
);
153 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
154 IN PSCSI_REQUEST_BLOCK Srb
);
156 static IO_COMPLETION_ROUTINE SpiCompletionRoutine
;
158 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
164 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
165 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
166 OUT PBOOLEAN NeedToCallStartIo
);
169 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
170 IN PSCSI_PORT_LUN_EXTENSION LunExtension
);
173 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
174 IN PVOID DeviceObject
,
175 IN PVOID SystemArgument1
,
176 IN PVOID SystemArgument2
);
179 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
180 PHW_INITIALIZATION_DATA HwInitData
,
181 PCONFIGURATION_INFO InternalConfigInfo
,
182 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
186 SpQueryDeviceCallout(IN PVOID Context
,
187 IN PUNICODE_STRING PathName
,
188 IN INTERFACE_TYPE BusType
,
190 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
191 IN CONFIGURATION_TYPE ControllerType
,
192 IN ULONG ControllerNumber
,
193 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
194 IN CONFIGURATION_TYPE PeripheralType
,
195 IN ULONG PeripheralNumber
,
196 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
);
199 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
201 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
202 IN PCONFIGURATION_INFO InternalConfigInfo
,
206 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
207 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
208 IN PPORT_CONFIGURATION_INFORMATION PortConfig
);
210 static PCM_RESOURCE_LIST
211 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
212 PPORT_CONFIGURATION_INFORMATION PortConfig
);
215 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
218 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
222 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
);
226 /* FUNCTIONS *****************************************************************/
228 /**********************************************************************
233 * This function initializes the driver.
240 * System allocated Driver Object for this driver.
243 * Name of registry driver service key.
250 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
251 IN PUNICODE_STRING RegistryPath
)
253 DPRINT("ScsiPort Driver %s\n", VERSION
);
254 return(STATUS_SUCCESS
);
258 /**********************************************************************
263 * Prints debugging messages.
270 * Debug level of the given message.
273 * Pointer to printf()-compatible format string.
276 Additional output data (see printf()).
285 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
286 IN PCHAR DebugMessage
,
292 if (DebugPrintLevel
> InternalDebugLevel
)
295 va_start(ap
, DebugMessage
);
296 vsprintf(Buffer
, DebugMessage
, ap
);
307 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
313 DPRINT("ScsiPortCompleteRequest()\n");
321 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
323 DPRINT("ScsiPortFlushDma()\n");
332 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
333 IN PVOID MappedAddress
)
335 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
336 PMAPPED_ADDRESS NextMa
, LastMa
;
338 //DPRINT("ScsiPortFreeDeviceBase() called\n");
340 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
341 SCSI_PORT_DEVICE_EXTENSION
,
342 MiniPortDeviceExtension
);
344 /* Initialize our pointers */
345 NextMa
= DeviceExtension
->MappedAddressList
;
350 if (NextMa
->MappedAddress
== MappedAddress
)
353 MmUnmapIoSpace(MappedAddress
, NextMa
->NumberOfBytes
);
355 /* Remove it from the list */
356 if (NextMa
== DeviceExtension
->MappedAddressList
)
358 /* Remove the first entry */
359 DeviceExtension
->MappedAddressList
= NextMa
->NextMappedAddress
;
363 LastMa
->NextMappedAddress
= NextMa
->NextMappedAddress
;
366 /* Free the resources and quit */
374 NextMa
= NextMa
->NextMappedAddress
;
384 ScsiPortGetBusData(IN PVOID DeviceExtension
,
385 IN ULONG BusDataType
,
386 IN ULONG SystemIoBusNumber
,
391 DPRINT("ScsiPortGetBusData()\n");
395 /* If Length is non-zero, just forward the call to
396 HalGetBusData() function */
397 return HalGetBusData(BusDataType
,
404 /* We have a more complex case here */
413 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
414 IN ULONG BusDataType
,
415 IN ULONG SystemIoBusNumber
,
421 DPRINT("ScsiPortSetBusDataByOffset()\n");
422 return HalSetBusDataByOffset(BusDataType
,
434 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
435 IN INTERFACE_TYPE BusType
,
436 IN ULONG SystemIoBusNumber
,
437 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
438 IN ULONG NumberOfBytes
,
439 IN BOOLEAN InIoSpace
)
441 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
442 PHYSICAL_ADDRESS TranslatedAddress
;
443 PMAPPED_ADDRESS DeviceBase
;
447 //DPRINT ("ScsiPortGetDeviceBase() called\n");
449 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
450 SCSI_PORT_DEVICE_EXTENSION
,
451 MiniPortDeviceExtension
);
453 AddressSpace
= (ULONG
)InIoSpace
;
454 if (HalTranslateBusAddress(BusType
,
458 &TranslatedAddress
) == FALSE
)
464 if (AddressSpace
!= 0)
465 return((PVOID
)TranslatedAddress
.u
.LowPart
);
467 MappedAddress
= MmMapIoSpace(TranslatedAddress
,
471 DeviceBase
= ExAllocatePoolWithTag(NonPagedPool
,
472 sizeof(MAPPED_ADDRESS
), TAG_SCSIPORT
);
474 if (DeviceBase
== NULL
)
475 return MappedAddress
;
477 DeviceBase
->MappedAddress
= MappedAddress
;
478 DeviceBase
->NumberOfBytes
= NumberOfBytes
;
479 DeviceBase
->IoAddress
= IoAddress
;
480 DeviceBase
->BusNumber
= SystemIoBusNumber
;
482 /* Link it to the Device Extension list */
483 DeviceBase
->NextMappedAddress
= DeviceExtension
->MappedAddressList
;
484 DeviceExtension
->MappedAddressList
= DeviceBase
;
486 return MappedAddress
;
493 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
500 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
501 PSCSI_PORT_LUN_EXTENSION LunExtension
;
504 DPRINT("ScsiPortGetLogicalUnit() called\n");
506 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
507 SCSI_PORT_DEVICE_EXTENSION
,
508 MiniPortDeviceExtension
);
509 if (IsListEmpty(&DeviceExtension
->LunExtensionListHead
))
512 Entry
= DeviceExtension
->LunExtensionListHead
.Flink
;
513 while (Entry
!= &DeviceExtension
->LunExtensionListHead
)
515 LunExtension
= CONTAINING_RECORD(Entry
,
516 SCSI_PORT_LUN_EXTENSION
,
518 if (LunExtension
->PathId
== PathId
&&
519 LunExtension
->TargetId
== TargetId
&&
520 LunExtension
->Lun
== Lun
)
522 return (PVOID
)&LunExtension
->MiniportLunExtension
;
525 Entry
= Entry
->Flink
;
535 SCSI_PHYSICAL_ADDRESS STDCALL
536 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
537 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
538 IN PVOID VirtualAddress
,
541 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
542 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
543 ULONG BufferLength
= 0;
545 PSCSI_SG_ADDRESS SGList
;
546 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
548 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
549 HwDeviceExtension
, Srb
, VirtualAddress
, Length
);
551 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
552 SCSI_PORT_DEVICE_EXTENSION
,
553 MiniPortDeviceExtension
);
555 if (Srb
== NULL
|| Srb
->SenseInfoBuffer
== VirtualAddress
)
557 /* Simply look it up in the allocated common buffer */
558 Offset
= (PUCHAR
)VirtualAddress
- (PUCHAR
)DeviceExtension
->SrbExtensionBuffer
;
560 BufferLength
= DeviceExtension
->CommonBufferLength
- Offset
;
561 PhysicalAddress
.QuadPart
= DeviceExtension
->PhysicalAddress
.QuadPart
+ Offset
;
563 else if (DeviceExtension
->MapRegisters
)
565 /* Scatter-gather list must be used */
566 SrbInfo
= SpiGetSrbData(DeviceExtension
,
572 SGList
= SrbInfo
->ScatterGather
;
574 /* Find needed item in the SG list */
575 Offset
= (PCHAR
)VirtualAddress
- (PCHAR
)Srb
->DataBuffer
;
576 while (Offset
>= SGList
->Length
)
578 Offset
-= SGList
->Length
;
582 /* We're done, store length and physical address */
583 BufferLength
= SGList
->Length
- Offset
;
584 PhysicalAddress
.QuadPart
= SGList
->PhysicalAddress
.QuadPart
+ Offset
;
590 PhysicalAddress
.QuadPart
= (LONGLONG
)(SP_UNINITIALIZED_VALUE
);
593 *Length
= BufferLength
;
594 return PhysicalAddress
;
601 PSCSI_REQUEST_BLOCK STDCALL
602 ScsiPortGetSrb(IN PVOID DeviceExtension
,
608 DPRINT1("ScsiPortGetSrb() unimplemented\n");
618 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
619 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
620 IN ULONG NumberOfBytes
)
622 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
623 DEVICE_DESCRIPTION DeviceDescription
;
624 ULONG MapRegistersCount
;
627 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
628 HwDeviceExtension
, ConfigInfo
, NumberOfBytes
);
630 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
631 SCSI_PORT_DEVICE_EXTENSION
,
632 MiniPortDeviceExtension
);
634 /* Check for allocated common DMA buffer */
635 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
)
637 DPRINT1("The HBA has already got a common DMA buffer!\n");
641 /* Check for DMA adapter object */
642 if (DeviceExtension
->AdapterObject
== NULL
)
644 /* Initialize DMA adapter description */
645 RtlZeroMemory(&DeviceDescription
, sizeof(DEVICE_DESCRIPTION
));
647 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
648 DeviceDescription
.Master
= ConfigInfo
->Master
;
649 DeviceDescription
.ScatterGather
= ConfigInfo
->ScatterGather
;
650 DeviceDescription
.DemandMode
= ConfigInfo
->DemandMode
;
651 DeviceDescription
.Dma32BitAddresses
= ConfigInfo
->Dma32BitAddresses
;
652 DeviceDescription
.BusNumber
= ConfigInfo
->SystemIoBusNumber
;
653 DeviceDescription
.DmaChannel
= ConfigInfo
->DmaChannel
;
654 DeviceDescription
.InterfaceType
= ConfigInfo
->AdapterInterfaceType
;
655 DeviceDescription
.DmaWidth
= ConfigInfo
->DmaWidth
;
656 DeviceDescription
.DmaSpeed
= ConfigInfo
->DmaSpeed
;
657 DeviceDescription
.MaximumLength
= ConfigInfo
->MaximumTransferLength
;
658 DeviceDescription
.DmaPort
= ConfigInfo
->DmaPort
;
660 /* Get a DMA adapter object */
661 DeviceExtension
->AdapterObject
=
662 HalGetAdapter(&DeviceDescription
, &MapRegistersCount
);
664 /* Fail in case of error */
665 if (DeviceExtension
->AdapterObject
== NULL
)
667 DPRINT1("HalGetAdapter() failed\n");
671 /* Set number of physical breaks */
672 if (ConfigInfo
->NumberOfPhysicalBreaks
!= 0 &&
673 MapRegistersCount
> ConfigInfo
->NumberOfPhysicalBreaks
)
675 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
=
676 ConfigInfo
->NumberOfPhysicalBreaks
;
680 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
= MapRegistersCount
;
684 /* Update auto request sense feature */
685 DeviceExtension
->SupportsAutoSense
= ConfigInfo
->AutoRequestSense
;
687 /* Update Srb extension size */
688 if (DeviceExtension
->SrbExtensionSize
!= ConfigInfo
->SrbExtensionSize
)
689 DeviceExtension
->SrbExtensionSize
= ConfigInfo
->SrbExtensionSize
;
691 /* Update Srb extension alloc flag */
692 if (ConfigInfo
->AutoRequestSense
|| DeviceExtension
->SrbExtensionSize
)
693 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
695 /* Allocate a common DMA buffer */
696 Status
= SpiAllocateCommonBuffer(DeviceExtension
, NumberOfBytes
);
698 if (!NT_SUCCESS(Status
))
700 DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status
);
704 return DeviceExtension
->NonCachedExtension
;
708 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
)
710 PVOID
*SrbExtension
, CommonBuffer
;
711 ULONG CommonBufferLength
, BufSize
;
713 /* If size is 0, set it to 16 */
714 if (!DeviceExtension
->SrbExtensionSize
)
715 DeviceExtension
->SrbExtensionSize
= 16;
718 BufSize
= DeviceExtension
->SrbExtensionSize
;
720 /* Add autosense data size if needed */
721 if (DeviceExtension
->SupportsAutoSense
)
722 BufSize
+= sizeof(SENSE_DATA
);
726 BufSize
= (BufSize
+ sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
728 /* Sum up into the total common buffer length, and round it to page size */
730 ROUND_TO_PAGES(NonCachedSize
+ BufSize
* DeviceExtension
->RequestsNumber
);
733 if (!DeviceExtension
->AdapterObject
)
735 /* From nonpaged pool if there is no DMA */
736 CommonBuffer
= ExAllocatePoolWithTag(NonPagedPool
, CommonBufferLength
, TAG_SCSIPORT
);
740 /* Perform a full request since we have a DMA adapter*/
741 CommonBuffer
= HalAllocateCommonBuffer(DeviceExtension
->AdapterObject
,
743 &DeviceExtension
->PhysicalAddress
,
747 /* Fail in case of error */
749 return STATUS_INSUFFICIENT_RESOURCES
;
752 RtlZeroMemory(CommonBuffer
, CommonBufferLength
);
754 /* Store its size in Device Extension */
755 DeviceExtension
->CommonBufferLength
= CommonBufferLength
;
757 /* SrbExtension buffer is located at the beginning of the buffer */
758 DeviceExtension
->SrbExtensionBuffer
= CommonBuffer
;
760 /* Non-cached extension buffer is located at the end of
764 CommonBufferLength
-= NonCachedSize
;
765 DeviceExtension
->NonCachedExtension
= (PUCHAR
)CommonBuffer
+ CommonBufferLength
;
769 DeviceExtension
->NonCachedExtension
= NULL
;
772 if (DeviceExtension
->NeedSrbExtensionAlloc
)
774 /* Look up how many SRB data structures we need */
775 DeviceExtension
->SrbDataCount
= CommonBufferLength
/ BufSize
;
777 /* Initialize the free SRB extensions list */
778 SrbExtension
= (PVOID
*)CommonBuffer
;
779 DeviceExtension
->FreeSrbExtensions
= SrbExtension
;
781 /* Fill the remainding pointers (if we have more than 1 SRB) */
782 while (CommonBufferLength
>= 2 * BufSize
)
784 *SrbExtension
= (PVOID
*)((PCHAR
)SrbExtension
+ BufSize
);
785 SrbExtension
= *SrbExtension
;
787 CommonBufferLength
-= BufSize
;
791 return STATUS_SUCCESS
;
800 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
801 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
803 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
806 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
807 HwDeviceExtension
, PhysicalAddress
.QuadPart
);
809 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
810 SCSI_PORT_DEVICE_EXTENSION
,
811 MiniPortDeviceExtension
);
813 if (DeviceExtension
->PhysicalAddress
.QuadPart
> PhysicalAddress
.QuadPart
)
816 Offset
= (ULONG
)(PhysicalAddress
.QuadPart
- DeviceExtension
->PhysicalAddress
.QuadPart
);
818 if (Offset
>= DeviceExtension
->CommonBufferLength
)
821 return (PVOID
)((ULONG_PTR
)DeviceExtension
->SrbExtensionBuffer
+ Offset
);
825 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo
, PUNICODE_STRING RegistryPath
)
827 OBJECT_ATTRIBUTES ObjectAttributes
;
828 UNICODE_STRING KeyName
;
831 /* Open the service key */
832 InitializeObjectAttributes(&ObjectAttributes
,
834 OBJ_CASE_INSENSITIVE
,
838 Status
= ZwOpenKey(&ConfigInfo
->ServiceKey
,
842 if (!NT_SUCCESS(Status
))
844 DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath
, Status
);
845 ConfigInfo
->ServiceKey
= NULL
;
848 /* If we could open driver's service key, then proceed to the Parameters key */
849 if (ConfigInfo
->ServiceKey
!= NULL
)
851 RtlInitUnicodeString(&KeyName
, L
"Parameters");
852 InitializeObjectAttributes(&ObjectAttributes
,
854 OBJ_CASE_INSENSITIVE
,
855 ConfigInfo
->ServiceKey
,
856 (PSECURITY_DESCRIPTOR
) NULL
);
859 Status
= ZwOpenKey(&ConfigInfo
->DeviceKey
,
863 if (NT_SUCCESS(Status
))
865 /* Yes, Parameters key exist, and it must be used instead of
867 ZwClose(ConfigInfo
->ServiceKey
);
868 ConfigInfo
->ServiceKey
= ConfigInfo
->DeviceKey
;
869 ConfigInfo
->DeviceKey
= NULL
;
873 if (ConfigInfo
->ServiceKey
!= NULL
)
875 /* Open the Device key */
876 RtlInitUnicodeString(&KeyName
, L
"Device");
877 InitializeObjectAttributes(&ObjectAttributes
,
879 OBJ_CASE_INSENSITIVE
,
880 ConfigInfo
->ServiceKey
,
883 /* We don't check for failure here - not needed */
884 ZwOpenKey(&ConfigInfo
->DeviceKey
,
891 /**********************************************************************
896 * Initializes SCSI port driver specific data.
903 * Pointer to the miniport driver's driver object.
906 * Pointer to the miniport driver's registry path.
908 * HwInitializationData
909 * Pointer to port driver specific configuration data.
912 Miniport driver specific context.
921 ScsiPortInitialize(IN PVOID Argument1
,
923 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
926 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
927 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
928 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
929 PCONFIGURATION_INFORMATION SystemConfig
;
930 PPORT_CONFIGURATION_INFORMATION PortConfig
;
931 PORT_CONFIGURATION_INFORMATION InitialPortConfig
;
932 CONFIGURATION_INFO ConfigInfo
;
933 ULONG DeviceExtensionSize
;
934 ULONG PortConfigSize
;
936 BOOLEAN DeviceFound
= FALSE
;
937 BOOLEAN FirstConfigCall
= TRUE
;
942 PCI_SLOT_NUMBER SlotNumber
;
944 PDEVICE_OBJECT PortDeviceObject
;
945 WCHAR NameBuffer
[80];
946 UNICODE_STRING DeviceName
;
947 WCHAR DosNameBuffer
[80];
948 UNICODE_STRING DosDeviceName
;
949 PIO_SCSI_CAPABILITIES PortCapabilities
;
954 PCM_RESOURCE_LIST ResourceList
;
958 DPRINT ("ScsiPortInitialize() called!\n");
960 /* Check params for validity */
961 if ((HwInitializationData
->HwInitialize
== NULL
) ||
962 (HwInitializationData
->HwStartIo
== NULL
) ||
963 (HwInitializationData
->HwInterrupt
== NULL
) ||
964 (HwInitializationData
->HwFindAdapter
== NULL
) ||
965 (HwInitializationData
->HwResetBus
== NULL
))
967 return STATUS_INVALID_PARAMETER
;
971 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
972 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
973 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
974 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
975 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
976 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
978 /* Obtain configuration information */
979 SystemConfig
= IoGetConfigurationInformation();
981 /* Zero the internal configuration info structure */
982 RtlZeroMemory(&ConfigInfo
, sizeof(CONFIGURATION_INFO
));
984 /* Zero starting slot number */
985 SlotNumber
.u
.AsULONG
= 0;
987 /* Allocate space for access ranges */
988 if (HwInitializationData
->NumberOfAccessRanges
)
990 ConfigInfo
.AccessRanges
=
991 ExAllocatePoolWithTag(PagedPool
,
992 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
), TAG_SCSIPORT
);
995 if (ConfigInfo
.AccessRanges
== NULL
)
996 return STATUS_INSUFFICIENT_RESOURCES
;
999 /* Open registry keys */
1000 SpiInitOpenKeys(&ConfigInfo
, (PUNICODE_STRING
)Argument2
);
1002 /* Last adapter number = not known */
1003 ConfigInfo
.LastAdapterNumber
= SP_UNINITIALIZED_VALUE
;
1005 /* Calculate sizes of DeviceExtension and PortConfig */
1006 DeviceExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
1007 HwInitializationData
->DeviceExtensionSize
;
1009 MaxBus
= (HwInitializationData
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
1010 DPRINT("MaxBus: %lu\n", MaxBus
);
1014 /* Create a unicode device name */
1015 swprintf(NameBuffer
,
1016 L
"\\Device\\ScsiPort%lu",
1017 SystemConfig
->ScsiPortCount
);
1018 RtlInitUnicodeString(&DeviceName
, NameBuffer
);
1020 DPRINT("Creating device: %wZ\n", &DeviceName
);
1022 /* Create the port device */
1023 Status
= IoCreateDevice(DriverObject
,
1024 DeviceExtensionSize
,
1026 FILE_DEVICE_CONTROLLER
,
1031 if (!NT_SUCCESS(Status
))
1033 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
1034 PortDeviceObject
= NULL
;
1038 DPRINT ("Created device: %wZ (%p)\n", &DeviceName
, PortDeviceObject
);
1040 /* Set the buffering strategy here... */
1041 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1042 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
; /* FIXME: Is this really needed? */
1044 /* Fill Device Extension */
1045 DeviceExtension
= PortDeviceObject
->DeviceExtension
;
1046 DeviceExtension
->Length
= DeviceExtensionSize
;
1047 DeviceExtension
->DeviceObject
= PortDeviceObject
;
1048 DeviceExtension
->PortNumber
= SystemConfig
->ScsiPortCount
;
1050 /* Driver's routines... */
1051 DeviceExtension
->HwInitialize
= HwInitializationData
->HwInitialize
;
1052 DeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
1053 DeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
1054 DeviceExtension
->HwResetBus
= HwInitializationData
->HwResetBus
;
1055 DeviceExtension
->HwDmaStarted
= HwInitializationData
->HwDmaStarted
;
1057 /* Extensions sizes */
1058 DeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
1059 DeviceExtension
->LunExtensionSize
= HwInitializationData
->SpecificLuExtensionSize
;
1060 DeviceExtension
->SrbExtensionSize
= HwInitializationData
->SrbExtensionSize
;
1062 /* Round Srb extension size to the quadword */
1063 DeviceExtension
->SrbExtensionSize
=
1064 ~(sizeof(LONGLONG
) - 1) & (DeviceExtension
->SrbExtensionSize
+
1065 sizeof(LONGLONG
) - 1);
1067 /* Fill some numbers (bus count, lun count, etc) */
1068 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
1069 DeviceExtension
->RequestsNumber
= 16;
1071 /* Initialize the spin lock in the controller extension */
1072 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1073 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
1075 /* Initialize the DPC object */
1076 IoInitializeDpcRequest(PortDeviceObject
,
1079 /* Initialize the device timer */
1080 DeviceExtension
->TimerCount
= -1;
1081 IoInitializeTimer(PortDeviceObject
,
1085 /* Initialize miniport timer */
1086 KeInitializeTimer(&DeviceExtension
->MiniportTimer
);
1087 KeInitializeDpc(&DeviceExtension
->MiniportTimerDpc
,
1088 SpiMiniportTimerDpc
,
1093 Status
= SpiCreatePortConfig(DeviceExtension
,
1094 HwInitializationData
,
1099 if (!NT_SUCCESS(Status
))
1101 DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status
);
1105 /* Allocate and initialize port configuration info */
1106 PortConfigSize
= (sizeof(PORT_CONFIGURATION_INFORMATION
) +
1107 HwInitializationData
->NumberOfAccessRanges
*
1108 sizeof(ACCESS_RANGE
) + 7) & ~7;
1109 DeviceExtension
->PortConfig
= ExAllocatePoolWithTag(NonPagedPool
, PortConfigSize
, TAG_SCSIPORT
);
1111 /* Fail if failed */
1112 if (DeviceExtension
->PortConfig
== NULL
)
1114 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1118 PortConfig
= DeviceExtension
->PortConfig
;
1120 /* Copy information here */
1121 RtlCopyMemory(PortConfig
,
1123 sizeof(PORT_CONFIGURATION_INFORMATION
));
1126 /* Copy extension sizes into the PortConfig */
1127 PortConfig
->SpecificLuExtensionSize
= DeviceExtension
->LunExtensionSize
;
1128 PortConfig
->SrbExtensionSize
= DeviceExtension
->SrbExtensionSize
;
1130 /* Initialize Access ranges */
1131 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1133 PortConfig
->AccessRanges
= (PVOID
)(PortConfig
+1);
1135 /* Align to LONGLONG */
1136 PortConfig
->AccessRanges
= (PVOID
)((ULONG
)(PortConfig
->AccessRanges
) + 7);
1137 PortConfig
->AccessRanges
= (PVOID
)((ULONG
)(PortConfig
->AccessRanges
) & ~7);
1140 RtlCopyMemory(PortConfig
->AccessRanges
,
1141 ConfigInfo
.AccessRanges
,
1142 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
1145 /* Search for matching PCI device */
1146 if ((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1147 (HwInitializationData
->VendorIdLength
> 0) &&
1148 (HwInitializationData
->VendorId
!= NULL
) &&
1149 (HwInitializationData
->DeviceIdLength
> 0) &&
1150 (HwInitializationData
->DeviceId
!= NULL
))
1152 PortConfig
->BusInterruptLevel
= 0;
1154 /* Get PCI device data */
1155 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1156 HwInitializationData
->VendorIdLength
,
1157 HwInitializationData
->VendorId
,
1158 HwInitializationData
->DeviceIdLength
,
1159 HwInitializationData
->DeviceId
);
1161 if (!SpiGetPciConfigData(DriverObject
,
1163 HwInitializationData
,
1166 ConfigInfo
.BusNumber
,
1169 /* Continue to the next bus, nothing here */
1170 ConfigInfo
.BusNumber
++;
1171 DeviceExtension
->PortConfig
= NULL
;
1172 ExFreePool(PortConfig
);
1174 goto CreatePortConfig
;
1177 if (!PortConfig
->BusInterruptLevel
)
1179 /* Bypass this slot, because no interrupt was assigned */
1180 DeviceExtension
->PortConfig
= NULL
;
1181 ExFreePool(PortConfig
);
1182 goto CreatePortConfig
;
1187 DPRINT("Non-pci bus\n");
1190 /* Note: HwFindAdapter is called once for each bus */
1192 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
1193 Result
= (HwInitializationData
->HwFindAdapter
)(&DeviceExtension
->MiniPortDeviceExtension
,
1195 0, /* BusInformation */
1196 ConfigInfo
.Parameter
, /* ArgumentString */
1200 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1201 Result
, (Again
) ? "True" : "False");
1203 /* Free MapRegisterBase, it's not needed anymore */
1204 if (DeviceExtension
->MapRegisterBase
!= NULL
)
1206 ExFreePool(DeviceExtension
->MapRegisterBase
);
1207 DeviceExtension
->MapRegisterBase
= NULL
;
1210 /* If result is nothing good... */
1211 if (Result
!= SP_RETURN_FOUND
)
1213 DPRINT("HwFindAdapter() Result: %lu\n", Result
);
1215 if (Result
== SP_RETURN_NOT_FOUND
)
1217 /* We can continue on the next bus */
1218 ConfigInfo
.BusNumber
++;
1221 DeviceExtension
->PortConfig
= NULL
;
1222 ExFreePool(PortConfig
);
1223 goto CreatePortConfig
;
1226 /* Otherwise, break */
1227 Status
= STATUS_INTERNAL_ERROR
;
1231 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1232 PortConfig
->BusInterruptVector
, PortConfig
->InitiatorBusId
[0]);
1234 /* If the SRB extension size was updated */
1235 if (!DeviceExtension
->NonCachedExtension
&&
1236 (PortConfig
->SrbExtensionSize
!= DeviceExtension
->SrbExtensionSize
))
1238 /* Set it (rounding to LONGLONG again) */
1239 DeviceExtension
->SrbExtensionSize
=
1240 (PortConfig
->SrbExtensionSize
+
1241 sizeof(LONGLONG
)) & ~(sizeof(LONGLONG
) - 1);
1244 /* The same with LUN extension size */
1245 if (PortConfig
->SpecificLuExtensionSize
!= DeviceExtension
->LunExtensionSize
)
1246 DeviceExtension
->LunExtensionSize
= PortConfig
->SpecificLuExtensionSize
;
1249 if (!((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1250 (HwInitializationData
->VendorIdLength
> 0) &&
1251 (HwInitializationData
->VendorId
!= NULL
) &&
1252 (HwInitializationData
->DeviceIdLength
> 0) &&
1253 (HwInitializationData
->DeviceId
!= NULL
)))
1255 /* Construct a resource list */
1256 ResourceList
= SpiConfigToResource(DeviceExtension
,
1261 UNICODE_STRING UnicodeString
;
1262 RtlInitUnicodeString(&UnicodeString
, L
"ScsiAdapter");
1263 DPRINT("Reporting resources\n");
1264 Status
= IoReportResourceUsage(&UnicodeString
,
1270 FIELD_OFFSET(CM_RESOURCE_LIST
,
1271 List
[0].PartialResourceList
.PartialDescriptors
) +
1272 ResourceList
->List
[0].PartialResourceList
.Count
1273 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
1276 ExFreePool(ResourceList
);
1278 /* In case of a failure or a conflict, break */
1279 if (Conflict
|| (!NT_SUCCESS(Status
)))
1282 Status
= STATUS_CONFLICTING_ADDRESSES
;
1288 /* Reset the Conflict var */
1291 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1292 if (PortConfig
->MaximumNumberOfTargets
> SCSI_MAXIMUM_TARGETS_PER_BUS
)
1293 DeviceExtension
->MaxTargedIds
= SCSI_MAXIMUM_TARGETS_PER_BUS
;
1295 DeviceExtension
->MaxTargedIds
= PortConfig
->MaximumNumberOfTargets
;
1297 DeviceExtension
->BusNum
= PortConfig
->NumberOfBuses
;
1298 DeviceExtension
->CachesData
= PortConfig
->CachesData
;
1299 DeviceExtension
->ReceiveEvent
= PortConfig
->ReceiveEvent
;
1300 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->TaggedQueuing
;
1301 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
;
1303 /* If something was disabled via registry - apply it */
1304 if (ConfigInfo
.DisableMultipleLun
)
1305 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1307 if (ConfigInfo
.DisableTaggedQueueing
)
1308 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1310 /* Check if we need to alloc SRB data */
1311 if (DeviceExtension
->SupportsTaggedQueuing
||
1312 DeviceExtension
->MultipleReqsPerLun
)
1314 DeviceExtension
->NeedSrbDataAlloc
= TRUE
;
1318 DeviceExtension
->NeedSrbDataAlloc
= FALSE
;
1321 /* Get a pointer to the port capabilities */
1322 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1324 /* Copy one field there */
1325 DeviceExtension
->MapBuffers
= PortConfig
->MapBuffers
;
1326 PortCapabilities
->AdapterUsesPio
= PortConfig
->MapBuffers
;
1328 if (DeviceExtension
->AdapterObject
== NULL
&&
1329 (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
|| PortConfig
->Master
))
1331 DPRINT1("DMA is not supported yet\n");
1335 if (DeviceExtension
->SrbExtensionBuffer
== NULL
&&
1336 (DeviceExtension
->SrbExtensionSize
!= 0 ||
1337 PortConfig
->AutoRequestSense
))
1339 DeviceExtension
->SupportsAutoSense
= PortConfig
->AutoRequestSense
;
1340 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
1342 /* Allocate common buffer */
1343 Status
= SpiAllocateCommonBuffer(DeviceExtension
, 0);
1345 /* Check for failure */
1346 if (!NT_SUCCESS(Status
))
1350 /* Allocate SrbData, if needed */
1351 if (DeviceExtension
->NeedSrbDataAlloc
)
1354 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1356 if (DeviceExtension
->SrbDataCount
!= 0)
1357 Count
= DeviceExtension
->SrbDataCount
;
1359 Count
= DeviceExtension
->RequestsNumber
* 2;
1361 /* Allocate the data */
1362 SrbData
= ExAllocatePoolWithTag(NonPagedPool
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
), TAG_SCSIPORT
);
1363 if (SrbData
== NULL
)
1364 return STATUS_INSUFFICIENT_RESOURCES
;
1366 RtlZeroMemory(SrbData
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
));
1368 DeviceExtension
->SrbInfo
= SrbData
;
1369 DeviceExtension
->FreeSrbInfo
= SrbData
;
1370 DeviceExtension
->SrbDataCount
= Count
;
1372 /* Link it to the list */
1375 SrbData
->Requests
.Flink
= (PLIST_ENTRY
)(SrbData
+ 1);
1380 /* Mark the last entry of the list */
1382 SrbData
->Requests
.Flink
= NULL
;
1385 /* Initialize port capabilities */
1386 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1387 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1388 PortCapabilities
->MaximumTransferLength
= PortConfig
->MaximumTransferLength
;
1390 if (PortConfig
->ReceiveEvent
)
1391 PortCapabilities
->SupportedAsynchronousEvents
|= SRBEV_SCSI_ASYNC_NOTIFICATION
;
1393 PortCapabilities
->TaggedQueuing
= DeviceExtension
->SupportsTaggedQueuing
;
1394 PortCapabilities
->AdapterScansDown
= PortConfig
->AdapterScansDown
;
1396 if (PortConfig
->AlignmentMask
> PortDeviceObject
->AlignmentRequirement
)
1397 PortDeviceObject
->AlignmentRequirement
= PortConfig
->AlignmentMask
;
1399 PortCapabilities
->AlignmentMask
= PortDeviceObject
->AlignmentRequirement
;
1401 if (PortCapabilities
->MaximumPhysicalPages
== 0)
1403 PortCapabilities
->MaximumPhysicalPages
=
1404 BYTES_TO_PAGES(PortCapabilities
->MaximumTransferLength
);
1406 /* Apply miniport's limits */
1407 if (PortConfig
->NumberOfPhysicalBreaks
< PortCapabilities
->MaximumPhysicalPages
)
1409 PortCapabilities
->MaximumPhysicalPages
= PortConfig
->NumberOfPhysicalBreaks
;
1413 /* Deal with interrupts */
1414 if (DeviceExtension
->HwInterrupt
== NULL
||
1415 (PortConfig
->BusInterruptLevel
== 0 && PortConfig
->BusInterruptVector
== 0))
1418 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1420 /* FIXME: Use synchronization routine */
1421 ASSERT("No interrupts branch requires changes in synchronization\n");
1423 DeviceExtension
->Interrupt
= (PVOID
)DeviceExtension
;
1424 DPRINT("No interrupts\n");
1429 /* Are 2 interrupts needed? */
1430 if (DeviceExtension
->HwInterrupt
!= NULL
&&
1431 (PortConfig
->BusInterruptLevel
!= 0 || PortConfig
->BusInterruptVector
!= 0) &&
1432 (PortConfig
->BusInterruptLevel2
!= 0 || PortConfig
->BusInterruptVector2
!= 0))
1434 DPRINT1("2 interrupts requested! Not yet supported\n");
1439 BOOLEAN InterruptShareable
;
1441 /* No, only 1 interrupt */
1442 DPRINT("1 interrupt, IRQ is %d\n", PortConfig
->BusInterruptLevel
);
1444 DeviceExtension
->InterruptLevel
= PortConfig
->BusInterruptLevel
;
1446 /* Register an interrupt handler for this device */
1447 MappedIrq
= HalGetInterruptVector(PortConfig
->AdapterInterfaceType
,
1448 PortConfig
->SystemIoBusNumber
,
1449 PortConfig
->BusInterruptLevel
,
1450 PortConfig
->BusInterruptVector
,
1454 /* Determing IRQ sharability as usual */
1455 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1456 PortConfig
->InterruptMode
== LevelSensitive
)
1458 InterruptShareable
= TRUE
;
1462 InterruptShareable
= FALSE
;
1465 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
,
1466 (PKSERVICE_ROUTINE
)ScsiPortIsr
,
1472 PortConfig
->InterruptMode
,
1477 if (!(NT_SUCCESS(Status
)))
1479 DPRINT1("Could not connect interrupt %d\n",
1480 PortConfig
->BusInterruptVector
);
1481 DeviceExtension
->Interrupt
= NULL
;
1488 /* Save IoAddress (from access ranges) */
1489 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1491 DeviceExtension
->IoAddress
=
1492 ((*(PortConfig
->AccessRanges
))[0]).RangeStart
.LowPart
;
1494 DPRINT("Io Address %x\n", DeviceExtension
->IoAddress
);
1497 /* Set flag that it's allowed to disconnect during this command */
1498 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
1500 /* Initialize counter of active requests (-1 means there are none) */
1501 DeviceExtension
->ActiveRequestCounter
= -1;
1503 /* Analyze what we have about DMA */
1504 if (DeviceExtension
->AdapterObject
!= NULL
&&
1505 PortConfig
->Master
&&
1506 PortConfig
->NeedPhysicalAddresses
)
1508 DeviceExtension
->MapRegisters
= TRUE
;
1512 DeviceExtension
->MapRegisters
= FALSE
;
1515 /* Call HwInitialize at DISPATCH_LEVEL */
1516 KeRaiseIrql(DISPATCH_LEVEL
, &Dirql
);
1518 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1519 DeviceExtension
->HwInitialize
,
1520 DeviceExtension
->MiniPortDeviceExtension
))
1522 DPRINT1("HwInitialize() failed!\n");
1524 Status
= STATUS_ADAPTER_HARDWARE_ERROR
;
1528 /* Check if a notification is needed */
1529 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
1531 /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1532 ScsiPortDpcForIsr(NULL
,
1533 DeviceExtension
->DeviceObject
,
1538 /* Lower irql back to what it was */
1541 /* Start our timer */
1542 IoStartTimer(PortDeviceObject
);
1544 /* Initialize bus scanning information */
1545 DeviceExtension
->BusesConfig
= ExAllocatePoolWithTag(PagedPool
,
1546 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1547 + sizeof(ULONG
), TAG_SCSIPORT
);
1549 if (!DeviceExtension
->BusesConfig
)
1551 DPRINT1("Out of resources!\n");
1552 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1557 RtlZeroMemory(DeviceExtension
->BusesConfig
,
1558 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1561 /* Store number of buses there */
1562 DeviceExtension
->BusesConfig
->NumberOfBuses
= (UCHAR
)DeviceExtension
->BusNum
;
1564 /* Scan the adapter for devices */
1565 SpiScanAdapter(DeviceExtension
);
1567 /* Build the registry device map */
1568 SpiBuildDeviceMap(DeviceExtension
,
1569 (PUNICODE_STRING
)Argument2
);
1571 /* Create the dos device link */
1572 swprintf(DosNameBuffer
,
1574 SystemConfig
->ScsiPortCount
);
1575 RtlInitUnicodeString(&DosDeviceName
, DosNameBuffer
);
1576 IoCreateSymbolicLink(&DosDeviceName
, &DeviceName
);
1578 /* Increase the port count */
1579 SystemConfig
->ScsiPortCount
++;
1580 FirstConfigCall
= FALSE
;
1582 /* Increase adapter number and bus number respectively */
1583 ConfigInfo
.AdapterNumber
++;
1586 ConfigInfo
.BusNumber
++;
1588 DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber
, MaxBus
);
1593 /* Clean up the mess */
1594 SpiCleanupAfterInit(DeviceExtension
);
1596 /* Close registry keys */
1597 if (ConfigInfo
.ServiceKey
!= NULL
)
1598 ZwClose(ConfigInfo
.ServiceKey
);
1600 if (ConfigInfo
.DeviceKey
!= NULL
)
1601 ZwClose(ConfigInfo
.DeviceKey
);
1603 if (ConfigInfo
.BusKey
!= NULL
)
1604 ZwClose(ConfigInfo
.BusKey
);
1606 if (ConfigInfo
.AccessRanges
!= NULL
)
1607 ExFreePool(ConfigInfo
.AccessRanges
);
1609 if (ConfigInfo
.Parameter
!= NULL
)
1610 ExFreePool(ConfigInfo
.Parameter
);
1612 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1613 Status
, DeviceFound
);
1615 return (DeviceFound
== FALSE
) ? Status
: STATUS_SUCCESS
;
1619 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1621 PSCSI_LUN_INFO LunInfo
;
1625 /* Check if we have something to clean up */
1626 if (DeviceExtension
== NULL
)
1629 /* Stop the timer and disconnect the interrupt */
1630 if (DeviceExtension
->Interrupt
)
1632 IoStopTimer(DeviceExtension
->DeviceObject
);
1633 IoDisconnectInterrupt(DeviceExtension
->Interrupt
);
1636 /* Delete ConfigInfo */
1637 if (DeviceExtension
->BusesConfig
)
1639 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
1641 if (!DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
])
1644 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
1648 /* Free current, but save pointer to the next one */
1649 Ptr
= LunInfo
->Next
;
1650 ExFreePool(LunInfo
);
1654 ExFreePool(DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]);
1657 ExFreePool(DeviceExtension
->BusesConfig
);
1660 /* Free PortConfig */
1661 if (DeviceExtension
->PortConfig
)
1662 ExFreePool(DeviceExtension
->PortConfig
);
1665 for(Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
1667 while (DeviceExtension
->LunExtensionList
[Lun
])
1669 Ptr
= DeviceExtension
->LunExtensionList
[Lun
];
1670 DeviceExtension
->LunExtensionList
[Lun
] = DeviceExtension
->LunExtensionList
[Lun
]->Next
;
1676 /* Free common buffer (if it exists) */
1677 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
&&
1678 DeviceExtension
->CommonBufferLength
!= 0)
1680 if (!DeviceExtension
->AdapterObject
)
1682 ExFreePool(DeviceExtension
->SrbExtensionBuffer
);
1686 HalFreeCommonBuffer(DeviceExtension
->AdapterObject
,
1687 DeviceExtension
->CommonBufferLength
,
1688 DeviceExtension
->PhysicalAddress
,
1689 DeviceExtension
->SrbExtensionBuffer
,
1695 if (DeviceExtension
->SrbInfo
!= NULL
)
1696 ExFreePool(DeviceExtension
->SrbInfo
);
1698 /* Unmap mapped addresses */
1699 while (DeviceExtension
->MappedAddressList
!= NULL
)
1701 MmUnmapIoSpace(DeviceExtension
->MappedAddressList
->MappedAddress
,
1702 DeviceExtension
->MappedAddressList
->NumberOfBytes
);
1704 Ptr
= DeviceExtension
->MappedAddressList
;
1705 DeviceExtension
->MappedAddressList
= DeviceExtension
->MappedAddressList
->NextMappedAddress
;
1710 /* Finally delete the device object */
1711 DPRINT("Deleting device %p\n", DeviceExtension
->DeviceObject
);
1712 IoDeleteDevice(DeviceExtension
->DeviceObject
);
1719 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
1720 IN PSCSI_REQUEST_BLOCK Srb
,
1721 IN PVOID LogicalAddress
,
1724 DPRINT1("ScsiPortIoMapTransfer()\n");
1732 ScsiPortLogError(IN PVOID HwDeviceExtension
,
1733 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
1740 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1742 DPRINT1("ScsiPortLogError() called\n");
1744 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1745 SCSI_PORT_DEVICE_EXTENSION
,
1746 MiniPortDeviceExtension
);
1749 DPRINT("ScsiPortLogError() done\n");
1756 ScsiPortMoveMemory(OUT PVOID Destination
,
1760 RtlMoveMemory(Destination
,
1770 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
1771 IN PVOID HwDeviceExtension
,
1774 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1777 DPRINT("ScsiPortNotification() called\n");
1779 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1780 SCSI_PORT_DEVICE_EXTENSION
,
1781 MiniPortDeviceExtension
);
1783 DPRINT("DeviceExtension %p\n", DeviceExtension
);
1785 va_start(ap
, HwDeviceExtension
);
1787 switch (NotificationType
)
1789 case RequestComplete
:
1791 PSCSI_REQUEST_BLOCK Srb
;
1792 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1794 Srb
= (PSCSI_REQUEST_BLOCK
) va_arg (ap
, PSCSI_REQUEST_BLOCK
);
1796 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb
);
1798 /* Make sure Srb is allright */
1799 ASSERT(Srb
->SrbStatus
!= SRB_STATUS_PENDING
);
1800 ASSERT(Srb
->Function
!= SRB_FUNCTION_EXECUTE_SCSI
|| Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
|| Srb
->ScsiStatus
== SCSISTAT_GOOD
);
1802 if (!(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
1804 /* It's been already completed */
1809 /* It's not active anymore */
1810 Srb
->SrbFlags
&= ~SRB_FLAGS_IS_ACTIVE
;
1812 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
1814 /* TODO: Treat it specially */
1819 /* Get the SRB data */
1820 SrbData
= SpiGetSrbData(DeviceExtension
,
1826 /* Make sure there are no CompletedRequests and there is a Srb */
1827 ASSERT(SrbData
->CompletedRequests
== NULL
&& SrbData
->Srb
!= NULL
);
1829 /* If it's a read/write request, make sure it has data inside it */
1830 if ((Srb
->SrbStatus
== SRB_STATUS_SUCCESS
) &&
1831 ((Srb
->Cdb
[0] == SCSIOP_READ
) || (Srb
->Cdb
[0] == SCSIOP_WRITE
)))
1833 ASSERT(Srb
->DataTransferLength
);
1836 SrbData
->CompletedRequests
= DeviceExtension
->InterruptData
.CompletedRequests
;
1837 DeviceExtension
->InterruptData
.CompletedRequests
= SrbData
;
1843 DPRINT("Notify: NextRequest\n");
1844 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1852 PSCSI_PORT_LUN_EXTENSION LunExtension
;
1854 PathId
= (UCHAR
) va_arg (ap
, int);
1855 TargetId
= (UCHAR
) va_arg (ap
, int);
1856 Lun
= (UCHAR
) va_arg (ap
, int);
1858 DPRINT("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1859 PathId
, TargetId
, Lun
);
1861 /* Mark it in the flags field */
1862 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1864 /* Get the LUN extension */
1865 LunExtension
= SpiGetLunExtension(DeviceExtension
,
1870 /* This request should not be processed if */
1871 if ((LunExtension
&& LunExtension
->ReadyLun
) ||
1872 (LunExtension
&& LunExtension
->SrbInfo
.Srb
))
1874 /* Nothing to do here */
1878 /* Add this LUN to the list */
1879 LunExtension
->ReadyLun
= DeviceExtension
->InterruptData
.ReadyLun
;
1880 DeviceExtension
->InterruptData
.ReadyLun
= LunExtension
;
1885 DPRINT("Notify: ResetDetected\n");
1886 /* Add RESET flags */
1887 DeviceExtension
->InterruptData
.Flags
|=
1888 SCSI_PORT_RESET
| SCSI_PORT_RESET_REPORTED
;
1892 DPRINT1 ("Unsupported notification %lu\n", NotificationType
);
1898 /* Request a DPC after we're done with the interrupt */
1899 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NOTIFICATION_NEEDED
;
1906 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
1907 IN INTERFACE_TYPE BusType
,
1908 IN ULONG SystemIoBusNumber
,
1909 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
1910 IN ULONG NumberOfBytes
,
1911 IN BOOLEAN InIoSpace
)
1913 DPRINT("ScsiPortValidateRange()\n");
1918 /* INTERNAL FUNCTIONS ********************************************************/
1921 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
1922 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
1923 IN PPORT_CONFIGURATION_INFORMATION PortConfig
)
1925 PACCESS_RANGE AccessRange
;
1926 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData
;
1932 /* Loop through all entries */
1933 for (Index
= 0; Index
< ResourceDescriptor
->PartialResourceList
.Count
; Index
++)
1935 PartialData
= &ResourceDescriptor
->PartialResourceList
.PartialDescriptors
[Index
];
1937 switch (PartialData
->Type
)
1939 case CmResourceTypePort
:
1940 /* Copy access ranges */
1941 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
1943 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
1945 AccessRange
->RangeStart
= PartialData
->u
.Port
.Start
;
1946 AccessRange
->RangeLength
= PartialData
->u
.Port
.Length
;
1948 AccessRange
->RangeInMemory
= FALSE
;
1953 case CmResourceTypeMemory
:
1954 /* Copy access ranges */
1955 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
1957 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
1959 AccessRange
->RangeStart
= PartialData
->u
.Memory
.Start
;
1960 AccessRange
->RangeLength
= PartialData
->u
.Memory
.Length
;
1962 AccessRange
->RangeInMemory
= TRUE
;
1967 case CmResourceTypeInterrupt
:
1968 /* Copy interrupt data */
1969 PortConfig
->BusInterruptLevel
= PartialData
->u
.Interrupt
.Level
;
1970 PortConfig
->BusInterruptVector
= PartialData
->u
.Interrupt
.Vector
;
1972 /* Set interrupt mode accordingly to the resource */
1973 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
1975 PortConfig
->InterruptMode
= Latched
;
1977 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
1979 PortConfig
->InterruptMode
= LevelSensitive
;
1983 case CmResourceTypeDma
:
1984 PortConfig
->DmaChannel
= PartialData
->u
.Dma
.Channel
;
1985 PortConfig
->DmaPort
= PartialData
->u
.Dma
.Port
;
1991 static PCM_RESOURCE_LIST
1992 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1993 PPORT_CONFIGURATION_INFORMATION PortConfig
)
1995 PCONFIGURATION_INFORMATION ConfigInfo
;
1996 PCM_RESOURCE_LIST ResourceList
;
1997 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
1998 PACCESS_RANGE AccessRange
;
2000 ULONG ListLength
= 0, i
, FullSize
;
2003 /* Get current Atdisk usage from the system */
2004 ConfigInfo
= IoGetConfigurationInformation();
2006 if (PortConfig
->AtdiskPrimaryClaimed
)
2007 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
2009 if (PortConfig
->AtdiskSecondaryClaimed
)
2010 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
2012 /* Do we use DMA? */
2013 if (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
||
2014 PortConfig
->DmaPort
!= SP_UNINITIALIZED_VALUE
)
2024 /* How many interrupts to we have? */
2025 if (DeviceExtension
->HwInterrupt
== NULL
||
2026 (PortConfig
->BusInterruptLevel
== 0 &&
2027 PortConfig
->BusInterruptVector
== 0))
2037 if (DeviceExtension
->HwInterrupt
!= NULL
&&
2038 (PortConfig
->BusInterruptLevel2
!= 0 ||
2039 PortConfig
->BusInterruptVector2
!= 0))
2045 /* How many access ranges do we use? */
2046 AccessRange
= &((*(PortConfig
->AccessRanges
))[0]);
2047 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2049 if (AccessRange
->RangeLength
!= 0)
2055 /* Allocate the resource list, since we know its size now */
2056 FullSize
= sizeof(CM_RESOURCE_LIST
) + (ListLength
- 1) *
2057 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
2059 ResourceList
= (PCM_RESOURCE_LIST
)ExAllocatePoolWithTag(PagedPool
, FullSize
, TAG_SCSIPORT
);
2065 RtlZeroMemory(ResourceList
, FullSize
);
2068 ResourceList
->Count
= 1;
2069 ResourceList
->List
[0].InterfaceType
= PortConfig
->AdapterInterfaceType
;
2070 ResourceList
->List
[0].BusNumber
= PortConfig
->SystemIoBusNumber
;
2071 ResourceList
->List
[0].PartialResourceList
.Count
= ListLength
;
2072 ResourceDescriptor
= ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
;
2074 /* Copy access ranges array over */
2075 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2077 AccessRange
= &((*(PortConfig
->AccessRanges
))[i
]);
2079 /* If the range is empty - skip it */
2080 if (AccessRange
->RangeLength
== 0)
2083 if (AccessRange
->RangeInMemory
)
2085 ResourceDescriptor
->Type
= CmResourceTypeMemory
;
2086 ResourceDescriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
;
2090 ResourceDescriptor
->Type
= CmResourceTypePort
;
2091 ResourceDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
2094 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2096 ResourceDescriptor
->u
.Memory
.Start
= AccessRange
->RangeStart
;
2097 ResourceDescriptor
->u
.Memory
.Length
= AccessRange
->RangeLength
;
2099 ResourceDescriptor
++;
2102 /* If we use interrupt(s), copy them */
2105 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2107 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2108 PortConfig
->InterruptMode
== LevelSensitive
)
2110 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2111 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2115 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2116 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2119 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
2120 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
2121 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2123 ResourceDescriptor
++;
2127 /* Copy 2nd interrupt
2128 FIXME: Stupid code duplication, remove */
2131 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2133 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2134 PortConfig
->InterruptMode
== LevelSensitive
)
2136 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2137 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2141 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2142 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2145 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
2146 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
2147 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2149 ResourceDescriptor
++;
2155 ResourceDescriptor
->Type
= CmResourceTypeDma
;
2156 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2157 ResourceDescriptor
->u
.Dma
.Channel
= PortConfig
->DmaChannel
;
2158 ResourceDescriptor
->u
.Dma
.Port
= PortConfig
->DmaPort
;
2159 ResourceDescriptor
->Flags
= 0;
2161 if (PortConfig
->DmaChannel
== SP_UNINITIALIZED_VALUE
)
2162 ResourceDescriptor
->u
.Dma
.Channel
= 0;
2164 if (PortConfig
->DmaPort
== SP_UNINITIALIZED_VALUE
)
2165 ResourceDescriptor
->u
.Dma
.Port
= 0;
2168 return ResourceList
;
2173 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
2174 IN PDEVICE_OBJECT DeviceObject
,
2175 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
2176 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
2177 IN PUNICODE_STRING RegistryPath
,
2179 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
)
2181 PCI_COMMON_CONFIG PciConfig
;
2182 PCI_SLOT_NUMBER SlotNumber
;
2185 ULONG FunctionNumber
;
2186 CHAR VendorIdString
[8];
2187 CHAR DeviceIdString
[8];
2188 UNICODE_STRING UnicodeStr
;
2189 PCM_RESOURCE_LIST ResourceList
;
2192 DPRINT ("SpiGetPciConfiguration() called\n");
2194 RtlZeroMemory(&ResourceList
, sizeof(PCM_RESOURCE_LIST
));
2195 SlotNumber
.u
.AsULONG
= 0;
2197 /* Loop through all devices */
2198 for (DeviceNumber
= NextSlotNumber
->u
.bits
.DeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
2200 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
2202 /* Loop through all functions */
2203 for (FunctionNumber
= NextSlotNumber
->u
.bits
.FunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
2205 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
2207 /* Get PCI config bytes */
2208 DataSize
= HalGetBusData(PCIConfiguration
,
2210 SlotNumber
.u
.AsULONG
,
2214 /* If result of HalGetBusData is 0, then the bus is wrong */
2218 /* If result is PCI_INVALID_VENDORID, then this device has no more
2220 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
2223 sprintf (VendorIdString
, "%04hx", PciConfig
.VendorID
);
2224 sprintf (DeviceIdString
, "%04hx", PciConfig
.DeviceID
);
2226 if (_strnicmp(VendorIdString
, HwInitializationData
->VendorId
, HwInitializationData
->VendorIdLength
) ||
2227 _strnicmp(DeviceIdString
, HwInitializationData
->DeviceId
, HwInitializationData
->DeviceIdLength
))
2229 /* It is not our device */
2233 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2237 SlotNumber
.u
.bits
.DeviceNumber
,
2238 SlotNumber
.u
.bits
.FunctionNumber
);
2241 RtlInitUnicodeString(&UnicodeStr
, L
"ScsiAdapter");
2242 Status
= HalAssignSlotResources(RegistryPath
,
2248 SlotNumber
.u
.AsULONG
,
2251 if (!NT_SUCCESS(Status
))
2254 /* Create configuration information */
2255 SpiResourceToConfig(HwInitializationData
,
2259 /* Free the resource list */
2260 ExFreePool(ResourceList
);
2262 /* Set dev & fn numbers */
2263 NextSlotNumber
->u
.bits
.DeviceNumber
= DeviceNumber
;
2264 NextSlotNumber
->u
.bits
.FunctionNumber
= FunctionNumber
+ 1;
2266 /* Save the slot number */
2267 PortConfig
->SlotNumber
= SlotNumber
.u
.AsULONG
;
2271 NextSlotNumber
->u
.bits
.FunctionNumber
= 0;
2274 NextSlotNumber
->u
.bits
.DeviceNumber
= 0;
2275 DPRINT ("No device found\n");
2282 /**********************************************************************
2284 * ScsiPortCreateClose
2287 * Answer requests for Create/Close calls: a null operation.
2294 * Pointer to a device object.
2297 * Pointer to an IRP.
2303 static NTSTATUS STDCALL
2304 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
2307 DPRINT("ScsiPortCreateClose()\n");
2309 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2310 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2312 return STATUS_SUCCESS
;
2316 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2319 PSCSI_LUN_INFO LunInfo
;
2320 PIO_STACK_LOCATION IrpStack
;
2321 PDEVICE_OBJECT DeviceObject
;
2322 PSCSI_REQUEST_BLOCK Srb
;
2325 /* Get pointer to the SRB */
2326 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2327 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
2329 /* Check if PathId matches number of buses */
2330 if (DeviceExtension
->BusesConfig
== NULL
||
2331 DeviceExtension
->BusesConfig
->NumberOfBuses
<= Srb
->PathId
)
2333 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2334 return STATUS_DEVICE_DOES_NOT_EXIST
;
2337 /* Get pointer to LunInfo */
2338 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Srb
->PathId
]->LunInfo
;
2340 /* Find matching LunInfo */
2343 if (LunInfo
->PathId
== Srb
->PathId
&&
2344 LunInfo
->TargetId
== Srb
->TargetId
&&
2345 LunInfo
->Lun
== Srb
->Lun
)
2350 LunInfo
= LunInfo
->Next
;
2353 /* If we couldn't find it - exit */
2354 if (LunInfo
== NULL
)
2355 return STATUS_DEVICE_DOES_NOT_EXIST
;
2359 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2361 /* Release, if asked */
2362 if (Srb
->Function
== SRB_FUNCTION_RELEASE_DEVICE
)
2364 LunInfo
->DeviceClaimed
= FALSE
;
2365 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2366 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2368 return STATUS_SUCCESS
;
2371 /* Attach, if not already claimed */
2372 if (LunInfo
->DeviceClaimed
)
2374 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2375 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
2377 return STATUS_DEVICE_BUSY
;
2380 /* Save the device object */
2381 DeviceObject
= LunInfo
->DeviceObject
;
2383 if (Srb
->Function
== SRB_FUNCTION_CLAIM_DEVICE
)
2384 LunInfo
->DeviceClaimed
= TRUE
;
2386 if (Srb
->Function
== SRB_FUNCTION_ATTACH_DEVICE
)
2387 LunInfo
->DeviceObject
= Srb
->DataBuffer
;
2389 Srb
->DataBuffer
= DeviceObject
;
2391 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2392 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2394 return STATUS_SUCCESS
;
2398 /**********************************************************************
2400 * ScsiPortDispatchScsi
2403 * Answer requests for SCSI calls
2409 * Standard dispatch arguments
2415 static NTSTATUS STDCALL
2416 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
2419 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2420 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2421 PIO_STACK_LOCATION Stack
;
2422 PSCSI_REQUEST_BLOCK Srb
;
2424 NTSTATUS Status
= STATUS_SUCCESS
;
2425 PIRP NextIrp
, IrpList
;
2426 PKDEVICE_QUEUE_ENTRY Entry
;
2428 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2431 DeviceExtension
= DeviceObject
->DeviceExtension
;
2432 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2434 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2437 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2438 Status
= STATUS_UNSUCCESSFUL
;
2440 Irp
->IoStatus
.Status
= Status
;
2441 Irp
->IoStatus
.Information
= 0;
2443 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2448 DPRINT("Srb: %p\n", Srb
);
2449 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
2450 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
2452 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2456 if (LunExtension
== NULL
)
2458 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2459 Status
= STATUS_NO_SUCH_DEVICE
;
2461 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2462 Irp
->IoStatus
.Status
= Status
;
2463 Irp
->IoStatus
.Information
= 0;
2465 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2470 switch (Srb
->Function
)
2472 case SRB_FUNCTION_SHUTDOWN
:
2473 case SRB_FUNCTION_FLUSH
:
2474 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2475 if (DeviceExtension
->CachesData
== FALSE
)
2477 /* All success here */
2478 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2479 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2480 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2481 return STATUS_SUCCESS
;
2483 /* Fall through to a usual execute operation */
2485 case SRB_FUNCTION_EXECUTE_SCSI
:
2486 case SRB_FUNCTION_IO_CONTROL
:
2487 /* Mark IRP as pending in all cases */
2488 IoMarkIrpPending(Irp
);
2490 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2492 /* Start IO directly */
2493 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2499 /* We need to be at DISPATCH_LEVEL */
2500 KeRaiseIrql (DISPATCH_LEVEL
, &oldIrql
);
2502 /* Insert IRP into the queue */
2503 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
2504 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
2507 /* It means the queue is empty, and we just start this request */
2508 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2511 /* Back to the old IRQL */
2512 KeLowerIrql (oldIrql
);
2514 return STATUS_PENDING
;
2516 case SRB_FUNCTION_CLAIM_DEVICE
:
2517 case SRB_FUNCTION_ATTACH_DEVICE
:
2518 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2520 /* Reference device object and keep the device object */
2521 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2524 case SRB_FUNCTION_RELEASE_DEVICE
:
2525 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2527 /* Dereference device object and clear the device object */
2528 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2531 case SRB_FUNCTION_RELEASE_QUEUE
:
2532 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2534 /* Guard with the spinlock */
2535 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2537 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2539 DPRINT("Queue is not frozen really\n");
2541 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2542 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2543 Status
= STATUS_SUCCESS
;
2548 /* Unfreeze the queue */
2549 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2551 if (LunExtension
->SrbInfo
.Srb
== NULL
)
2553 /* Get next logical unit request */
2554 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
2556 /* SpiGetNextRequestFromLun() releases the spinlock */
2561 DPRINT("The queue has active request\n");
2562 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2566 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2567 Status
= STATUS_SUCCESS
;
2570 case SRB_FUNCTION_FLUSH_QUEUE
:
2571 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2573 /* Guard with the spinlock */
2574 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2576 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2578 DPRINT("Queue is not frozen really\n");
2580 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2581 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2585 /* Make sure there is no active request */
2586 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
2588 /* Compile a list from the device queue */
2590 while ((Entry
= KeRemoveDeviceQueue(&LunExtension
->DeviceQueue
)) != NULL
)
2592 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
2595 Stack
= IoGetCurrentIrpStackLocation(NextIrp
);
2596 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2599 Srb
->SrbStatus
= SRB_STATUS_REQUEST_FLUSHED
;
2600 NextIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2602 /* Add then to the list */
2603 NextIrp
->Tail
.Overlay
.ListEntry
.Flink
= (PLIST_ENTRY
)IrpList
;
2607 /* Unfreeze the queue */
2608 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2610 /* Release the spinlock */
2611 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2613 /* Complete those requests */
2617 IrpList
= (PIRP
)NextIrp
->Tail
.Overlay
.ListEntry
.Flink
;
2619 IoCompleteRequest(NextIrp
, 0);
2622 Status
= STATUS_SUCCESS
;
2626 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
2627 Status
= STATUS_NOT_IMPLEMENTED
;
2631 Irp
->IoStatus
.Status
= Status
;
2633 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2639 /**********************************************************************
2641 * ScsiPortDeviceControl
2644 * Answer requests for device control calls
2650 * Standard dispatch arguments
2656 static NTSTATUS STDCALL
2657 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
2660 PIO_STACK_LOCATION Stack
;
2661 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2662 NTSTATUS Status
= STATUS_SUCCESS
;;
2664 DPRINT("ScsiPortDeviceControl()\n");
2666 Irp
->IoStatus
.Information
= 0;
2668 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2669 DeviceExtension
= DeviceObject
->DeviceExtension
;
2671 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
2673 case IOCTL_SCSI_GET_DUMP_POINTERS
:
2675 PDUMP_POINTERS DumpPointers
;
2676 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2677 DumpPointers
= (PDUMP_POINTERS
)Irp
->AssociatedIrp
.SystemBuffer
;
2678 DumpPointers
->DeviceObject
= DeviceObject
;
2680 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2684 case IOCTL_SCSI_GET_CAPABILITIES
:
2685 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2686 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
== sizeof(PVOID
))
2688 *((PVOID
*)Irp
->AssociatedIrp
.SystemBuffer
) = &DeviceExtension
->PortCapabilities
;
2690 Irp
->IoStatus
.Information
= sizeof(PVOID
);
2691 Status
= STATUS_SUCCESS
;
2695 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(IO_SCSI_CAPABILITIES
))
2697 Status
= STATUS_BUFFER_TOO_SMALL
;
2701 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2702 &DeviceExtension
->PortCapabilities
,
2703 sizeof(IO_SCSI_CAPABILITIES
));
2705 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
2706 Status
= STATUS_SUCCESS
;
2709 case IOCTL_SCSI_GET_INQUIRY_DATA
:
2710 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2712 /* Copy inquiry data to the port device extension */
2713 Status
= SpiGetInquiryData(DeviceExtension
, Irp
);
2717 DPRINT1(" unknown ioctl code: 0x%lX\n",
2718 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2722 /* Complete the request with the given status */
2723 Irp
->IoStatus
.Status
= Status
;
2724 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2731 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
2734 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2735 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2736 PIO_STACK_LOCATION IrpStack
;
2737 PSCSI_REQUEST_BLOCK Srb
;
2738 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2742 DPRINT("ScsiPortStartIo() called!\n");
2744 DeviceExtension
= DeviceObject
->DeviceExtension
;
2745 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2747 DPRINT("DeviceExtension %p\n", DeviceExtension
);
2749 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2751 /* Apply "default" flags */
2752 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
2754 /* Get LUN extension */
2755 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2760 if (DeviceExtension
->NeedSrbDataAlloc
||
2761 DeviceExtension
->NeedSrbExtensionAlloc
)
2764 SrbInfo
= SpiAllocateSrbStructures(DeviceExtension
,
2768 /* Couldn't alloc one or both data structures, return */
2769 if (SrbInfo
== NULL
)
2771 /* We have to call IoStartNextPacket, because this request
2773 if (LunExtension
->Flags
& LUNEX_REQUEST_PENDING
)
2774 IoStartNextPacket(DeviceObject
, FALSE
);
2781 /* No allocations are needed */
2782 SrbInfo
= &LunExtension
->SrbInfo
;
2783 Srb
->SrbExtension
= NULL
;
2784 Srb
->QueueTag
= SP_UNTAGGED
;
2787 /* Increase sequence number of SRB */
2788 if (!SrbInfo
->SequenceNumber
)
2790 /* Increase global sequence number */
2791 DeviceExtension
->SequenceNumber
++;
2794 SrbInfo
->SequenceNumber
= DeviceExtension
->SequenceNumber
;
2797 /* Check some special SRBs */
2798 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2800 /* Some special handling */
2801 DPRINT1("Abort command! Unimplemented now\n");
2808 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
)
2810 // Store the MDL virtual address in SrbInfo structure
2811 SrbInfo
->DataOffset
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2813 if (DeviceExtension
->MapBuffers
&& Irp
->MdlAddress
)
2815 /* Calculate offset within DataBuffer */
2816 SrbInfo
->DataOffset
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
2817 Srb
->DataBuffer
= SrbInfo
->DataOffset
+
2818 (ULONG
)((PUCHAR
)Srb
->DataBuffer
-
2819 (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2822 if (DeviceExtension
->AdapterObject
)
2825 KeFlushIoBuffers(Irp
->MdlAddress
,
2826 Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? TRUE
: FALSE
,
2830 if (DeviceExtension
->MapRegisters
)
2832 /* Calculate number of needed map registers */
2833 SrbInfo
->NumberOfMapRegisters
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
2835 Srb
->DataTransferLength
);
2837 /* Allocate adapter channel */
2838 Status
= IoAllocateAdapterChannel(DeviceExtension
->AdapterObject
,
2839 DeviceExtension
->DeviceObject
,
2840 SrbInfo
->NumberOfMapRegisters
,
2844 if (!NT_SUCCESS(Status
))
2846 DPRINT1("IoAllocateAdapterChannel() failed!\n");
2848 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
2849 ScsiPortNotification(RequestComplete
,
2850 DeviceExtension
+ 1,
2853 ScsiPortNotification(NextRequest
,
2854 DeviceExtension
+ 1);
2856 /* Request DPC for that work */
2857 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2860 /* Control goes to SpiAdapterControl */
2865 /* Increase active request counter */
2866 CounterResult
= InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
2868 if (CounterResult
== 0 &&
2869 DeviceExtension
->AdapterObject
!= NULL
&&
2870 !DeviceExtension
->MapRegisters
)
2872 IoAllocateAdapterChannel(
2873 DeviceExtension
->AdapterObject
,
2875 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
,
2876 ScsiPortAllocateAdapterChannel
,
2883 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
2885 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
2886 ScsiPortStartPacket
,
2889 DPRINT("Synchronization failed!\n");
2891 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2892 Irp
->IoStatus
.Information
= 0;
2893 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
2895 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2899 /* Release the spinlock only */
2900 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
2904 DPRINT("ScsiPortStartIo() done\n");
2908 static BOOLEAN STDCALL
2909 ScsiPortStartPacket(IN OUT PVOID Context
)
2911 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2912 PIO_STACK_LOCATION IrpStack
;
2913 PSCSI_REQUEST_BLOCK Srb
;
2914 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)Context
;
2915 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2916 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2920 DPRINT("ScsiPortStartPacket() called\n");
2922 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
2924 IrpStack
= IoGetCurrentIrpStackLocation(DeviceObject
->CurrentIrp
);
2925 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2927 /* Get LUN extension */
2928 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2933 /* Check if we are in a reset state */
2934 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
2936 /* Mark the we've got requests while being in the reset state */
2937 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET_REQUEST
;
2941 /* Set the time out value */
2942 DeviceExtension
->TimerCount
= Srb
->TimeOutValue
;
2945 DeviceExtension
->Flags
|= SCSI_PORT_DEVICE_BUSY
;
2947 if (LunExtension
->RequestTimeout
!= -1)
2949 /* Timer already active */
2954 /* It hasn't been initialized yet */
2955 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
2959 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2961 /* Handle bypass-requests */
2963 /* Is this an abort request? */
2964 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2966 /* Get pointer to SRB info structure */
2967 SrbInfo
= SpiGetSrbData(DeviceExtension
,
2973 /* Check if the request is still "active" */
2974 if (SrbInfo
== NULL
||
2975 SrbInfo
->Srb
== NULL
||
2976 !(SrbInfo
->Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
2978 /* It's not, mark it as active then */
2979 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
2982 LunExtension
->RequestTimeout
= -1;
2984 DPRINT("Request has been already completed, but abort request came\n");
2985 Srb
->SrbStatus
= SRB_STATUS_ABORT_FAILED
;
2987 /* Notify about request complete */
2988 ScsiPortNotification(RequestComplete
,
2989 DeviceExtension
->MiniPortDeviceExtension
,
2992 /* and about readiness for the next request */
2993 ScsiPortNotification(NextRequest
,
2994 DeviceExtension
->MiniPortDeviceExtension
);
2996 /* They might ask for some work, so queue the DPC for them */
2997 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2999 /* We're done in this branch */
3005 /* Add number of queued requests */
3006 LunExtension
->QueueCount
++;
3009 /* Bypass requests don't need request sense */
3010 LunExtension
->Flags
&= ~LUNEX_NEED_REQUEST_SENSE
;
3012 /* Is disconnect disabled for this request? */
3013 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3015 /* Set the corresponding flag */
3016 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3019 /* Transfer timeout value from Srb to Lun */
3020 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
3024 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3026 /* It's a disconnect, so no more requests can go */
3027 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3030 LunExtension
->Flags
|= SCSI_PORT_LU_ACTIVE
;
3032 /* Increment queue count */
3033 LunExtension
->QueueCount
++;
3035 /* If it's tagged - special thing */
3036 if (Srb
->QueueTag
!= SP_UNTAGGED
)
3038 SrbInfo
= &DeviceExtension
->SrbInfo
[Srb
->QueueTag
- 1];
3040 /* Chek for consistency */
3041 ASSERT(SrbInfo
->Requests
.Blink
== NULL
);
3043 /* Insert it into the list of requests */
3044 InsertTailList(&LunExtension
->SrbInfo
.Requests
, &SrbInfo
->Requests
);
3048 /* Mark this Srb active */
3049 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
3051 /* Call HwStartIo routine */
3052 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
3055 /* If notification is needed, then request a DPC */
3056 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
3057 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3062 IO_ALLOCATION_ACTION
3064 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
,
3066 PVOID MapRegisterBase
,
3069 PSCSI_REQUEST_BLOCK Srb
;
3070 PSCSI_SG_ADDRESS ScatterGatherList
;
3072 PIO_STACK_LOCATION IrpStack
;
3073 ULONG TotalLength
= 0;
3074 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3075 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3077 BOOLEAN WriteToDevice
;
3079 /* Get pointers to SrbInfo and DeviceExtension */
3080 SrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)Context
;
3081 DeviceExtension
= DeviceObject
->DeviceExtension
;
3083 /* Get pointer to SRB */
3084 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3085 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
3087 /* Depending on the map registers number, we allocate
3088 either from NonPagedPool, or from our static list */
3089 if (SrbInfo
->NumberOfMapRegisters
> MAX_SG_LIST
)
3091 SrbInfo
->ScatterGather
= ExAllocatePoolWithTag(
3092 NonPagedPool
, SrbInfo
->NumberOfMapRegisters
* sizeof(SCSI_SG_ADDRESS
), TAG_SCSIPORT
);
3094 if (SrbInfo
->ScatterGather
== NULL
)
3097 Srb
->SrbFlags
|= SRB_FLAGS_SGLIST_FROM_POOL
;
3101 SrbInfo
->ScatterGather
= SrbInfo
->ScatterGatherList
;
3104 /* Use chosen SG list source */
3105 ScatterGatherList
= SrbInfo
->ScatterGather
;
3107 /* Save map registers base */
3108 SrbInfo
->BaseOfMapRegister
= MapRegisterBase
;
3110 /* Determine WriteToDevice flag */
3111 WriteToDevice
= Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
? TRUE
: FALSE
;
3113 /* Get virtual address of the data buffer */
3114 DataVA
= (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
3115 ((PCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
3117 /* Build the actual SG list */
3118 while (TotalLength
< Srb
->DataTransferLength
)
3120 if (!ScatterGatherList
)
3123 ScatterGatherList
->Length
= Srb
->DataTransferLength
- TotalLength
;
3124 ScatterGatherList
->PhysicalAddress
= IoMapTransfer(NULL
,
3127 DataVA
+ TotalLength
,
3128 &ScatterGatherList
->Length
,
3131 TotalLength
+= ScatterGatherList
->Length
;
3132 ScatterGatherList
++;
3135 /* Schedule an active request */
3136 InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
3137 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &CurrentIrql
);
3138 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
3139 ScsiPortStartPacket
,
3141 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, CurrentIrql
);
3143 return DeallocateObjectKeepRegisters
;
3146 static PSCSI_PORT_LUN_EXTENSION
3147 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3149 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3150 ULONG LunExtensionSize
;
3152 DPRINT("SpiAllocateLunExtension (%p)\n",
3155 /* Round LunExtensionSize first to the sizeof LONGLONG */
3156 LunExtensionSize
= (DeviceExtension
->LunExtensionSize
+
3157 sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
3159 LunExtensionSize
+= sizeof(SCSI_PORT_LUN_EXTENSION
);
3160 DPRINT("LunExtensionSize %lu\n", LunExtensionSize
);
3162 LunExtension
= ExAllocatePoolWithTag(NonPagedPool
, LunExtensionSize
, TAG_SCSIPORT
);
3163 if (LunExtension
== NULL
)
3165 DPRINT1("Out of resources!\n");
3169 /* Zero everything */
3170 RtlZeroMemory(LunExtension
, LunExtensionSize
);
3172 /* Initialize a list of requests */
3173 InitializeListHead(&LunExtension
->SrbInfo
.Requests
);
3175 /* Initialize timeout counter */
3176 LunExtension
->RequestTimeout
= -1;
3178 /* Set maximum queue size */
3179 LunExtension
->MaxQueueCount
= 256;
3181 /* Initialize request queue */
3182 KeInitializeDeviceQueue (&LunExtension
->DeviceQueue
);
3184 return LunExtension
;
3187 static PSCSI_PORT_LUN_EXTENSION
3188 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3193 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3195 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3196 DeviceExtension
, PathId
, TargetId
, Lun
);
3198 /* Get appropriate list */
3199 LunExtension
= DeviceExtension
->LunExtensionList
[(TargetId
+ Lun
) % LUS_NUMBER
];
3201 /* Iterate it until we find what we need */
3202 while (LunExtension
)
3204 if (LunExtension
->TargetId
== TargetId
&&
3205 LunExtension
->Lun
== Lun
&&
3206 LunExtension
->PathId
== PathId
)
3208 /* All matches, return */
3209 return LunExtension
;
3212 /* Advance to the next item */
3213 LunExtension
= LunExtension
->Next
;
3216 /* We did not find anything */
3217 DPRINT("Nothing found\n");
3221 static PSCSI_REQUEST_BLOCK_INFO
3222 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3223 PSCSI_PORT_LUN_EXTENSION LunExtension
,
3224 PSCSI_REQUEST_BLOCK Srb
)
3227 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3229 /* Spinlock must be held while this function executes */
3230 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3232 /* Allocate SRB data structure */
3233 if (DeviceExtension
->NeedSrbDataAlloc
)
3235 /* Treat the abort request in a special way */
3236 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
3238 SrbInfo
= SpiGetSrbData(DeviceExtension
,
3244 else if (Srb
->SrbFlags
&
3245 (SRB_FLAGS_QUEUE_ACTION_ENABLE
| SRB_FLAGS_NO_QUEUE_FREEZE
) &&
3246 !(Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3249 /* Do not process tagged commands if need request sense is set */
3250 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
3252 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3254 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3255 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3257 /* Relese the spinlock and return */
3258 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3262 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
3263 SrbInfo
= DeviceExtension
->FreeSrbInfo
;
3265 if (SrbInfo
== NULL
)
3267 /* No SRB structures left in the list. We have to leave
3268 and wait while we are called again */
3270 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3271 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3275 DeviceExtension
->FreeSrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)SrbInfo
->Requests
.Flink
;
3277 /* QueueTag must never be 0, so +1 to it */
3278 Srb
->QueueTag
= (UCHAR
)(SrbInfo
- DeviceExtension
->SrbInfo
) + 1;
3282 /* Usual untagged command */
3284 (!IsListEmpty(&LunExtension
->SrbInfo
.Requests
) ||
3285 LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
) &&
3286 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
3289 /* Mark it as pending and leave */
3290 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3291 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3292 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3294 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3298 Srb
->QueueTag
= SP_UNTAGGED
;
3299 SrbInfo
= &LunExtension
->SrbInfo
;
3304 Srb
->QueueTag
= SP_UNTAGGED
;
3305 SrbInfo
= &LunExtension
->SrbInfo
;
3308 /* Allocate SRB extension structure */
3309 if (DeviceExtension
->NeedSrbExtensionAlloc
)
3311 /* Check the list of free extensions */
3312 SrbExtension
= DeviceExtension
->FreeSrbExtensions
;
3314 /* If no free extensions... */
3315 if (SrbExtension
== NULL
)
3318 if (Srb
->Function
!= SRB_FUNCTION_ABORT_COMMAND
&&
3319 Srb
->QueueTag
!= SP_UNTAGGED
)
3321 SrbInfo
->Requests
.Blink
= NULL
;
3322 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
3323 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
3326 /* Return, in order to be called again later */
3327 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3328 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3332 /* Remove that free SRB extension from the list (since
3333 we're going to use it) */
3334 DeviceExtension
->FreeSrbExtensions
= *((PVOID
*)SrbExtension
);
3336 /* Spinlock can be released now */
3337 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3339 Srb
->SrbExtension
= SrbExtension
;
3341 if (Srb
->SenseInfoBuffer
!= NULL
&&
3342 DeviceExtension
->SupportsAutoSense
)
3344 /* Store pointer to the SenseInfo buffer */
3345 SrbInfo
->SaveSenseRequest
= Srb
->SenseInfoBuffer
;
3347 /* Does data fit the buffer? */
3348 if (Srb
->SenseInfoBufferLength
> sizeof(SENSE_DATA
))
3350 /* No, disabling autosense at all */
3351 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_AUTOSENSE
;
3355 /* Yes, update the buffer pointer */
3356 Srb
->SenseInfoBuffer
= SrbExtension
+ DeviceExtension
->SrbExtensionSize
;
3363 Srb
->SrbExtension
= NULL
;
3364 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3372 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
3373 IN PSCSI_LUN_INFO LunInfo
)
3375 IO_STATUS_BLOCK IoStatusBlock
;
3376 PIO_STACK_LOCATION IrpStack
;
3381 PINQUIRYDATA InquiryBuffer
;
3382 PSENSE_DATA SenseBuffer
;
3383 BOOLEAN KeepTrying
= TRUE
;
3384 ULONG RetryCount
= 0;
3385 SCSI_REQUEST_BLOCK Srb
;
3387 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3388 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3390 DPRINT ("SpiSendInquiry() called\n");
3392 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3394 InquiryBuffer
= ExAllocatePoolWithTag (NonPagedPool
, INQUIRYDATABUFFERSIZE
, TAG_SCSIPORT
);
3395 if (InquiryBuffer
== NULL
)
3396 return STATUS_INSUFFICIENT_RESOURCES
;
3398 SenseBuffer
= ExAllocatePoolWithTag (NonPagedPool
, SENSE_BUFFER_SIZE
, TAG_SCSIPORT
);
3399 if (SenseBuffer
== NULL
)
3401 ExFreePool(InquiryBuffer
);
3402 return STATUS_INSUFFICIENT_RESOURCES
;
3407 /* Initialize event for waiting */
3408 KeInitializeEvent(&Event
,
3413 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN
,
3418 INQUIRYDATABUFFERSIZE
,
3424 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3425 return STATUS_INSUFFICIENT_RESOURCES
;
3429 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3431 Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
3432 Srb
.OriginalRequest
= Irp
;
3433 Srb
.PathId
= LunInfo
->PathId
;
3434 Srb
.TargetId
= LunInfo
->TargetId
;
3435 Srb
.Lun
= LunInfo
->Lun
;
3436 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3437 Srb
.SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3438 Srb
.TimeOutValue
= 4;
3441 Srb
.SenseInfoBuffer
= SenseBuffer
;
3442 Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3444 Srb
.DataBuffer
= InquiryBuffer
;
3445 Srb
.DataTransferLength
= INQUIRYDATABUFFERSIZE
;
3447 /* Attach Srb to the Irp */
3448 IrpStack
= IoGetNextIrpStackLocation (Irp
);
3449 IrpStack
->Parameters
.Scsi
.Srb
= &Srb
;
3452 Cdb
= (PCDB
)Srb
.Cdb
;
3453 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_INQUIRY
;
3454 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= LunInfo
->Lun
;
3455 Cdb
->CDB6INQUIRY
.AllocationLength
= INQUIRYDATABUFFERSIZE
;
3457 /* Call the driver */
3458 Status
= IoCallDriver(DeviceObject
, Irp
);
3460 /* Wait for it to complete */
3461 if (Status
== STATUS_PENDING
)
3463 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3464 KeWaitForSingleObject(&Event
,
3469 Status
= IoStatusBlock
.Status
;
3472 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status
);
3474 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_SUCCESS
)
3476 /* All fine, copy data over */
3477 RtlCopyMemory(LunInfo
->InquiryData
,
3479 INQUIRYDATABUFFERSIZE
);
3481 Status
= STATUS_SUCCESS
;
3486 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb
.SrbStatus
);
3487 /* Check if the queue is frozen */
3488 if (Srb
.SrbStatus
& SRB_STATUS_QUEUE_FROZEN
)
3490 /* Something weird happened, deal with it (unfreeze the queue) */
3493 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb
.TargetId
);
3495 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3500 /* Clear frozen flag */
3501 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
3503 /* Acquire the spinlock */
3504 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
3506 /* Process the request */
3507 SpiGetNextRequestFromLun(DeviceObject
->DeviceExtension
, LunExtension
);
3509 /* SpiGetNextRequestFromLun() releases the spinlock,
3510 so we just lower irql back to what it was before */
3514 /* Check if data overrun happened */
3515 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
3517 DPRINT("Data overrun at TargetId %d\n", LunInfo
->TargetId
);
3518 /* Nothing dramatic, just copy data, but limiting the size */
3519 RtlCopyMemory(LunInfo
->InquiryData
,
3521 (Srb
.DataTransferLength
> INQUIRYDATABUFFERSIZE
) ?
3522 INQUIRYDATABUFFERSIZE
: Srb
.DataTransferLength
);
3524 Status
= STATUS_SUCCESS
;
3527 else if ((Srb
.SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3528 SenseBuffer
->SenseKey
== SCSI_SENSE_ILLEGAL_REQUEST
)
3530 /* LUN is not valid, but some device responds there.
3531 Mark it as invalid anyway */
3533 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3538 /* Retry a couple of times if no timeout happened */
3539 if ((RetryCount
< 2) &&
3540 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_NO_DEVICE
) &&
3541 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_SELECTION_TIMEOUT
))
3548 /* That's all, go to exit */
3551 /* Set status according to SRB status */
3552 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_FUNCTION
||
3553 SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH
)
3555 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3559 Status
= STATUS_IO_DEVICE_ERROR
;
3567 ExFreePool(InquiryBuffer
);
3568 ExFreePool(SenseBuffer
);
3570 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status
);
3576 /* Scans all SCSI buses */
3578 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3580 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3584 PSCSI_BUS_SCAN_INFO BusScanInfo
;
3585 PSCSI_LUN_INFO LastLunInfo
, LunInfo
, LunInfoExists
;
3586 BOOLEAN DeviceExists
;
3591 DPRINT("SpiScanAdapter() called\n");
3593 /* Scan all buses */
3594 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
3596 DPRINT(" Scanning bus %d\n", Bus
);
3599 /* Get pointer to the scan information */
3600 BusScanInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
];
3604 /* Find the last LUN info in the list */
3605 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3606 LastLunInfo
= LunInfo
;
3608 while (LunInfo
!= NULL
)
3610 LastLunInfo
= LunInfo
;
3611 LunInfo
= LunInfo
->Next
;
3616 /* We need to allocate this buffer */
3617 BusScanInfo
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_BUS_SCAN_INFO
), TAG_SCSIPORT
);
3621 DPRINT1("Out of resources!\n");
3625 /* Store the pointer in the BusScanInfo array */
3626 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
] = BusScanInfo
;
3628 /* Fill this struct (length and bus ids for now) */
3629 BusScanInfo
->Length
= sizeof(SCSI_BUS_SCAN_INFO
);
3630 BusScanInfo
->LogicalUnitsCount
= 0;
3631 BusScanInfo
->BusIdentifier
= DeviceExtension
->PortConfig
->InitiatorBusId
[Bus
];
3632 BusScanInfo
->LunInfo
= NULL
;
3634 /* Set pointer to the last LUN info to NULL */
3638 /* Create LUN information structure */
3639 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3641 if (LunInfo
== NULL
)
3643 DPRINT1("Out of resources!\n");
3647 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3649 /* Create LunExtension */
3650 LunExtension
= SpiAllocateLunExtension (DeviceExtension
);
3652 /* And send INQUIRY to every target */
3653 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
3655 /* TODO: Support scan bottom-up */
3657 /* Skip if it's the same address */
3658 if (Target
== BusScanInfo
->BusIdentifier
)
3661 /* Try to find an existing device here */
3662 DeviceExists
= FALSE
;
3663 LunInfoExists
= BusScanInfo
->LunInfo
;
3665 /* Find matching address on this bus */
3666 while (LunInfoExists
)
3668 if (LunInfoExists
->TargetId
== Target
)
3670 DeviceExists
= TRUE
;
3674 /* Advance to the next one */
3675 LunInfoExists
= LunInfoExists
->Next
;
3678 /* No need to bother rescanning, since we already did that before */
3682 /* Scan all logical units */
3683 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
3685 if ((!LunExtension
) || (!LunInfo
))
3688 /* Add extension to the list */
3689 Hint
= (Target
+ Lun
) % LUS_NUMBER
;
3690 LunExtension
->Next
= DeviceExtension
->LunExtensionList
[Hint
];
3691 DeviceExtension
->LunExtensionList
[Hint
] = LunExtension
;
3693 /* Fill Path, Target, Lun fields */
3694 LunExtension
->PathId
= LunInfo
->PathId
= (UCHAR
)Bus
;
3695 LunExtension
->TargetId
= LunInfo
->TargetId
= (UCHAR
) Target
;
3696 LunExtension
->Lun
= LunInfo
->Lun
= (UCHAR
)Lun
;
3698 /* Set flag to prevent race conditions */
3699 LunExtension
->Flags
|= SCSI_PORT_SCAN_IN_PROGRESS
;
3701 /* Zero LU extension contents */
3702 if (DeviceExtension
->LunExtensionSize
)
3704 RtlZeroMemory(LunExtension
+ 1,
3705 DeviceExtension
->LunExtensionSize
);
3708 /* Finally send the inquiry command */
3709 Status
= SpiSendInquiry(DeviceExtension
->DeviceObject
, LunInfo
);
3711 if (NT_SUCCESS(Status
))
3713 /* Let's see if we really found a device */
3714 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3716 /* Check if this device is unsupported */
3717 if (InquiryData
->DeviceTypeQualifier
== DEVICE_QUALIFIER_NOT_SUPPORTED
)
3719 DeviceExtension
->LunExtensionList
[Hint
] =
3720 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3725 /* Clear the "in scan" flag */
3726 LunExtension
->Flags
&= ~SCSI_PORT_SCAN_IN_PROGRESS
;
3728 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3729 InquiryData
->DeviceType
, Bus
, Target
, Lun
);
3731 /* Add this info to the linked list */
3732 LunInfo
->Next
= NULL
;
3734 LastLunInfo
->Next
= LunInfo
;
3736 BusScanInfo
->LunInfo
= LunInfo
;
3738 /* Store the last LUN info */
3739 LastLunInfo
= LunInfo
;
3741 /* Store DeviceObject */
3742 LunInfo
->DeviceObject
= DeviceExtension
->DeviceObject
;
3744 /* Allocate another buffer */
3745 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3749 DPRINT1("Out of resources!\n");
3753 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3755 /* Create a new LU extension */
3756 LunExtension
= SpiAllocateLunExtension(DeviceExtension
);
3762 /* Remove this LUN from the list */
3763 DeviceExtension
->LunExtensionList
[Hint
] =
3764 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3766 /* Decide whether we are continuing or not */
3767 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
3775 /* Free allocated buffers */
3777 ExFreePool(LunExtension
);
3780 ExFreePool(LunInfo
);
3782 /* Sum what we found */
3783 BusScanInfo
->LogicalUnitsCount
+= (UCHAR
) DevicesFound
;
3784 DPRINT(" Found %d devices on bus %d\n", DevicesFound
, Bus
);
3787 DPRINT ("SpiScanAdapter() done\n");
3792 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3795 ULONG InquiryDataSize
;
3796 PSCSI_LUN_INFO LunInfo
;
3797 ULONG BusCount
, LunCount
, Length
;
3798 PIO_STACK_LOCATION IrpStack
;
3799 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
3800 PSCSI_INQUIRY_DATA InquiryData
;
3801 PSCSI_BUS_DATA BusData
;
3805 DPRINT("SpiGetInquiryData() called\n");
3807 /* Get pointer to the buffer */
3808 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3809 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3811 /* Initialize bus and LUN counters */
3812 BusCount
= DeviceExtension
->BusesConfig
->NumberOfBuses
;
3815 /* Calculate total number of LUNs */
3816 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3817 LunCount
+= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3819 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
3821 ((sizeof(SCSI_INQUIRY_DATA
) - 1 + INQUIRYDATABUFFERSIZE
+
3822 sizeof(ULONG
) - 1) & ~(sizeof(ULONG
) - 1));
3824 /* Calculate data size */
3825 Length
= sizeof(SCSI_ADAPTER_BUS_INFO
) + (BusCount
- 1) *
3826 sizeof(SCSI_BUS_DATA
);
3828 Length
+= InquiryDataSize
* LunCount
;
3830 /* Check, if all data is going to fit into provided buffer */
3831 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< Length
)
3833 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3834 return STATUS_BUFFER_TOO_SMALL
;
3837 /* Store data size in the IRP */
3838 Irp
->IoStatus
.Information
= Length
;
3840 DPRINT("Data size: %lu\n", Length
);
3842 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
3844 AdapterBusInfo
->NumberOfBuses
= (UCHAR
)BusCount
;
3846 /* Point InquiryData to the corresponding place inside Buffer */
3847 InquiryData
= (PSCSI_INQUIRY_DATA
)(Buffer
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
3848 (BusCount
- 1) * sizeof(SCSI_BUS_DATA
));
3851 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3853 BusData
= &AdapterBusInfo
->BusData
[Bus
];
3855 /* Calculate and save an offset of the inquiry data */
3856 BusData
->InquiryDataOffset
= (PUCHAR
)InquiryData
- Buffer
;
3858 /* Get a pointer to the LUN information structure */
3859 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3861 /* Store Initiator Bus Id */
3862 BusData
->InitiatorBusId
=
3863 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->BusIdentifier
;
3865 /* Store LUN count */
3866 BusData
->NumberOfLogicalUnits
=
3867 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3870 while (LunInfo
!= NULL
)
3872 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
3873 Bus
, LunInfo
->TargetId
, LunInfo
->Lun
);
3875 /* Fill InquiryData with values */
3876 InquiryData
->PathId
= LunInfo
->PathId
;
3877 InquiryData
->TargetId
= LunInfo
->TargetId
;
3878 InquiryData
->Lun
= LunInfo
->Lun
;
3879 InquiryData
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
3880 InquiryData
->DeviceClaimed
= LunInfo
->DeviceClaimed
;
3881 InquiryData
->NextInquiryDataOffset
=
3882 (PUCHAR
)InquiryData
+ InquiryDataSize
- Buffer
;
3884 /* Copy data in it */
3885 RtlCopyMemory(InquiryData
->InquiryData
,
3886 LunInfo
->InquiryData
,
3887 INQUIRYDATABUFFERSIZE
);
3889 /* Move to the next LUN */
3890 LunInfo
= LunInfo
->Next
;
3891 InquiryData
= (PSCSI_INQUIRY_DATA
) ((PCHAR
)InquiryData
+ InquiryDataSize
);
3894 /* Either mark the end, or set offset to 0 */
3895 if (BusData
->NumberOfLogicalUnits
!= 0)
3896 ((PSCSI_INQUIRY_DATA
) ((PCHAR
) InquiryData
- InquiryDataSize
))->NextInquiryDataOffset
= 0;
3898 BusData
->InquiryDataOffset
= 0;
3901 /* Finish with success */
3902 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3903 return STATUS_SUCCESS
;
3906 static PSCSI_REQUEST_BLOCK_INFO
3907 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3913 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3915 if (QueueTag
== SP_UNTAGGED
)
3917 /* Untagged request, get LU and return pointer to SrbInfo */
3918 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3923 /* Return NULL in case of error */
3927 /* Return the pointer to SrbInfo */
3928 return &LunExtension
->SrbInfo
;
3932 /* Make sure the tag is valid, if it is - return the data */
3933 if (QueueTag
> DeviceExtension
->SrbDataCount
|| QueueTag
< 1)
3936 return &DeviceExtension
->SrbInfo
[QueueTag
-1];
3941 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3942 IN PSCSI_REQUEST_BLOCK InitialSrb
)
3944 PSCSI_REQUEST_BLOCK Srb
;
3947 PIO_STACK_LOCATION IrpStack
;
3948 LARGE_INTEGER LargeInt
;
3951 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb
);
3954 Srb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
) + sizeof(PVOID
), TAG_SCSIPORT
);
3955 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3958 LargeInt
.QuadPart
= (LONGLONG
) 1;
3959 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_READ
,
3960 DeviceExtension
->DeviceObject
,
3961 InitialSrb
->SenseInfoBuffer
,
3962 InitialSrb
->SenseInfoBufferLength
,
3966 IoSetCompletionRoutine(Irp
,
3967 (PIO_COMPLETION_ROUTINE
)SpiCompletionRoutine
,
3975 DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb
);
3979 IrpStack
= IoGetNextIrpStackLocation(Irp
);
3980 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3982 /* Put Srb address into Irp... */
3983 IrpStack
->Parameters
.Others
.Argument1
= (PVOID
)Srb
;
3985 /* ...and vice versa */
3986 Srb
->OriginalRequest
= Irp
;
3989 Ptr
= (PVOID
*)(Srb
+1);
3992 /* Build CDB for REQUEST SENSE */
3994 Cdb
= (PCDB
)Srb
->Cdb
;
3996 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
3997 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= 0;
3998 Cdb
->CDB6INQUIRY
.Reserved1
= 0;
3999 Cdb
->CDB6INQUIRY
.PageCode
= 0;
4000 Cdb
->CDB6INQUIRY
.IReserved
= 0;
4001 Cdb
->CDB6INQUIRY
.AllocationLength
= (UCHAR
)InitialSrb
->SenseInfoBufferLength
;
4002 Cdb
->CDB6INQUIRY
.Control
= 0;
4005 Srb
->TargetId
= InitialSrb
->TargetId
;
4006 Srb
->Lun
= InitialSrb
->Lun
;
4007 Srb
->PathId
= InitialSrb
->PathId
;
4009 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4010 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
4012 /* Timeout will be 2 seconds */
4013 Srb
->TimeOutValue
= 2;
4015 /* No auto request sense */
4016 Srb
->SenseInfoBufferLength
= 0;
4017 Srb
->SenseInfoBuffer
= NULL
;
4019 /* Set necessary flags */
4020 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_BYPASS_FROZEN_QUEUE
|
4021 SRB_FLAGS_DISABLE_DISCONNECT
;
4023 /* Transfer disable synch transfer flag */
4024 if (InitialSrb
->SrbFlags
& SRB_FLAGS_DISABLE_SYNCH_TRANSFER
)
4025 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4027 Srb
->DataBuffer
= InitialSrb
->SenseInfoBuffer
;
4029 /* Fill the transfer length */
4030 Srb
->DataTransferLength
= InitialSrb
->SenseInfoBufferLength
;
4032 /* Clear statuses */
4033 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
4036 /* Call the driver */
4037 (VOID
)IoCallDriver(DeviceExtension
->DeviceObject
, Irp
);
4039 DPRINT("SpiSendRequestSense() done\n");
4046 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4047 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
4048 OUT PBOOLEAN NeedToCallStartIo
)
4050 PSCSI_REQUEST_BLOCK Srb
;
4051 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4054 ULONG SequenceNumber
;
4057 Irp
= Srb
->OriginalRequest
;
4059 /* Get Lun extension */
4060 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4065 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
&&
4066 DeviceExtension
->MapBuffers
&&
4069 /* MDL is shared if transfer is broken into smaller parts */
4070 Srb
->DataBuffer
= (PCCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
4071 ((PCCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
4073 /* In case of data going in, flush the buffers */
4074 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
4076 KeFlushIoBuffers(Irp
->MdlAddress
,
4082 /* Flush adapter if needed */
4083 if (SrbInfo
->BaseOfMapRegister
)
4085 /* TODO: Implement */
4089 /* Clear the request */
4090 SrbInfo
->Srb
= NULL
;
4092 /* If disconnect is disabled... */
4093 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
4095 /* Acquire the spinlock since we mess with flags */
4096 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4098 /* Set corresponding flag */
4099 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
4101 /* Clear the timer if needed */
4102 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
))
4103 DeviceExtension
->TimerCount
= -1;
4105 /* Spinlock is not needed anymore */
4106 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4108 if (!(DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
) &&
4109 !(DeviceExtension
->Flags
& SCSI_PORT_DEVICE_BUSY
) &&
4110 !(*NeedToCallStartIo
))
4112 /* We're not busy, but we have a request pending */
4113 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4117 /* Scatter/gather */
4118 if (Srb
->SrbFlags
& SRB_FLAGS_SGLIST_FROM_POOL
)
4120 /* TODO: Implement */
4124 /* Acquire spinlock (we're freeing SrbExtension) */
4125 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4127 /* Free it (if needed) */
4128 if (Srb
->SrbExtension
)
4130 if (Srb
->SenseInfoBuffer
!= NULL
&& DeviceExtension
->SupportsAutoSense
)
4132 ASSERT(Srb
->SenseInfoBuffer
== NULL
|| SrbInfo
->SaveSenseRequest
!= NULL
);
4134 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)
4136 /* Copy sense data to the buffer */
4137 RtlCopyMemory(SrbInfo
->SaveSenseRequest
,
4138 Srb
->SenseInfoBuffer
,
4139 Srb
->SenseInfoBufferLength
);
4142 /* And restore the pointer */
4143 Srb
->SenseInfoBuffer
= SrbInfo
->SaveSenseRequest
;
4146 /* Put it into the free srb extensions list */
4147 *((PVOID
*)Srb
->SrbExtension
) = DeviceExtension
->FreeSrbExtensions
;
4148 DeviceExtension
->FreeSrbExtensions
= Srb
->SrbExtension
;
4151 /* Save transfer length in the IRP */
4152 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
4154 SequenceNumber
= SrbInfo
->SequenceNumber
;
4155 SrbInfo
->SequenceNumber
= 0;
4157 /* Decrement the queue count */
4158 LunExtension
->QueueCount
--;
4160 /* Free Srb, if needed*/
4161 if (Srb
->QueueTag
!= SP_UNTAGGED
)
4163 /* Put it into the free list */
4164 SrbInfo
->Requests
.Blink
= NULL
;
4165 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
4166 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
4169 /* SrbInfo is not used anymore */
4172 if (DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
)
4174 /* Clear the flag */
4175 DeviceExtension
->Flags
&= ~SCSI_PORT_REQUEST_PENDING
;
4177 /* Note the caller about StartIo */
4178 *NeedToCallStartIo
= TRUE
;
4181 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
4183 /* Start the packet */
4184 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4186 if (!(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
) &&
4187 LunExtension
->RequestTimeout
== -1)
4189 /* Start the next packet */
4190 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4194 /* Release the spinlock */
4195 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4198 DPRINT("IoCompleting request IRP 0x%p\n", Irp
);
4200 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4202 /* Decrement number of active requests, and analyze the result */
4203 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4206 !DeviceExtension
->MapRegisters
&&
4207 DeviceExtension
->AdapterObject
!= NULL
)
4209 /* Nullify map registers */
4210 DeviceExtension
->MapRegisterBase
= NULL
;
4211 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4214 /* Exit, we're done */
4218 /* Decrement number of active requests, and analyze the result */
4219 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4222 !DeviceExtension
->MapRegisters
&&
4223 DeviceExtension
->AdapterObject
!= NULL
)
4225 /* Result is negative, so this is a slave, free map registers */
4226 DeviceExtension
->MapRegisterBase
= NULL
;
4227 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4230 /* Convert status */
4231 Irp
->IoStatus
.Status
= SpiStatusSrbToNt(Srb
->SrbStatus
);
4233 /* It's not a bypass, it's busy or the queue is full? */
4234 if ((Srb
->ScsiStatus
== SCSISTAT_BUSY
||
4235 Srb
->SrbStatus
== SRB_STATUS_BUSY
||
4236 Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
) &&
4237 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
))
4240 DPRINT("Busy SRB status %x\n", Srb
->SrbStatus
);
4242 /* Requeu, if needed */
4243 if (LunExtension
->Flags
& (LUNEX_FROZEN_QUEUE
| LUNEX_BUSY
))
4245 DPRINT("it's being requeued\n");
4247 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4248 Srb
->ScsiStatus
= 0;
4250 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4251 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
4254 /* It's a big f.ck up if we got here */
4255 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
4256 Srb
->ScsiStatus
= SCSISTAT_BUSY
;
4262 /* Release the spinlock */
4263 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4266 else if (LunExtension
->AttemptCount
++ < 20)
4268 /* LUN is still busy */
4269 Srb
->ScsiStatus
= 0;
4270 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4272 LunExtension
->BusyRequest
= Irp
;
4273 LunExtension
->Flags
|= LUNEX_BUSY
;
4275 /* Release the spinlock */
4276 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4281 /* Freeze the queue*/
4282 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4283 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4285 /* "Unfull" the queue */
4286 LunExtension
->Flags
&= ~LUNEX_FULL_QUEUE
;
4288 /* Release the spinlock */
4289 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4291 /* Return status that the device is not ready */
4292 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
4293 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4299 /* Start the next request, if LUN is idle, and this is sense request */
4300 if (((Srb
->ScsiStatus
!= SCSISTAT_CHECK_CONDITION
) ||
4301 (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) ||
4302 !Srb
->SenseInfoBuffer
|| !Srb
->SenseInfoBufferLength
)
4303 && (Srb
->SrbFlags
& SRB_FLAGS_NO_QUEUE_FREEZE
))
4305 if (LunExtension
->RequestTimeout
== -1)
4306 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4308 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4312 /* Freeze the queue */
4313 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4314 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4316 /* Do we need a request sense? */
4317 if (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4318 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
4319 Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
)
4321 /* If LUN is busy, we have to requeue it in order to allow request sense */
4322 if (LunExtension
->Flags
& LUNEX_BUSY
)
4324 DPRINT("Requeueing busy request to allow request sense\n");
4326 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4327 &LunExtension
->BusyRequest
->Tail
.Overlay
.DeviceQueueEntry
,
4330 /* We should never get here */
4333 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4334 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4339 /* Clear busy flags */
4340 LunExtension
->Flags
&= ~(LUNEX_FULL_QUEUE
| LUNEX_BUSY
);
4343 /* Release the spinlock */
4344 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4346 /* Send RequestSense */
4347 SpiSendRequestSense(DeviceExtension
, Srb
);
4353 /* Release the spinlock */
4354 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4357 /* Complete the request */
4358 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4363 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
4367 PSCSI_REQUEST_BLOCK Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
4368 PSCSI_REQUEST_BLOCK InitialSrb
;
4371 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp
);
4373 if ((Srb
->Function
== SRB_FUNCTION_RESET_BUS
) ||
4374 (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
))
4376 /* Deallocate SRB and IRP and exit */
4380 return STATUS_MORE_PROCESSING_REQUIRED
;
4383 /* Get a pointer to the SRB and IRP which were initially sent */
4384 InitialSrb
= *((PVOID
*)(Srb
+1));
4385 InitialIrp
= InitialSrb
->OriginalRequest
;
4387 if ((SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
) ||
4388 (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_DATA_OVERRUN
))
4390 /* Sense data is OK */
4391 InitialSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
4393 /* Set length to be the same */
4394 InitialSrb
->SenseInfoBufferLength
= (UCHAR
)Srb
->DataTransferLength
;
4397 /* Make sure initial SRB's queue is frozen */
4398 ASSERT(InitialSrb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
);
4400 /* Complete this request */
4401 IoCompleteRequest(InitialIrp
, IO_DISK_INCREMENT
);
4403 /* Deallocate everything (internal) */
4406 if (Irp
->MdlAddress
!= NULL
)
4408 /* We don't need to unlock this MDL because the request could
4409 * only have come from dispatch level */
4410 IoFreeMdl(Irp
->MdlAddress
);
4411 Irp
->MdlAddress
= NULL
;
4415 return STATUS_MORE_PROCESSING_REQUIRED
;
4418 static BOOLEAN STDCALL
4419 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
4420 IN PVOID ServiceContext
)
4422 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4425 DPRINT("ScsiPortIsr() called!\n");
4427 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
4429 /* If interrupts are disabled - we don't expect any */
4430 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_DISABLE_INTERRUPTS
)
4433 /* Call miniport's HwInterrupt routine */
4434 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
4436 /* If flag of notification is set - queue a DPC */
4437 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4439 IoRequestDpc(DeviceExtension
->DeviceObject
,
4440 DeviceExtension
->CurrentIrp
,
4449 SpiSaveInterruptData(IN PVOID Context
)
4451 PSCSI_PORT_SAVE_INTERRUPT InterruptContext
= Context
;
4452 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4453 PSCSI_REQUEST_BLOCK Srb
;
4454 PSCSI_REQUEST_BLOCK_INFO SrbInfo
, NextSrbInfo
;
4455 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4458 /* Get pointer to the device extension */
4459 DeviceExtension
= InterruptContext
->DeviceExtension
;
4461 /* If we don't have anything pending - return */
4462 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
))
4465 /* Actually save the interrupt data */
4466 *InterruptContext
->InterruptData
= DeviceExtension
->InterruptData
;
4468 /* Clear the data stored in the device extension */
4469 DeviceExtension
->InterruptData
.Flags
&=
4470 (SCSI_PORT_RESET
| SCSI_PORT_RESET_REQUEST
| SCSI_PORT_DISABLE_INTERRUPTS
);
4471 DeviceExtension
->InterruptData
.CompletedAbort
= NULL
;
4472 DeviceExtension
->InterruptData
.ReadyLun
= NULL
;
4473 DeviceExtension
->InterruptData
.CompletedRequests
= NULL
;
4475 /* Loop through the list of completed requests */
4476 SrbInfo
= InterruptContext
->InterruptData
->CompletedRequests
;
4480 /* Make sure we have SRV */
4481 ASSERT(SrbInfo
->Srb
);
4483 /* Get SRB and LunExtension */
4486 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4491 /* We have to check special cases if request is unsuccessfull*/
4492 if (Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
)
4494 /* Check if we need request sense by a few conditions */
4495 if (Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
&&
4496 Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4497 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
))
4499 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
4501 /* It means: we tried to send REQUEST SENSE, but failed */
4503 Srb
->ScsiStatus
= 0;
4504 Srb
->SrbStatus
= SRB_STATUS_REQUEST_SENSE_FAILED
;
4508 /* Set the corresponding flag, so that REQUEST SENSE
4510 LunExtension
->Flags
|= LUNEX_NEED_REQUEST_SENSE
;
4515 /* Check for a full queue */
4516 if (Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
)
4518 /* TODO: Implement when it's encountered */
4523 /* Let's decide if we need to watch timeout or not */
4524 if (Srb
->QueueTag
== SP_UNTAGGED
)
4530 if (LunExtension
->SrbInfo
.Requests
.Flink
== &SrbInfo
->Requests
)
4535 /* Remove it from the queue */
4536 RemoveEntryList(&SrbInfo
->Requests
);
4541 /* We have to maintain timeout counter */
4542 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
))
4544 LunExtension
->RequestTimeout
= -1;
4548 NextSrbInfo
= CONTAINING_RECORD(LunExtension
->SrbInfo
.Requests
.Flink
,
4549 SCSI_REQUEST_BLOCK_INFO
,
4552 Srb
= NextSrbInfo
->Srb
;
4554 /* Update timeout counter */
4555 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
4559 SrbInfo
= SrbInfo
->CompletedRequests
;
4567 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4568 IN PSCSI_PORT_LUN_EXTENSION LunExtension
)
4570 PIO_STACK_LOCATION IrpStack
;
4572 PKDEVICE_QUEUE_ENTRY Entry
;
4573 PSCSI_REQUEST_BLOCK Srb
;
4576 /* If LUN is not active or queue is more than maximum allowed */
4577 if (LunExtension
->QueueCount
>= LunExtension
->MaxQueueCount
||
4578 !(LunExtension
->Flags
& SCSI_PORT_LU_ACTIVE
))
4580 /* Release the spinlock and exit */
4581 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4585 /* Check if we can get a next request */
4586 if (LunExtension
->Flags
&
4587 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_BUSY
|
4588 LUNEX_FULL_QUEUE
| LUNEX_FROZEN_QUEUE
| LUNEX_REQUEST_PENDING
))
4590 /* Pending requests can only be started if the queue is empty */
4591 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
) &&
4592 !(LunExtension
->Flags
&
4593 (LUNEX_BUSY
| LUNEX_FROZEN_QUEUE
| LUNEX_FULL_QUEUE
| LUNEX_NEED_REQUEST_SENSE
)))
4595 /* Make sure we have SRB */
4596 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
4598 /* Clear active and pending flags */
4599 LunExtension
->Flags
&= ~(LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
);
4601 /* Get next Irp, and clear pending requests list */
4602 NextIrp
= LunExtension
->PendingRequest
;
4603 LunExtension
->PendingRequest
= NULL
;
4605 /* Set attempt counter to zero */
4606 LunExtension
->AttemptCount
= 0;
4608 /* Release the spinlock */
4609 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4611 /* Start the next pending request */
4612 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4618 /* Release the spinlock, without clearing any flags and exit */
4619 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4625 /* Reset active flag */
4626 LunExtension
->Flags
&= ~SCSI_PORT_LU_ACTIVE
;
4628 /* Set attempt counter to zero */
4629 LunExtension
->AttemptCount
= 0;
4631 /* Remove packet from the device queue */
4632 Entry
= KeRemoveByKeyDeviceQueue(&LunExtension
->DeviceQueue
, LunExtension
->SortKey
);
4636 /* Get pointer to the next irp */
4637 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
4639 /* Get point to the SRB */
4640 IrpStack
= IoGetCurrentIrpStackLocation(NextIrp
);
4641 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
4644 LunExtension
->SortKey
= Srb
->QueueSortKey
;
4645 LunExtension
->SortKey
++;
4647 /* Release the spinlock */
4648 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4650 /* Start the next pending request */
4651 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4655 /* Release the spinlock */
4656 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4662 // ScsiPortDpcForIsr
4669 // IN PDEVICE_OBJECT DpcDeviceObject
4671 // IN PVOID DpcContext
4674 ScsiPortDpcForIsr(IN PKDPC Dpc
,
4675 IN PDEVICE_OBJECT DpcDeviceObject
,
4677 IN PVOID DpcContext
)
4679 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DpcDeviceObject
->DeviceExtension
;
4680 SCSI_PORT_INTERRUPT_DATA InterruptData
;
4681 SCSI_PORT_SAVE_INTERRUPT Context
;
4682 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4683 BOOLEAN NeedToStartIo
;
4684 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
4686 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4687 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
4689 /* We need to acquire spinlock */
4690 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4692 RtlZeroMemory(&InterruptData
, sizeof(SCSI_PORT_INTERRUPT_DATA
));
4696 /* Interrupt structure must be snapshotted, and only then analyzed */
4697 Context
.InterruptData
= &InterruptData
;
4698 Context
.DeviceExtension
= DeviceExtension
;
4700 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4701 SpiSaveInterruptData
,
4704 /* Nothing - just return (don't forget to release the spinlock */
4705 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4706 DPRINT("ScsiPortDpcForIsr() done\n");
4710 /* If flush of adapters is needed - do it */
4711 if (InterruptData
.Flags
& SCSI_PORT_FLUSH_ADAPTERS
)
4713 /* TODO: Implement */
4717 /* Check for IoMapTransfer */
4718 if (InterruptData
.Flags
& SCSI_PORT_MAP_TRANSFER
)
4720 /* TODO: Implement */
4724 /* Check if timer is needed */
4725 if (InterruptData
.Flags
& SCIS_PORT_TIMER_NEEDED
)
4727 /* TODO: Implement */
4731 /* If it's ready for the next request */
4732 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4734 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4735 if ((DeviceExtension
->Flags
&
4736 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
)) ==
4737 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
))
4739 /* Clear busy flag set by ScsiPortStartPacket() */
4740 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4742 if (!(InterruptData
.Flags
& SCSI_PORT_RESET
))
4744 /* Ready for next, and no reset is happening */
4745 DeviceExtension
->TimerCount
= -1;
4750 /* Not busy, but not ready for the next request */
4751 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4752 InterruptData
.Flags
&= ~SCSI_PORT_NEXT_REQUEST_READY
;
4757 if (InterruptData
.Flags
& SCSI_PORT_RESET_REPORTED
)
4759 /* Hold for a bit */
4760 DeviceExtension
->TimerCount
= 4;
4763 /* Any ready LUN? */
4764 if (InterruptData
.ReadyLun
!= NULL
)
4767 /* Process all LUNs from the list*/
4770 /* Remove it from the list first (as processed) */
4771 LunExtension
= InterruptData
.ReadyLun
;
4772 InterruptData
.ReadyLun
= LunExtension
->ReadyLun
;
4773 LunExtension
->ReadyLun
= NULL
;
4775 /* Get next request for this LUN */
4776 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4778 /* Still ready requests exist?
4779 If yes - get spinlock, if no - stop here */
4780 if (InterruptData
.ReadyLun
!= NULL
)
4781 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4788 /* Release the spinlock */
4789 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4792 /* If we ready for next packet, start it */
4793 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4794 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4796 NeedToStartIo
= FALSE
;
4798 /* Loop the completed request list */
4799 while (InterruptData
.CompletedRequests
)
4801 /* Remove the request */
4802 SrbInfo
= InterruptData
.CompletedRequests
;
4803 InterruptData
.CompletedRequests
= SrbInfo
->CompletedRequests
;
4804 SrbInfo
->CompletedRequests
= NULL
;
4807 SpiProcessCompletedRequest(DeviceExtension
,
4812 /* Loop abort request list */
4813 while (InterruptData
.CompletedAbort
)
4815 LunExtension
= InterruptData
.CompletedAbort
;
4817 /* Remove the request */
4818 InterruptData
.CompletedAbort
= LunExtension
->CompletedAbortRequests
;
4820 /* Get spinlock since we're going to change flags */
4821 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4823 /* TODO: Put SrbExtension to the list of free extensions */
4827 /* If we need - call StartIo routine */
4830 /* Make sure CurrentIrp is not null! */
4831 ASSERT(DpcDeviceObject
->CurrentIrp
!= NULL
);
4832 ScsiPortStartIo(DpcDeviceObject
, DpcDeviceObject
->CurrentIrp
);
4835 /* Everything has been done, check */
4836 if (InterruptData
.Flags
& SCSI_PORT_ENABLE_INT_REQUEST
)
4838 /* Synchronize using spinlock */
4839 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4841 /* Request an interrupt */
4842 DeviceExtension
->HwInterrupt(DeviceExtension
->MiniPortDeviceExtension
);
4844 ASSERT(DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
);
4846 /* Should interrupts be enabled again? */
4847 if (DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
)
4849 /* Clear this flag */
4850 DeviceExtension
->Flags
&= ~SCSI_PORT_DISABLE_INT_REQUESET
;
4852 /* Call a special routine to do this */
4855 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4856 SpiEnableInterrupts
,
4861 /* If we need a notification again - loop */
4862 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4865 /* Release the spinlock */
4866 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4869 DPRINT("ScsiPortDpcForIsr() done\n");
4874 SpiProcessTimeout(PVOID ServiceContext
)
4876 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
4877 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
4880 DPRINT("SpiProcessTimeout() entered\n");
4882 DeviceExtension
->TimerCount
= -1;
4884 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
4886 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET
;
4888 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET_REQUEST
)
4890 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET_REQUEST
;
4891 ScsiPortStartPacket(ServiceContext
);
4898 DPRINT("Resetting the bus\n");
4900 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
4902 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
, Bus
);
4904 /* Reset flags and set reset timeout to 4 seconds */
4905 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
4906 DeviceExtension
->TimerCount
= 4;
4909 /* If miniport requested - request a dpc for it */
4910 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4911 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
4920 SpiResetBus(PVOID ServiceContext
)
4922 PRESETBUS_PARAMS ResetParams
= (PRESETBUS_PARAMS
)ServiceContext
;
4923 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4925 /* Perform the bus reset */
4926 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ResetParams
->DeviceExtension
;
4927 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
,
4928 ResetParams
->PathId
);
4930 /* Set flags and start the timer */
4931 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
4932 DeviceExtension
->TimerCount
= 4;
4934 /* If miniport requested - give him a DPC */
4935 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4936 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
4943 // This function handles timeouts and other time delayed processing
4948 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
4949 // IN PVOID Context the Controller extension for the
4950 // controller the device is on
4953 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
4956 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4957 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4961 DPRINT("ScsiPortIoTimer()\n");
4963 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
4965 /* Protect with the spinlock */
4966 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4968 /* Check timeouts */
4969 if (DeviceExtension
->TimerCount
> 0)
4971 /* Decrease the timeout counter */
4972 DeviceExtension
->TimerCount
--;
4974 if (DeviceExtension
->TimerCount
== 0)
4976 /* Timeout, process it */
4977 if (KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4979 DeviceExtension
->DeviceObject
))
4981 DPRINT("Error happened during processing timeout, but nothing critical\n");
4985 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4987 /* We should exit now, since timeout is processed */
4991 /* Per-Lun scanning of timeouts is needed... */
4992 for (Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
4994 LunExtension
= DeviceExtension
->LunExtensionList
[Lun
];
4996 while (LunExtension
)
4998 if (LunExtension
->Flags
& LUNEX_BUSY
)
5000 if (!(LunExtension
->Flags
&
5001 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_FROZEN_QUEUE
)))
5003 DPRINT("Retrying busy request\n");
5005 /* Clear flags, and retry busy request */
5006 LunExtension
->Flags
&= ~(LUNEX_BUSY
| LUNEX_FULL_QUEUE
);
5007 Irp
= LunExtension
->BusyRequest
;
5009 /* Clearing busy request */
5010 LunExtension
->BusyRequest
= NULL
;
5012 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5014 IoStartPacket(DeviceObject
, Irp
, (PULONG
)NULL
, NULL
);
5016 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5019 else if (LunExtension
->RequestTimeout
== 0)
5021 RESETBUS_PARAMS ResetParams
;
5023 LunExtension
->RequestTimeout
= -1;
5025 DPRINT("Request timed out, resetting bus\n");
5027 /* Pass params to the bus reset routine */
5028 ResetParams
.PathId
= LunExtension
->PathId
;
5029 ResetParams
.DeviceExtension
= DeviceExtension
;
5031 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
5035 DPRINT1("Reset failed\n");
5038 else if (LunExtension
->RequestTimeout
> 0)
5040 /* Decrement the timeout counter */
5041 LunExtension
->RequestTimeout
--;
5044 LunExtension
= LunExtension
->Next
;
5048 /* Release the spinlock */
5049 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5052 /**********************************************************************
5057 * Builds the registry device map of all device which are attached
5058 * to the given SCSI HBA port. The device map is located at:
5059 * \Registry\Machine\DeviceMap\Scsi
5069 * Name of registry driver service key.
5076 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5077 PUNICODE_STRING RegistryPath
)
5079 PSCSI_PORT_LUN_EXTENSION LunExtension
;
5080 OBJECT_ATTRIBUTES ObjectAttributes
;
5081 UNICODE_STRING KeyName
;
5082 UNICODE_STRING ValueName
;
5083 WCHAR NameBuffer
[64];
5086 HANDLE ScsiPortKey
= NULL
;
5087 HANDLE ScsiBusKey
= NULL
;
5088 HANDLE ScsiInitiatorKey
= NULL
;
5089 HANDLE ScsiTargetKey
= NULL
;
5090 HANDLE ScsiLunKey
= NULL
;
5093 ULONG CurrentTarget
;
5100 DPRINT("SpiBuildDeviceMap() called\n");
5102 if (DeviceExtension
== NULL
|| RegistryPath
== NULL
)
5104 DPRINT1("Invalid parameter\n");
5105 return(STATUS_INVALID_PARAMETER
);
5108 /* Open or create the 'Scsi' subkey */
5109 RtlInitUnicodeString(&KeyName
,
5110 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
5111 InitializeObjectAttributes(&ObjectAttributes
,
5113 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
5116 Status
= ZwCreateKey(&ScsiKey
,
5121 REG_OPTION_VOLATILE
,
5123 if (!NT_SUCCESS(Status
))
5125 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5129 /* Create new 'Scsi Port X' subkey */
5130 DPRINT("Scsi Port %lu\n",
5131 DeviceExtension
->PortNumber
);
5133 swprintf(NameBuffer
,
5135 DeviceExtension
->PortNumber
);
5136 RtlInitUnicodeString(&KeyName
,
5138 InitializeObjectAttributes(&ObjectAttributes
,
5143 Status
= ZwCreateKey(&ScsiPortKey
,
5148 REG_OPTION_VOLATILE
,
5151 if (!NT_SUCCESS(Status
))
5153 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5158 * Create port-specific values
5161 /* Set 'DMA Enabled' (REG_DWORD) value */
5162 UlongData
= (ULONG
)!DeviceExtension
->PortCapabilities
.AdapterUsesPio
;
5163 DPRINT(" DMA Enabled = %s\n", (UlongData
) ? "TRUE" : "FALSE");
5164 RtlInitUnicodeString(&ValueName
,
5166 Status
= ZwSetValueKey(ScsiPortKey
,
5172 if (!NT_SUCCESS(Status
))
5174 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status
);
5175 ZwClose(ScsiPortKey
);
5179 /* Set 'Driver' (REG_SZ) value */
5180 DriverName
= wcsrchr(RegistryPath
->Buffer
, L
'\\') + 1;
5181 RtlInitUnicodeString(&ValueName
,
5183 Status
= ZwSetValueKey(ScsiPortKey
,
5188 (wcslen(DriverName
) + 1) * sizeof(WCHAR
));
5189 if (!NT_SUCCESS(Status
))
5191 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status
);
5192 ZwClose(ScsiPortKey
);
5196 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
5197 UlongData
= (ULONG
)DeviceExtension
->PortConfig
->BusInterruptLevel
;
5198 DPRINT(" Interrupt = %lu\n", UlongData
);
5199 RtlInitUnicodeString(&ValueName
,
5201 Status
= ZwSetValueKey(ScsiPortKey
,
5207 if (!NT_SUCCESS(Status
))
5209 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status
);
5210 ZwClose(ScsiPortKey
);
5214 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
5215 UlongData
= ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension
->PortConfig
->AccessRanges
)[0].RangeStart
);
5216 DPRINT(" IOAddress = %lx\n", UlongData
);
5217 RtlInitUnicodeString(&ValueName
,
5219 Status
= ZwSetValueKey(ScsiPortKey
,
5225 if (!NT_SUCCESS(Status
))
5227 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status
);
5228 ZwClose(ScsiPortKey
);
5232 /* Enumerate buses */
5233 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
->NumberOfBuses
; BusNumber
++)
5235 /* Create 'Scsi Bus X' key */
5236 DPRINT(" Scsi Bus %lu\n", BusNumber
);
5237 swprintf(NameBuffer
,
5240 RtlInitUnicodeString(&KeyName
,
5242 InitializeObjectAttributes(&ObjectAttributes
,
5247 Status
= ZwCreateKey(&ScsiBusKey
,
5252 REG_OPTION_VOLATILE
,
5254 if (!NT_SUCCESS(Status
))
5256 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5260 /* Create 'Initiator Id X' key */
5261 DPRINT(" Initiator Id %u\n",
5262 DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5263 swprintf(NameBuffer
,
5265 (unsigned int)(UCHAR
)DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5266 RtlInitUnicodeString(&KeyName
,
5268 InitializeObjectAttributes(&ObjectAttributes
,
5273 Status
= ZwCreateKey(&ScsiInitiatorKey
,
5278 REG_OPTION_VOLATILE
,
5280 if (!NT_SUCCESS(Status
))
5282 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5286 /* FIXME: Are there any initiator values (??) */
5288 ZwClose(ScsiInitiatorKey
);
5289 ScsiInitiatorKey
= NULL
;
5292 /* Enumerate targets */
5293 CurrentTarget
= (ULONG
)-1;
5294 ScsiTargetKey
= NULL
;
5295 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
5297 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
5299 LunExtension
= SpiGetLunExtension(DeviceExtension
,
5303 if (LunExtension
!= NULL
)
5305 if (Target
!= CurrentTarget
)
5307 /* Close old target key */
5308 if (ScsiTargetKey
!= NULL
)
5310 ZwClose(ScsiTargetKey
);
5311 ScsiTargetKey
= NULL
;
5314 /* Create 'Target Id X' key */
5315 DPRINT(" Target Id %lu\n", Target
);
5316 swprintf(NameBuffer
,
5319 RtlInitUnicodeString(&KeyName
,
5321 InitializeObjectAttributes(&ObjectAttributes
,
5326 Status
= ZwCreateKey(&ScsiTargetKey
,
5331 REG_OPTION_VOLATILE
,
5333 if (!NT_SUCCESS(Status
))
5335 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5339 CurrentTarget
= Target
;
5342 /* Create 'Logical Unit Id X' key */
5343 DPRINT(" Logical Unit Id %lu\n", Lun
);
5344 swprintf(NameBuffer
,
5345 L
"Logical Unit Id %lu",
5347 RtlInitUnicodeString(&KeyName
,
5349 InitializeObjectAttributes(&ObjectAttributes
,
5354 Status
= ZwCreateKey(&ScsiLunKey
,
5359 REG_OPTION_VOLATILE
,
5361 if (!NT_SUCCESS(Status
))
5363 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5367 /* Set 'Identifier' (REG_SZ) value */
5368 swprintf(NameBuffer
,
5370 LunExtension
->InquiryData
.VendorId
,
5371 LunExtension
->InquiryData
.ProductId
,
5372 LunExtension
->InquiryData
.ProductRevisionLevel
);
5373 DPRINT(" Identifier = '%S'\n", NameBuffer
);
5374 RtlInitUnicodeString(&ValueName
,
5376 Status
= ZwSetValueKey(ScsiLunKey
,
5381 (wcslen(NameBuffer
) + 1) * sizeof(WCHAR
));
5382 if (!NT_SUCCESS(Status
))
5384 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status
);
5388 /* Set 'Type' (REG_SZ) value */
5389 switch (LunExtension
->InquiryData
.DeviceType
)
5392 TypeName
= L
"DiskPeripheral";
5395 TypeName
= L
"TapePeripheral";
5398 TypeName
= L
"PrinterPeripheral";
5401 TypeName
= L
"WormPeripheral";
5404 TypeName
= L
"CdRomPeripheral";
5407 TypeName
= L
"ScannerPeripheral";
5410 TypeName
= L
"OpticalDiskPeripheral";
5413 TypeName
= L
"MediumChangerPeripheral";
5416 TypeName
= L
"CommunicationPeripheral";
5419 TypeName
= L
"OtherPeripheral";
5422 DPRINT(" Type = '%S'\n", TypeName
);
5423 RtlInitUnicodeString(&ValueName
,
5425 Status
= ZwSetValueKey(ScsiLunKey
,
5430 (wcslen(TypeName
) + 1) * sizeof(WCHAR
));
5431 if (!NT_SUCCESS(Status
))
5433 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status
);
5437 ZwClose(ScsiLunKey
);
5442 /* Close old target key */
5443 if (ScsiTargetKey
!= NULL
)
5445 ZwClose(ScsiTargetKey
);
5446 ScsiTargetKey
= NULL
;
5450 ZwClose(ScsiBusKey
);
5455 if (ScsiLunKey
!= NULL
)
5456 ZwClose (ScsiLunKey
);
5458 if (ScsiInitiatorKey
!= NULL
)
5459 ZwClose (ScsiInitiatorKey
);
5461 if (ScsiTargetKey
!= NULL
)
5462 ZwClose (ScsiTargetKey
);
5464 if (ScsiBusKey
!= NULL
)
5465 ZwClose (ScsiBusKey
);
5467 if (ScsiPortKey
!= NULL
)
5468 ZwClose (ScsiPortKey
);
5470 DPRINT("SpiBuildDeviceMap() done\n");
5477 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
5478 IN PVOID DeviceObject
,
5479 IN PVOID SystemArgument1
,
5480 IN PVOID SystemArgument2
)
5482 DPRINT1("Miniport timer DPC\n");
5487 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5488 PHW_INITIALIZATION_DATA HwInitData
,
5489 PCONFIGURATION_INFO InternalConfigInfo
,
5490 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5493 UNICODE_STRING UnicodeString
;
5494 OBJECT_ATTRIBUTES ObjectAttributes
;
5495 PCONFIGURATION_INFORMATION DdkConfigInformation
;
5496 HANDLE RootKey
, Key
;
5498 WCHAR DeviceBuffer
[16];
5499 WCHAR StrBuffer
[512];
5503 /* Zero out the struct if told so */
5506 /* First zero the portconfig */
5507 RtlZeroMemory(ConfigInfo
, sizeof(PORT_CONFIGURATION_INFORMATION
));
5509 /* Then access ranges */
5510 RtlZeroMemory(InternalConfigInfo
->AccessRanges
,
5511 HwInitData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
5513 /* Initialize the struct */
5514 ConfigInfo
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
5515 ConfigInfo
->AdapterInterfaceType
= HwInitData
->AdapterInterfaceType
;
5516 ConfigInfo
->InterruptMode
= Latched
;
5517 ConfigInfo
->DmaChannel
= SP_UNINITIALIZED_VALUE
;
5518 ConfigInfo
->DmaPort
= SP_UNINITIALIZED_VALUE
;
5519 ConfigInfo
->MaximumTransferLength
= SP_UNINITIALIZED_VALUE
;
5520 ConfigInfo
->NumberOfAccessRanges
= HwInitData
->NumberOfAccessRanges
;
5521 ConfigInfo
->MaximumNumberOfTargets
= 8;
5523 /* Store parameters */
5524 ConfigInfo
->NeedPhysicalAddresses
= HwInitData
->NeedPhysicalAddresses
;
5525 ConfigInfo
->MapBuffers
= HwInitData
->MapBuffers
;
5526 ConfigInfo
->AutoRequestSense
= HwInitData
->AutoRequestSense
;
5527 ConfigInfo
->ReceiveEvent
= HwInitData
->ReceiveEvent
;
5528 ConfigInfo
->TaggedQueuing
= HwInitData
->TaggedQueuing
;
5529 ConfigInfo
->MultipleRequestPerLu
= HwInitData
->MultipleRequestPerLu
;
5531 /* Get the disk usage */
5532 DdkConfigInformation
= IoGetConfigurationInformation();
5533 ConfigInfo
->AtdiskPrimaryClaimed
= DdkConfigInformation
->AtDiskPrimaryAddressClaimed
;
5534 ConfigInfo
->AtdiskSecondaryClaimed
= DdkConfigInformation
->AtDiskSecondaryAddressClaimed
;
5536 /* Initiator bus id is not set */
5537 for (Bus
= 0; Bus
< 8; Bus
++)
5538 ConfigInfo
->InitiatorBusId
[Bus
] = (CCHAR
)SP_UNINITIALIZED_VALUE
;
5541 ConfigInfo
->NumberOfPhysicalBreaks
= 17;
5543 /* Clear this information */
5544 InternalConfigInfo
->DisableTaggedQueueing
= FALSE
;
5545 InternalConfigInfo
->DisableMultipleLun
= FALSE
;
5547 /* Store Bus Number */
5548 ConfigInfo
->SystemIoBusNumber
= InternalConfigInfo
->BusNumber
;
5552 if (ConfigInfo
->AdapterInterfaceType
== Internal
)
5554 /* Open registry key for HW database */
5555 InitializeObjectAttributes(&ObjectAttributes
,
5556 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
5557 OBJ_CASE_INSENSITIVE
,
5561 Status
= ZwOpenKey(&RootKey
,
5565 if (NT_SUCCESS(Status
))
5567 /* Create name for it */
5568 swprintf(StrBuffer
, L
"ScsiAdapter\\%lu",
5569 InternalConfigInfo
->AdapterNumber
);
5571 RtlInitUnicodeString(&UnicodeString
, StrBuffer
);
5573 /* Open device key */
5574 InitializeObjectAttributes(&ObjectAttributes
,
5576 OBJ_CASE_INSENSITIVE
,
5580 Status
= ZwOpenKey(&Key
,
5586 if (NT_SUCCESS(Status
))
5588 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5590 DPRINT("Hardware info found at %S\n", StrBuffer
);
5593 SpiParseDeviceInfo(DeviceExtension
,
5599 InternalConfigInfo
->BusNumber
= 0;
5603 /* Try the next adapter */
5604 InternalConfigInfo
->AdapterNumber
++;
5610 /* Info was not found, exit */
5611 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status
);
5612 return STATUS_DEVICE_DOES_NOT_EXIST
;
5617 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status
);
5621 /* Look at device params */
5623 if (InternalConfigInfo
->Parameter
)
5625 ExFreePool(InternalConfigInfo
->Parameter
);
5626 InternalConfigInfo
->Parameter
= NULL
;
5629 if (InternalConfigInfo
->ServiceKey
!= NULL
)
5631 swprintf(DeviceBuffer
, L
"Device%lu", InternalConfigInfo
->AdapterNumber
);
5632 RtlInitUnicodeString(&UnicodeString
, DeviceBuffer
);
5634 /* Open the service key */
5635 InitializeObjectAttributes(&ObjectAttributes
,
5637 OBJ_CASE_INSENSITIVE
,
5638 InternalConfigInfo
->ServiceKey
,
5641 Status
= ZwOpenKey(&Key
,
5646 /* Parse device key */
5647 if (InternalConfigInfo
->DeviceKey
!= NULL
)
5649 SpiParseDeviceInfo(DeviceExtension
,
5650 InternalConfigInfo
->DeviceKey
,
5656 /* Then parse hw info */
5659 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5661 SpiParseDeviceInfo(DeviceExtension
,
5672 /* Adapter not found, go try the next one */
5673 InternalConfigInfo
->AdapterNumber
++;
5682 /* Update the last adapter number */
5683 InternalConfigInfo
->LastAdapterNumber
= InternalConfigInfo
->AdapterNumber
;
5685 /* Do we have this kind of bus at all? */
5687 Status
= IoQueryDeviceDescription(&HwInitData
->AdapterInterfaceType
,
5688 &InternalConfigInfo
->BusNumber
,
5693 SpQueryDeviceCallout
,
5696 /* This bus was not found */
5699 INTERFACE_TYPE InterfaceType
= Eisa
;
5701 /* Check for EISA */
5702 if (HwInitData
->AdapterInterfaceType
== Isa
)
5704 Status
= IoQueryDeviceDescription(&InterfaceType
,
5705 &InternalConfigInfo
->BusNumber
,
5710 SpQueryDeviceCallout
,
5713 /* Return respectively */
5715 return STATUS_SUCCESS
;
5717 return STATUS_DEVICE_DOES_NOT_EXIST
;
5721 return STATUS_DEVICE_DOES_NOT_EXIST
;
5726 return STATUS_SUCCESS
;
5731 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5733 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5734 IN PCONFIGURATION_INFO InternalConfigInfo
,
5737 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
5738 PCM_FULL_RESOURCE_DESCRIPTOR FullResource
;
5739 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
5740 PCM_SCSI_DEVICE_DATA ScsiDeviceData
;
5741 ULONG Length
, Count
;
5742 ULONG Index
= 0, RangeCount
= 0;
5743 UNICODE_STRING UnicodeString
;
5744 ANSI_STRING AnsiString
;
5745 NTSTATUS Status
= STATUS_SUCCESS
;
5747 KeyValueInformation
= (PKEY_VALUE_FULL_INFORMATION
) Buffer
;
5749 /* Loop through all values in the device node */
5752 Status
= ZwEnumerateValueKey(Key
,
5754 KeyValueFullInformation
,
5759 if (!NT_SUCCESS(Status
))
5764 /* Length for DWORD is ok? */
5765 if (KeyValueInformation
->Type
== REG_DWORD
&&
5766 KeyValueInformation
->DataLength
!= sizeof(ULONG
))
5771 /* Get MaximumLogicalUnit */
5772 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumLogicalUnit",
5773 KeyValueInformation
->NameLength
/2) == 0)
5776 if (KeyValueInformation
->Type
!= REG_DWORD
)
5778 DPRINT("Bad data type for MaximumLogicalUnit\n");
5782 DeviceExtension
->MaxLunCount
= *((PUCHAR
)
5783 (Buffer
+ KeyValueInformation
->DataOffset
));
5785 /* Check / reset if needed */
5786 if (DeviceExtension
->MaxLunCount
> SCSI_MAXIMUM_LOGICAL_UNITS
)
5787 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
5789 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension
->MaxLunCount
);
5792 /* Get InitiatorTargetId */
5793 if (_wcsnicmp(KeyValueInformation
->Name
, L
"InitiatorTargetId",
5794 KeyValueInformation
->NameLength
/ 2) == 0)
5797 if (KeyValueInformation
->Type
!= REG_DWORD
)
5799 DPRINT("Bad data type for InitiatorTargetId\n");
5803 ConfigInfo
->InitiatorBusId
[0] = *((PUCHAR
)
5804 (Buffer
+ KeyValueInformation
->DataOffset
));
5806 /* Check / reset if needed */
5807 if (ConfigInfo
->InitiatorBusId
[0] > ConfigInfo
->MaximumNumberOfTargets
- 1)
5808 ConfigInfo
->InitiatorBusId
[0] = (CCHAR
)-1;
5810 DPRINT("InitiatorTargetId = %d\n", ConfigInfo
->InitiatorBusId
[0]);
5814 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ScsiDebug",
5815 KeyValueInformation
->NameLength
/2) == 0)
5817 DPRINT("ScsiDebug key not supported\n");
5820 /* Check for a breakpoint */
5821 if (_wcsnicmp(KeyValueInformation
->Name
, L
"BreakPointOnEntry",
5822 KeyValueInformation
->NameLength
/2) == 0)
5824 DPRINT1("Breakpoint on entry requested!\n");
5828 /* Get DisableSynchronousTransfers */
5829 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableSynchronousTransfers",
5830 KeyValueInformation
->NameLength
/2) == 0)
5832 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5833 DPRINT("Synch transfers disabled\n");
5836 /* Get DisableDisconnects */
5837 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableDisconnects",
5838 KeyValueInformation
->NameLength
/2) == 0)
5840 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
5841 DPRINT("Disconnects disabled\n");
5844 /* Get DisableTaggedQueuing */
5845 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableTaggedQueuing",
5846 KeyValueInformation
->NameLength
/2) == 0)
5848 InternalConfigInfo
->DisableTaggedQueueing
= TRUE
;
5849 DPRINT("Tagged queueing disabled\n");
5852 /* Get DisableMultipleRequests */
5853 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableMultipleRequests",
5854 KeyValueInformation
->NameLength
/2) == 0)
5856 InternalConfigInfo
->DisableMultipleLun
= TRUE
;
5857 DPRINT("Multiple requests disabled\n");
5860 /* Get DriverParameters */
5861 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DriverParameters",
5862 KeyValueInformation
->NameLength
/2) == 0)
5864 /* Skip if nothing */
5865 if (KeyValueInformation
->DataLength
== 0)
5868 /* If there was something previously allocated - free it */
5869 if (InternalConfigInfo
->Parameter
!= NULL
)
5870 ExFreePool(InternalConfigInfo
->Parameter
);
5873 InternalConfigInfo
->Parameter
= ExAllocatePoolWithTag(NonPagedPool
,
5874 KeyValueInformation
->DataLength
, TAG_SCSIPORT
);
5876 if (InternalConfigInfo
->Parameter
!= NULL
)
5878 if (KeyValueInformation
->Type
!= REG_SZ
)
5882 InternalConfigInfo
->Parameter
,
5883 (PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
,
5884 KeyValueInformation
->DataLength
);
5888 /* If it's a unicode string, convert it to ansi */
5889 UnicodeString
.Length
= (USHORT
)KeyValueInformation
->DataLength
;
5890 UnicodeString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
5891 UnicodeString
.Buffer
=
5892 (PWSTR
)((PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
5894 AnsiString
.Length
= 0;
5895 AnsiString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
5896 AnsiString
.Buffer
= (PCHAR
)InternalConfigInfo
->Parameter
;
5898 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
5902 /* In case of error, free the allocated space */
5903 if (!NT_SUCCESS(Status
))
5905 ExFreePool(InternalConfigInfo
->Parameter
);
5906 InternalConfigInfo
->Parameter
= NULL
;
5912 DPRINT("Found driver parameter\n");
5915 /* Get MaximumSGList */
5916 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumSGList",
5917 KeyValueInformation
->NameLength
/2) == 0)
5919 if (KeyValueInformation
->Type
!= REG_DWORD
)
5921 DPRINT("Bad data type for MaximumSGList\n");
5925 ConfigInfo
->NumberOfPhysicalBreaks
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
5928 if (ConfigInfo
->NumberOfPhysicalBreaks
> SCSI_MAXIMUM_PHYSICAL_BREAKS
)
5930 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MAXIMUM_PHYSICAL_BREAKS
;
5932 else if (ConfigInfo
->NumberOfPhysicalBreaks
< SCSI_MINIMUM_PHYSICAL_BREAKS
)
5934 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MINIMUM_PHYSICAL_BREAKS
;
5937 DPRINT("MaximumSGList = %d\n", ConfigInfo
->NumberOfPhysicalBreaks
);
5940 /* Get NumberOfRequests */
5941 if (_wcsnicmp(KeyValueInformation
->Name
, L
"NumberOfRequests",
5942 KeyValueInformation
->NameLength
/2) == 0)
5944 if (KeyValueInformation
->Type
!= REG_DWORD
)
5946 DPRINT("NumberOfRequests has wrong data type\n");
5950 DeviceExtension
->RequestsNumber
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
5953 if (DeviceExtension
->RequestsNumber
< 16)
5955 DeviceExtension
->RequestsNumber
= 16;
5957 else if (DeviceExtension
->RequestsNumber
> 512)
5959 DeviceExtension
->RequestsNumber
= 512;
5962 DPRINT("Number Of Requests = %d\n", DeviceExtension
->RequestsNumber
);
5965 /* Get resource list */
5966 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ResourceList",
5967 KeyValueInformation
->NameLength
/2) == 0 ||
5968 _wcsnicmp(KeyValueInformation
->Name
, L
"Configuration Data",
5969 KeyValueInformation
->NameLength
/2) == 0 )
5971 if (KeyValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
||
5972 KeyValueInformation
->DataLength
< sizeof(REG_FULL_RESOURCE_DESCRIPTOR
))
5974 DPRINT("Bad data type for ResourceList\n");
5979 DPRINT("Found ResourceList\n");
5982 FullResource
= (PCM_FULL_RESOURCE_DESCRIPTOR
)(Buffer
+ KeyValueInformation
->DataOffset
);
5984 /* Copy some info from it */
5985 InternalConfigInfo
->BusNumber
= FullResource
->BusNumber
;
5986 ConfigInfo
->SystemIoBusNumber
= FullResource
->BusNumber
;
5988 /* Loop through it */
5989 for (Count
= 0; Count
< FullResource
->PartialResourceList
.Count
; Count
++)
5991 /* Get partial descriptor */
5993 &FullResource
->PartialResourceList
.PartialDescriptors
[Count
];
5995 /* Check datalength */
5996 if ((ULONG
)((PCHAR
)(PartialDescriptor
+ 1) -
5997 (PCHAR
)FullResource
) > KeyValueInformation
->DataLength
)
5999 DPRINT("Resource data is of incorrect size\n");
6003 switch (PartialDescriptor
->Type
)
6005 case CmResourceTypePort
:
6006 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
6008 DPRINT("Too many access ranges\n");
6012 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= FALSE
;
6013 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Port
.Start
;
6014 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Port
.Length
;
6019 case CmResourceTypeMemory
:
6020 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
6022 DPRINT("Too many access ranges\n");
6026 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= TRUE
;
6027 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Memory
.Start
;
6028 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Memory
.Length
;
6033 case CmResourceTypeInterrupt
:
6034 ConfigInfo
->BusInterruptLevel
=
6035 PartialDescriptor
->u
.Interrupt
.Level
;
6037 ConfigInfo
->BusInterruptVector
=
6038 PartialDescriptor
->u
.Interrupt
.Vector
;
6041 case CmResourceTypeDma
:
6042 ConfigInfo
->DmaChannel
= PartialDescriptor
->u
.Dma
.Channel
;
6043 ConfigInfo
->DmaPort
= PartialDescriptor
->u
.Dma
.Port
;
6046 case CmResourceTypeDeviceSpecific
:
6047 if (PartialDescriptor
->u
.DeviceSpecificData
.DataSize
<
6048 sizeof(CM_SCSI_DEVICE_DATA
) ||
6049 (PCHAR
) (PartialDescriptor
+ 1) - (PCHAR
)FullResource
+
6050 PartialDescriptor
->u
.DeviceSpecificData
.DataSize
>
6051 KeyValueInformation
->DataLength
)
6053 DPRINT("Resource data length is incorrect");
6057 /* Set only one field from it */
6058 ScsiDeviceData
= (PCM_SCSI_DEVICE_DATA
) (PartialDescriptor
+1);
6059 ConfigInfo
->InitiatorBusId
[0] = ScsiDeviceData
->HostIdentifier
;
6069 SpQueryDeviceCallout(IN PVOID Context
,
6070 IN PUNICODE_STRING PathName
,
6071 IN INTERFACE_TYPE BusType
,
6073 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
6074 IN CONFIGURATION_TYPE ControllerType
,
6075 IN ULONG ControllerNumber
,
6076 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
6077 IN CONFIGURATION_TYPE PeripheralType
,
6078 IN ULONG PeripheralNumber
,
6079 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
6081 PBOOLEAN Found
= (PBOOLEAN
)Context
;
6082 /* We just set our Found variable to TRUE */
6085 return STATUS_SUCCESS
;
6088 IO_ALLOCATION_ACTION
6090 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject
,
6092 IN PVOID MapRegisterBase
,
6096 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
6098 /* Guard access with the spinlock */
6099 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
6101 /* Save MapRegisterBase we've got here */
6102 DeviceExtension
->MapRegisterBase
= MapRegisterBase
;
6104 /* Start pending request */
6105 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
6106 ScsiPortStartPacket
, DeviceObject
);
6108 /* Release spinlock we took */
6109 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
6116 SpiStatusSrbToNt(UCHAR SrbStatus
)
6118 switch (SRB_STATUS(SrbStatus
))
6120 case SRB_STATUS_TIMEOUT
:
6121 case SRB_STATUS_COMMAND_TIMEOUT
:
6122 return STATUS_IO_TIMEOUT
;
6124 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH
:
6125 case SRB_STATUS_BAD_FUNCTION
:
6126 return STATUS_INVALID_DEVICE_REQUEST
;
6128 case SRB_STATUS_NO_DEVICE
:
6129 case SRB_STATUS_INVALID_LUN
:
6130 case SRB_STATUS_INVALID_TARGET_ID
:
6131 case SRB_STATUS_NO_HBA
:
6132 return STATUS_DEVICE_DOES_NOT_EXIST
;
6134 case SRB_STATUS_DATA_OVERRUN
:
6135 return STATUS_BUFFER_OVERFLOW
;
6137 case SRB_STATUS_SELECTION_TIMEOUT
:
6138 return STATUS_DEVICE_NOT_CONNECTED
;
6141 return STATUS_IO_DEVICE_ERROR
;
6144 return STATUS_IO_DEVICE_ERROR
;
6148 #undef ScsiPortConvertPhysicalAddressToUlong
6153 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
6155 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
6156 return(Address
.u
.LowPart
);