3 * Copyright (C) 2001, 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS Storage Stack
23 * FILE: drivers/storage/scsiport/scsiport.c
24 * PURPOSE: SCSI port driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
26 * Aleksey Bragin (aleksey reactos org)
29 /* INCLUDES *****************************************************************/
45 #include "scsiport_int.h"
52 ULONG InternalDebugLevel
= 0x00;
54 /* TYPES *********************************************************************/
56 /* GLOBALS *******************************************************************/
59 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
60 IN PDEVICE_OBJECT DeviceObject
,
61 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
62 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
63 IN PUNICODE_STRING RegistryPath
,
65 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
);
67 static NTSTATUS STDCALL
68 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
71 static DRIVER_DISPATCH ScsiPortDispatchScsi
;
72 static NTSTATUS STDCALL
73 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
76 static NTSTATUS STDCALL
77 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
80 static DRIVER_STARTIO ScsiPortStartIo
;
82 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
85 static BOOLEAN STDCALL
86 ScsiPortStartPacket(IN OUT PVOID Context
);
90 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
91 PVOID MapRegisterBase
, PVOID Context
);
93 static PSCSI_PORT_LUN_EXTENSION
94 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
96 static PSCSI_PORT_LUN_EXTENSION
97 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
102 static PSCSI_REQUEST_BLOCK_INFO
103 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
104 PSCSI_PORT_LUN_EXTENSION LunExtension
,
105 PSCSI_REQUEST_BLOCK Srb
);
108 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
109 IN PSCSI_LUN_INFO LunInfo
);
112 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
115 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
118 static PSCSI_REQUEST_BLOCK_INFO
119 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
125 static KSERVICE_ROUTINE ScsiPortIsr
;
126 static BOOLEAN STDCALL
127 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
128 IN PVOID ServiceContext
);
131 ScsiPortDpcForIsr(IN PKDPC Dpc
,
132 IN PDEVICE_OBJECT DpcDeviceObject
,
134 IN PVOID DpcContext
);
137 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
141 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
142 PUNICODE_STRING RegistryPath
);
145 SpiStatusSrbToNt(UCHAR SrbStatus
);
148 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
149 IN PSCSI_REQUEST_BLOCK Srb
);
151 static IO_COMPLETION_ROUTINE SpiCompletionRoutine
;
153 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
159 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
160 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
161 OUT PBOOLEAN NeedToCallStartIo
);
164 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
165 IN PSCSI_PORT_LUN_EXTENSION LunExtension
);
168 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
169 IN PVOID DeviceObject
,
170 IN PVOID SystemArgument1
,
171 IN PVOID SystemArgument2
);
174 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
175 PHW_INITIALIZATION_DATA HwInitData
,
176 PCONFIGURATION_INFO InternalConfigInfo
,
177 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
181 SpQueryDeviceCallout(IN PVOID Context
,
182 IN PUNICODE_STRING PathName
,
183 IN INTERFACE_TYPE BusType
,
185 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
186 IN CONFIGURATION_TYPE ControllerType
,
187 IN ULONG ControllerNumber
,
188 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
189 IN CONFIGURATION_TYPE PeripheralType
,
190 IN ULONG PeripheralNumber
,
191 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
);
194 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
196 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
197 IN PCONFIGURATION_INFO InternalConfigInfo
,
201 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
202 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
203 IN PPORT_CONFIGURATION_INFORMATION PortConfig
);
205 static PCM_RESOURCE_LIST
206 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
207 PPORT_CONFIGURATION_INFORMATION PortConfig
);
210 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
213 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
217 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
);
221 /* FUNCTIONS *****************************************************************/
223 /**********************************************************************
228 * This function initializes the driver.
235 * System allocated Driver Object for this driver.
238 * Name of registry driver service key.
245 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
246 IN PUNICODE_STRING RegistryPath
)
248 DPRINT("ScsiPort Driver %s\n", VERSION
);
249 return(STATUS_SUCCESS
);
253 /**********************************************************************
258 * Prints debugging messages.
265 * Debug level of the given message.
268 * Pointer to printf()-compatible format string.
271 Additional output data (see printf()).
280 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
281 IN PCHAR DebugMessage
,
287 if (DebugPrintLevel
> InternalDebugLevel
)
290 va_start(ap
, DebugMessage
);
291 vsprintf(Buffer
, DebugMessage
, ap
);
302 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
308 DPRINT("ScsiPortCompleteRequest()\n");
316 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
318 DPRINT("ScsiPortFlushDma()\n");
327 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
328 IN PVOID MappedAddress
)
330 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
331 PMAPPED_ADDRESS NextMa
, LastMa
;
333 //DPRINT("ScsiPortFreeDeviceBase() called\n");
335 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
336 SCSI_PORT_DEVICE_EXTENSION
,
337 MiniPortDeviceExtension
);
340 /* Initialize our pointers */
341 NextMa
= DeviceExtension
->MappedAddressList
;
346 if (NextMa
->MappedAddress
== MappedAddress
)
349 MmUnmapIoSpace(MappedAddress
, NextMa
->NumberOfBytes
);
351 /* Remove it from the list */
352 if (NextMa
== DeviceExtension
->MappedAddressList
)
354 /* Remove the first entry */
355 DeviceExtension
->MappedAddressList
= NextMa
->NextMappedAddress
;
359 LastMa
->NextMappedAddress
= NextMa
->NextMappedAddress
;
362 /* Free the resources and quit */
370 NextMa
= NextMa
->NextMappedAddress
;
380 ScsiPortGetBusData(IN PVOID DeviceExtension
,
381 IN ULONG BusDataType
,
382 IN ULONG SystemIoBusNumber
,
387 return(HalGetBusData(BusDataType
,
399 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
400 IN INTERFACE_TYPE BusType
,
401 IN ULONG SystemIoBusNumber
,
402 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
403 IN ULONG NumberOfBytes
,
404 IN BOOLEAN InIoSpace
)
406 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
407 PHYSICAL_ADDRESS TranslatedAddress
;
408 PMAPPED_ADDRESS DeviceBase
;
412 //DPRINT ("ScsiPortGetDeviceBase() called\n");
414 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
415 SCSI_PORT_DEVICE_EXTENSION
,
416 MiniPortDeviceExtension
);
418 AddressSpace
= (ULONG
)InIoSpace
;
419 if (HalTranslateBusAddress(BusType
,
423 &TranslatedAddress
) == FALSE
)
429 if (AddressSpace
!= 0)
430 return((PVOID
)TranslatedAddress
.u
.LowPart
);
432 MappedAddress
= MmMapIoSpace(TranslatedAddress
,
436 DeviceBase
= ExAllocatePoolWithTag(NonPagedPool
,
437 sizeof(MAPPED_ADDRESS
), TAG_SCSIPORT
);
439 if (DeviceBase
== NULL
)
440 return MappedAddress
;
442 DeviceBase
->MappedAddress
= MappedAddress
;
443 DeviceBase
->NumberOfBytes
= NumberOfBytes
;
444 DeviceBase
->IoAddress
= IoAddress
;
445 DeviceBase
->BusNumber
= SystemIoBusNumber
;
447 /* Link it to the Device Extension list */
448 DeviceBase
->NextMappedAddress
= DeviceExtension
->MappedAddressList
;
449 DeviceExtension
->MappedAddressList
= DeviceBase
;
451 return MappedAddress
;
458 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
465 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
466 PSCSI_PORT_LUN_EXTENSION LunExtension
;
469 DPRINT("ScsiPortGetLogicalUnit() called\n");
471 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
472 SCSI_PORT_DEVICE_EXTENSION
,
473 MiniPortDeviceExtension
);
474 if (IsListEmpty(&DeviceExtension
->LunExtensionListHead
))
477 Entry
= DeviceExtension
->LunExtensionListHead
.Flink
;
478 while (Entry
!= &DeviceExtension
->LunExtensionListHead
)
480 LunExtension
= CONTAINING_RECORD(Entry
,
481 SCSI_PORT_LUN_EXTENSION
,
483 if (LunExtension
->PathId
== PathId
&&
484 LunExtension
->TargetId
== TargetId
&&
485 LunExtension
->Lun
== Lun
)
487 return (PVOID
)&LunExtension
->MiniportLunExtension
;
490 Entry
= Entry
->Flink
;
500 SCSI_PHYSICAL_ADDRESS STDCALL
501 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
502 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
503 IN PVOID VirtualAddress
,
506 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
507 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
508 ULONG BufferLength
= 0;
510 PSCSI_SG_ADDRESS SGList
;
511 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
513 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
514 HwDeviceExtension
, Srb
, VirtualAddress
, Length
);
516 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
517 SCSI_PORT_DEVICE_EXTENSION
,
518 MiniPortDeviceExtension
);
520 if (Srb
== NULL
|| Srb
->SenseInfoBuffer
== VirtualAddress
)
522 /* Simply look it up in the allocated common buffer */
523 Offset
= (PUCHAR
)VirtualAddress
- (PUCHAR
)DeviceExtension
->SrbExtensionBuffer
;
525 BufferLength
= DeviceExtension
->CommonBufferLength
- Offset
;
526 PhysicalAddress
.QuadPart
= DeviceExtension
->PhysicalAddress
.QuadPart
+ Offset
;
528 else if (DeviceExtension
->MapRegisters
)
530 /* Scatter-gather list must be used */
531 SrbInfo
= SpiGetSrbData(DeviceExtension
,
537 SGList
= SrbInfo
->ScatterGather
;
539 /* Find needed item in the SG list */
540 Offset
= (PCHAR
)VirtualAddress
- (PCHAR
)Srb
->DataBuffer
;
541 while (Offset
>= SGList
->Length
)
543 Offset
-= SGList
->Length
;
547 /* We're done, store length and physical address */
548 BufferLength
= SGList
->Length
- Offset
;
549 PhysicalAddress
.QuadPart
= SGList
->PhysicalAddress
.QuadPart
+ Offset
;
555 PhysicalAddress
.QuadPart
= (LONGLONG
)(SP_UNINITIALIZED_VALUE
);
558 *Length
= BufferLength
;
559 return PhysicalAddress
;
566 PSCSI_REQUEST_BLOCK STDCALL
567 ScsiPortGetSrb(IN PVOID DeviceExtension
,
573 DPRINT1("ScsiPortGetSrb() unimplemented\n");
583 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
584 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
585 IN ULONG NumberOfBytes
)
587 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
588 DEVICE_DESCRIPTION DeviceDescription
;
589 ULONG MapRegistersCount
;
592 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
593 HwDeviceExtension
, ConfigInfo
, NumberOfBytes
);
595 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
596 SCSI_PORT_DEVICE_EXTENSION
,
597 MiniPortDeviceExtension
);
599 /* Check for allocated common DMA buffer */
600 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
)
602 DPRINT1("The HBA has already got a common DMA buffer!\n");
606 /* Check for DMA adapter object */
607 if (DeviceExtension
->AdapterObject
== NULL
)
609 /* Initialize DMA adapter description */
610 RtlZeroMemory(&DeviceDescription
, sizeof(DEVICE_DESCRIPTION
));
612 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
613 DeviceDescription
.Master
= ConfigInfo
->Master
;
614 DeviceDescription
.ScatterGather
= ConfigInfo
->ScatterGather
;
615 DeviceDescription
.DemandMode
= ConfigInfo
->DemandMode
;
616 DeviceDescription
.Dma32BitAddresses
= ConfigInfo
->Dma32BitAddresses
;
617 DeviceDescription
.BusNumber
= ConfigInfo
->SystemIoBusNumber
;
618 DeviceDescription
.DmaChannel
= ConfigInfo
->DmaChannel
;
619 DeviceDescription
.InterfaceType
= ConfigInfo
->AdapterInterfaceType
;
620 DeviceDescription
.DmaWidth
= ConfigInfo
->DmaWidth
;
621 DeviceDescription
.DmaSpeed
= ConfigInfo
->DmaSpeed
;
622 DeviceDescription
.MaximumLength
= ConfigInfo
->MaximumTransferLength
;
623 DeviceDescription
.DmaPort
= ConfigInfo
->DmaPort
;
625 /* Get a DMA adapter object */
626 DeviceExtension
->AdapterObject
=
627 HalGetAdapter(&DeviceDescription
, &MapRegistersCount
);
629 /* Fail in case of error */
630 if (DeviceExtension
->AdapterObject
== NULL
)
632 DPRINT1("HalGetAdapter() failed\n");
636 /* Set number of physical breaks */
637 if (ConfigInfo
->NumberOfPhysicalBreaks
!= 0 &&
638 MapRegistersCount
> ConfigInfo
->NumberOfPhysicalBreaks
)
640 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
=
641 ConfigInfo
->NumberOfPhysicalBreaks
;
645 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
= MapRegistersCount
;
649 /* Update auto request sense feature */
650 DeviceExtension
->SupportsAutoSense
= ConfigInfo
->AutoRequestSense
;
652 /* Update Srb extension size */
653 if (DeviceExtension
->SrbExtensionSize
!= ConfigInfo
->SrbExtensionSize
)
654 DeviceExtension
->SrbExtensionSize
= ConfigInfo
->SrbExtensionSize
;
656 /* Update Srb extension alloc flag */
657 if (ConfigInfo
->AutoRequestSense
|| DeviceExtension
->SrbExtensionSize
)
658 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
660 /* Allocate a common DMA buffer */
661 Status
= SpiAllocateCommonBuffer(DeviceExtension
, NumberOfBytes
);
663 if (!NT_SUCCESS(Status
))
665 DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status
);
669 return DeviceExtension
->NonCachedExtension
;
673 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
)
675 PVOID
*SrbExtension
, CommonBuffer
;
676 ULONG CommonBufferLength
, BufSize
;
678 /* If size is 0, set it to 16 */
679 if (!DeviceExtension
->SrbExtensionSize
)
680 DeviceExtension
->SrbExtensionSize
= 16;
683 BufSize
= DeviceExtension
->SrbExtensionSize
;
685 /* Add autosense data size if needed */
686 if (DeviceExtension
->SupportsAutoSense
)
687 BufSize
+= sizeof(SENSE_DATA
);
691 BufSize
= (BufSize
+ sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
693 /* Sum up into the total common buffer length, and round it to page size */
695 ROUND_TO_PAGES(NonCachedSize
+ BufSize
* DeviceExtension
->RequestsNumber
);
698 if (!DeviceExtension
->AdapterObject
)
700 /* From nonpaged pool if there is no DMA */
701 CommonBuffer
= ExAllocatePoolWithTag(NonPagedPool
, CommonBufferLength
, TAG_SCSIPORT
);
705 /* Perform a full request since we have a DMA adapter*/
706 CommonBuffer
= HalAllocateCommonBuffer(DeviceExtension
->AdapterObject
,
708 &DeviceExtension
->PhysicalAddress
,
712 /* Fail in case of error */
714 return STATUS_INSUFFICIENT_RESOURCES
;
717 RtlZeroMemory(CommonBuffer
, CommonBufferLength
);
719 /* Store its size in Device Extension */
720 DeviceExtension
->CommonBufferLength
= CommonBufferLength
;
722 /* SrbExtension buffer is located at the beginning of the buffer */
723 DeviceExtension
->SrbExtensionBuffer
= CommonBuffer
;
725 /* Non-cached extension buffer is located at the end of
729 CommonBufferLength
-= NonCachedSize
;
730 DeviceExtension
->NonCachedExtension
= (PUCHAR
)CommonBuffer
+ CommonBufferLength
;
734 DeviceExtension
->NonCachedExtension
= NULL
;
737 if (DeviceExtension
->NeedSrbExtensionAlloc
)
739 /* Look up how many SRB data structures we need */
740 DeviceExtension
->SrbDataCount
= CommonBufferLength
/ BufSize
;
742 /* Initialize the free SRB extensions list */
743 SrbExtension
= (PVOID
*)CommonBuffer
;
744 DeviceExtension
->FreeSrbExtensions
= SrbExtension
;
746 /* Fill the remainding pointers (if we have more than 1 SRB) */
747 while (CommonBufferLength
>= 2 * BufSize
)
749 *SrbExtension
= (PVOID
*)((PCHAR
)SrbExtension
+ BufSize
);
750 SrbExtension
= *SrbExtension
;
752 CommonBufferLength
-= BufSize
;
756 return STATUS_SUCCESS
;
765 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
766 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
768 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
771 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
772 HwDeviceExtension
, PhysicalAddress
.QuadPart
);
774 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
775 SCSI_PORT_DEVICE_EXTENSION
,
776 MiniPortDeviceExtension
);
778 if (DeviceExtension
->PhysicalAddress
.QuadPart
> PhysicalAddress
.QuadPart
)
781 Offset
= (ULONG
)(PhysicalAddress
.QuadPart
- DeviceExtension
->PhysicalAddress
.QuadPart
);
783 if (Offset
>= DeviceExtension
->CommonBufferLength
)
786 return (PVOID
)((ULONG_PTR
)DeviceExtension
->SrbExtensionBuffer
+ Offset
);
790 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo
, PUNICODE_STRING RegistryPath
)
792 OBJECT_ATTRIBUTES ObjectAttributes
;
793 UNICODE_STRING KeyName
;
796 /* Open the service key */
797 InitializeObjectAttributes(&ObjectAttributes
,
799 OBJ_CASE_INSENSITIVE
,
803 Status
= ZwOpenKey(&ConfigInfo
->ServiceKey
,
807 if (!NT_SUCCESS(Status
))
809 DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath
, Status
);
810 ConfigInfo
->ServiceKey
= NULL
;
813 /* If we could open driver's service key, then proceed to the Parameters key */
814 if (ConfigInfo
->ServiceKey
!= NULL
)
816 RtlInitUnicodeString(&KeyName
, L
"Parameters");
817 InitializeObjectAttributes(&ObjectAttributes
,
819 OBJ_CASE_INSENSITIVE
,
820 ConfigInfo
->ServiceKey
,
821 (PSECURITY_DESCRIPTOR
) NULL
);
824 Status
= ZwOpenKey(&ConfigInfo
->DeviceKey
,
828 if (NT_SUCCESS(Status
))
830 /* Yes, Parameters key exist, and it must be used instead of
832 ZwClose(ConfigInfo
->ServiceKey
);
833 ConfigInfo
->ServiceKey
= ConfigInfo
->DeviceKey
;
834 ConfigInfo
->DeviceKey
= NULL
;
838 if (ConfigInfo
->ServiceKey
!= NULL
)
840 /* Open the Device key */
841 RtlInitUnicodeString(&KeyName
, L
"Device");
842 InitializeObjectAttributes(&ObjectAttributes
,
844 OBJ_CASE_INSENSITIVE
,
845 ConfigInfo
->ServiceKey
,
848 /* We don't check for failure here - not needed */
849 ZwOpenKey(&ConfigInfo
->DeviceKey
,
856 /**********************************************************************
861 * Initializes SCSI port driver specific data.
868 * Pointer to the miniport driver's driver object.
871 * Pointer to the miniport driver's registry path.
873 * HwInitializationData
874 * Pointer to port driver specific configuration data.
877 Miniport driver specific context.
886 ScsiPortInitialize(IN PVOID Argument1
,
888 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
891 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
892 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
893 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
894 PCONFIGURATION_INFORMATION SystemConfig
;
895 PPORT_CONFIGURATION_INFORMATION PortConfig
;
896 PORT_CONFIGURATION_INFORMATION InitialPortConfig
;
897 CONFIGURATION_INFO ConfigInfo
;
898 ULONG DeviceExtensionSize
;
899 ULONG PortConfigSize
;
901 BOOLEAN DeviceFound
= FALSE
;
902 BOOLEAN FirstConfigCall
= TRUE
;
907 PCI_SLOT_NUMBER SlotNumber
;
909 PDEVICE_OBJECT PortDeviceObject
;
910 WCHAR NameBuffer
[80];
911 UNICODE_STRING DeviceName
;
912 WCHAR DosNameBuffer
[80];
913 UNICODE_STRING DosDeviceName
;
914 PIO_SCSI_CAPABILITIES PortCapabilities
;
919 PCM_RESOURCE_LIST ResourceList
;
923 DPRINT ("ScsiPortInitialize() called!\n");
925 /* Check params for validity */
926 if ((HwInitializationData
->HwInitialize
== NULL
) ||
927 (HwInitializationData
->HwStartIo
== NULL
) ||
928 (HwInitializationData
->HwInterrupt
== NULL
) ||
929 (HwInitializationData
->HwFindAdapter
== NULL
) ||
930 (HwInitializationData
->HwResetBus
== NULL
))
932 return STATUS_INVALID_PARAMETER
;
936 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
937 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
938 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
939 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
940 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
941 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
943 /* Obtain configuration information */
944 SystemConfig
= IoGetConfigurationInformation();
946 /* Zero the internal configuration info structure */
947 RtlZeroMemory(&ConfigInfo
, sizeof(CONFIGURATION_INFO
));
949 /* Zero starting slot number */
950 SlotNumber
.u
.AsULONG
= 0;
952 /* Allocate space for access ranges */
953 if (HwInitializationData
->NumberOfAccessRanges
)
955 ConfigInfo
.AccessRanges
=
956 ExAllocatePoolWithTag(PagedPool
,
957 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
), TAG_SCSIPORT
);
960 if (ConfigInfo
.AccessRanges
== NULL
)
961 return STATUS_INSUFFICIENT_RESOURCES
;
964 /* Open registry keys */
965 SpiInitOpenKeys(&ConfigInfo
, (PUNICODE_STRING
)Argument2
);
967 /* Last adapter number = not known */
968 ConfigInfo
.LastAdapterNumber
= SP_UNINITIALIZED_VALUE
;
970 /* Calculate sizes of DeviceExtension and PortConfig */
971 DeviceExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
972 HwInitializationData
->DeviceExtensionSize
;
974 MaxBus
= (HwInitializationData
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
975 DPRINT("MaxBus: %lu\n", MaxBus
);
979 /* Create a unicode device name */
981 L
"\\Device\\ScsiPort%lu",
982 SystemConfig
->ScsiPortCount
);
983 RtlInitUnicodeString(&DeviceName
, NameBuffer
);
985 DPRINT("Creating device: %wZ\n", &DeviceName
);
987 /* Create the port device */
988 Status
= IoCreateDevice(DriverObject
,
991 FILE_DEVICE_CONTROLLER
,
996 if (!NT_SUCCESS(Status
))
998 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
999 PortDeviceObject
= NULL
;
1003 DPRINT ("Created device: %wZ (%p)\n", &DeviceName
, PortDeviceObject
);
1005 /* Set the buffering strategy here... */
1006 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1007 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
; /* FIXME: Is this really needed? */
1009 /* Fill Device Extension */
1010 DeviceExtension
= PortDeviceObject
->DeviceExtension
;
1011 DeviceExtension
->Length
= DeviceExtensionSize
;
1012 DeviceExtension
->DeviceObject
= PortDeviceObject
;
1013 DeviceExtension
->PortNumber
= SystemConfig
->ScsiPortCount
;
1015 /* Driver's routines... */
1016 DeviceExtension
->HwInitialize
= HwInitializationData
->HwInitialize
;
1017 DeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
1018 DeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
1019 DeviceExtension
->HwResetBus
= HwInitializationData
->HwResetBus
;
1020 DeviceExtension
->HwDmaStarted
= HwInitializationData
->HwDmaStarted
;
1022 /* Extensions sizes */
1023 DeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
1024 DeviceExtension
->LunExtensionSize
= HwInitializationData
->SpecificLuExtensionSize
;
1025 DeviceExtension
->SrbExtensionSize
= HwInitializationData
->SrbExtensionSize
;
1027 /* Round Srb extension size to the quadword */
1028 DeviceExtension
->SrbExtensionSize
=
1029 ~(sizeof(LONGLONG
) - 1) & (DeviceExtension
->SrbExtensionSize
+
1030 sizeof(LONGLONG
) - 1);
1032 /* Fill some numbers (bus count, lun count, etc) */
1033 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
1034 DeviceExtension
->RequestsNumber
= 16;
1036 /* Initialize the spin lock in the controller extension */
1037 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1038 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
1040 /* Initialize the DPC object */
1041 IoInitializeDpcRequest(PortDeviceObject
,
1044 /* Initialize the device timer */
1045 DeviceExtension
->TimerCount
= -1;
1046 IoInitializeTimer(PortDeviceObject
,
1050 /* Initialize miniport timer */
1051 KeInitializeTimer(&DeviceExtension
->MiniportTimer
);
1052 KeInitializeDpc(&DeviceExtension
->MiniportTimerDpc
,
1053 SpiMiniportTimerDpc
,
1058 Status
= SpiCreatePortConfig(DeviceExtension
,
1059 HwInitializationData
,
1064 if (!NT_SUCCESS(Status
))
1067 /* Allocate and initialize port configuration info */
1068 PortConfigSize
= (sizeof(PORT_CONFIGURATION_INFORMATION
) +
1069 HwInitializationData
->NumberOfAccessRanges
*
1070 sizeof(ACCESS_RANGE
) + 7) & ~7;
1071 DeviceExtension
->PortConfig
= ExAllocatePoolWithTag(NonPagedPool
, PortConfigSize
, TAG_SCSIPORT
);
1073 /* Fail if failed */
1074 if (DeviceExtension
->PortConfig
== NULL
)
1076 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1080 PortConfig
= DeviceExtension
->PortConfig
;
1082 /* Copy information here */
1083 RtlCopyMemory(PortConfig
,
1085 sizeof(PORT_CONFIGURATION_INFORMATION
));
1088 /* Copy extension sizes into the PortConfig */
1089 PortConfig
->SpecificLuExtensionSize
= DeviceExtension
->LunExtensionSize
;
1090 PortConfig
->SrbExtensionSize
= DeviceExtension
->SrbExtensionSize
;
1092 /* Initialize Access ranges */
1093 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1095 PortConfig
->AccessRanges
= (PVOID
)(PortConfig
+1);
1097 /* Align to LONGLONG */
1098 PortConfig
->AccessRanges
= (PVOID
)((ULONG
)(PortConfig
->AccessRanges
) + 7);
1099 PortConfig
->AccessRanges
= (PVOID
)((ULONG
)(PortConfig
->AccessRanges
) & ~7);
1102 RtlCopyMemory(PortConfig
->AccessRanges
,
1103 ConfigInfo
.AccessRanges
,
1104 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
1107 /* Search for matching PCI device */
1108 if ((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1109 (HwInitializationData
->VendorIdLength
> 0) &&
1110 (HwInitializationData
->VendorId
!= NULL
) &&
1111 (HwInitializationData
->DeviceIdLength
> 0) &&
1112 (HwInitializationData
->DeviceId
!= NULL
))
1114 PortConfig
->BusInterruptLevel
= 0;
1116 /* Get PCI device data */
1117 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1118 HwInitializationData
->VendorIdLength
,
1119 HwInitializationData
->VendorId
,
1120 HwInitializationData
->DeviceIdLength
,
1121 HwInitializationData
->DeviceId
);
1123 if (!SpiGetPciConfigData(DriverObject
,
1125 HwInitializationData
,
1128 ConfigInfo
.BusNumber
,
1131 /* Continue to the next bus, nothing here */
1132 ConfigInfo
.BusNumber
++;
1133 DeviceExtension
->PortConfig
= NULL
;
1134 ExFreePool(PortConfig
);
1136 goto CreatePortConfig
;
1139 if (!PortConfig
->BusInterruptLevel
)
1141 /* Bypass this slot, because no interrupt was assigned */
1142 DeviceExtension
->PortConfig
= NULL
;
1143 ExFreePool(PortConfig
);
1144 goto CreatePortConfig
;
1149 DPRINT("Non-pci bus\n");
1152 /* Note: HwFindAdapter is called once for each bus */
1154 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
1155 Result
= (HwInitializationData
->HwFindAdapter
)(&DeviceExtension
->MiniPortDeviceExtension
,
1157 0, /* BusInformation */
1158 ConfigInfo
.Parameter
, /* ArgumentString */
1162 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1163 Result
, (Again
) ? "True" : "False");
1165 /* Free MapRegisterBase, it's not needed anymore */
1166 if (DeviceExtension
->MapRegisterBase
!= NULL
)
1168 ExFreePool(DeviceExtension
->MapRegisterBase
);
1169 DeviceExtension
->MapRegisterBase
= NULL
;
1172 /* If result is nothing good... */
1173 if (Result
!= SP_RETURN_FOUND
)
1175 DPRINT("HwFindAdapter() Result: %lu\n", Result
);
1177 if (Result
== SP_RETURN_NOT_FOUND
)
1179 /* We can continue on the next bus */
1180 ConfigInfo
.BusNumber
++;
1183 DeviceExtension
->PortConfig
= NULL
;
1184 ExFreePool(PortConfig
);
1185 goto CreatePortConfig
;
1188 /* Otherwise, break */
1189 Status
= STATUS_INTERNAL_ERROR
;
1193 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1194 PortConfig
->BusInterruptVector
, PortConfig
->InitiatorBusId
[0]);
1196 /* If the SRB extension size was updated */
1197 if (!DeviceExtension
->NonCachedExtension
&&
1198 (PortConfig
->SrbExtensionSize
!= DeviceExtension
->SrbExtensionSize
))
1200 /* Set it (rounding to LONGLONG again) */
1201 DeviceExtension
->SrbExtensionSize
=
1202 (PortConfig
->SrbExtensionSize
+
1203 sizeof(LONGLONG
)) & ~(sizeof(LONGLONG
) - 1);
1206 /* The same with LUN extension size */
1207 if (PortConfig
->SpecificLuExtensionSize
!= DeviceExtension
->LunExtensionSize
)
1208 DeviceExtension
->LunExtensionSize
= PortConfig
->SpecificLuExtensionSize
;
1211 if (!((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1212 (HwInitializationData
->VendorIdLength
> 0) &&
1213 (HwInitializationData
->VendorId
!= NULL
) &&
1214 (HwInitializationData
->DeviceIdLength
> 0) &&
1215 (HwInitializationData
->DeviceId
!= NULL
)))
1217 /* Construct a resource list */
1218 ResourceList
= SpiConfigToResource(DeviceExtension
,
1223 UNICODE_STRING UnicodeString
;
1224 RtlInitUnicodeString(&UnicodeString
, L
"ScsiAdapter");
1225 DPRINT("Reporting resources\n");
1226 Status
= IoReportResourceUsage(&UnicodeString
,
1232 FIELD_OFFSET(CM_RESOURCE_LIST
,
1233 List
[0].PartialResourceList
.PartialDescriptors
) +
1234 ResourceList
->List
[0].PartialResourceList
.Count
1235 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
1238 ExFreePool(ResourceList
);
1240 /* In case of a failure or a conflict, break */
1241 if (Conflict
|| (!NT_SUCCESS(Status
)))
1244 Status
= STATUS_CONFLICTING_ADDRESSES
;
1250 /* Reset the Conflict var */
1253 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1254 if (PortConfig
->MaximumNumberOfTargets
> SCSI_MAXIMUM_TARGETS_PER_BUS
)
1255 DeviceExtension
->MaxTargedIds
= SCSI_MAXIMUM_TARGETS_PER_BUS
;
1257 DeviceExtension
->MaxTargedIds
= PortConfig
->MaximumNumberOfTargets
;
1259 DeviceExtension
->BusNum
= PortConfig
->NumberOfBuses
;
1260 DeviceExtension
->CachesData
= PortConfig
->CachesData
;
1261 DeviceExtension
->ReceiveEvent
= PortConfig
->ReceiveEvent
;
1262 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->TaggedQueuing
;
1263 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
;
1265 /* If something was disabled via registry - apply it */
1266 if (ConfigInfo
.DisableMultipleLun
)
1267 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1269 if (ConfigInfo
.DisableTaggedQueueing
)
1270 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1272 /* Check if we need to alloc SRB data */
1273 if (DeviceExtension
->SupportsTaggedQueuing
||
1274 DeviceExtension
->MultipleReqsPerLun
)
1276 DeviceExtension
->NeedSrbDataAlloc
= TRUE
;
1280 DeviceExtension
->NeedSrbDataAlloc
= FALSE
;
1283 /* Get a pointer to the port capabilities */
1284 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1286 /* Copy one field there */
1287 DeviceExtension
->MapBuffers
= PortConfig
->MapBuffers
;
1288 PortCapabilities
->AdapterUsesPio
= PortConfig
->MapBuffers
;
1290 if (DeviceExtension
->AdapterObject
== NULL
&&
1291 (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
|| PortConfig
->Master
))
1293 DPRINT1("DMA is not supported yet\n");
1297 if (DeviceExtension
->SrbExtensionBuffer
== NULL
&&
1298 (DeviceExtension
->SrbExtensionSize
!= 0 ||
1299 PortConfig
->AutoRequestSense
))
1301 DeviceExtension
->SupportsAutoSense
= PortConfig
->AutoRequestSense
;
1302 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
1304 /* Allocate common buffer */
1305 Status
= SpiAllocateCommonBuffer(DeviceExtension
, 0);
1307 /* Check for failure */
1308 if (!NT_SUCCESS(Status
))
1312 /* Allocate SrbData, if needed */
1313 if (DeviceExtension
->NeedSrbDataAlloc
)
1316 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1318 if (DeviceExtension
->SrbDataCount
!= 0)
1319 Count
= DeviceExtension
->SrbDataCount
;
1321 Count
= DeviceExtension
->RequestsNumber
* 2;
1323 /* Allocate the data */
1324 SrbData
= ExAllocatePoolWithTag(NonPagedPool
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
), TAG_SCSIPORT
);
1325 if (SrbData
== NULL
)
1326 return STATUS_INSUFFICIENT_RESOURCES
;
1328 RtlZeroMemory(SrbData
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
));
1330 DeviceExtension
->SrbInfo
= SrbData
;
1331 DeviceExtension
->FreeSrbInfo
= SrbData
;
1332 DeviceExtension
->SrbDataCount
= Count
;
1334 /* Link it to the list */
1337 SrbData
->Requests
.Flink
= (PLIST_ENTRY
)(SrbData
+ 1);
1342 /* Mark the last entry of the list */
1344 SrbData
->Requests
.Flink
= NULL
;
1347 /* Initialize port capabilities */
1348 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1349 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1350 PortCapabilities
->MaximumTransferLength
= PortConfig
->MaximumTransferLength
;
1352 if (PortConfig
->ReceiveEvent
)
1353 PortCapabilities
->SupportedAsynchronousEvents
|= SRBEV_SCSI_ASYNC_NOTIFICATION
;
1355 PortCapabilities
->TaggedQueuing
= DeviceExtension
->SupportsTaggedQueuing
;
1356 PortCapabilities
->AdapterScansDown
= PortConfig
->AdapterScansDown
;
1358 if (PortConfig
->AlignmentMask
> PortDeviceObject
->AlignmentRequirement
)
1359 PortDeviceObject
->AlignmentRequirement
= PortConfig
->AlignmentMask
;
1361 PortCapabilities
->AlignmentMask
= PortDeviceObject
->AlignmentRequirement
;
1363 if (PortCapabilities
->MaximumPhysicalPages
== 0)
1365 PortCapabilities
->MaximumPhysicalPages
=
1366 BYTES_TO_PAGES(PortCapabilities
->MaximumTransferLength
);
1368 /* Apply miniport's limits */
1369 if (PortConfig
->NumberOfPhysicalBreaks
< PortCapabilities
->MaximumPhysicalPages
)
1371 PortCapabilities
->MaximumPhysicalPages
= PortConfig
->NumberOfPhysicalBreaks
;
1375 /* Deal with interrupts */
1376 if (DeviceExtension
->HwInterrupt
== NULL
||
1377 (PortConfig
->BusInterruptLevel
== 0 && PortConfig
->BusInterruptVector
== 0))
1380 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1382 /* FIXME: Use synchronization routine */
1383 ASSERT("No interrupts branch requires changes in synchronization\n");
1385 DeviceExtension
->Interrupt
= (PVOID
)DeviceExtension
;
1386 DPRINT("No interrupts\n");
1391 /* Are 2 interrupts needed? */
1392 if (DeviceExtension
->HwInterrupt
!= NULL
&&
1393 (PortConfig
->BusInterruptLevel
!= 0 || PortConfig
->BusInterruptVector
!= 0) &&
1394 (PortConfig
->BusInterruptLevel2
!= 0 || PortConfig
->BusInterruptVector2
!= 0))
1396 DPRINT1("2 interrupts requested! Not yet supported\n");
1401 BOOLEAN InterruptShareable
;
1403 /* No, only 1 interrupt */
1404 DPRINT("1 interrupt, IRQ is %d\n", PortConfig
->BusInterruptLevel
);
1406 DeviceExtension
->InterruptLevel
= PortConfig
->BusInterruptLevel
;
1408 /* Register an interrupt handler for this device */
1409 MappedIrq
= HalGetInterruptVector(PortConfig
->AdapterInterfaceType
,
1410 PortConfig
->SystemIoBusNumber
,
1411 PortConfig
->BusInterruptLevel
,
1412 PortConfig
->BusInterruptVector
,
1416 /* Determing IRQ sharability as usual */
1417 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1418 PortConfig
->InterruptMode
== LevelSensitive
)
1420 InterruptShareable
= TRUE
;
1424 InterruptShareable
= FALSE
;
1427 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
,
1428 (PKSERVICE_ROUTINE
)ScsiPortIsr
,
1434 PortConfig
->InterruptMode
,
1439 if (!(NT_SUCCESS(Status
)))
1441 DPRINT1("Could not connect interrupt %d\n",
1442 PortConfig
->BusInterruptVector
);
1443 DeviceExtension
->Interrupt
= NULL
;
1450 /* Save IoAddress (from access ranges) */
1451 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1453 DeviceExtension
->IoAddress
=
1454 ((*(PortConfig
->AccessRanges
))[0]).RangeStart
.LowPart
;
1456 DPRINT("Io Address %x\n", DeviceExtension
->IoAddress
);
1459 /* Set flag that it's allowed to disconnect during this command */
1460 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
1462 /* Initialize counter of active requests (-1 means there are none) */
1463 DeviceExtension
->ActiveRequestCounter
= -1;
1465 /* Analyze what we have about DMA */
1466 if (DeviceExtension
->AdapterObject
!= NULL
&&
1467 PortConfig
->Master
&&
1468 PortConfig
->NeedPhysicalAddresses
)
1470 DeviceExtension
->MapRegisters
= TRUE
;
1474 DeviceExtension
->MapRegisters
= FALSE
;
1477 /* Call HwInitialize at DISPATCH_LEVEL */
1478 KeRaiseIrql(DISPATCH_LEVEL
, &Dirql
);
1480 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1481 DeviceExtension
->HwInitialize
,
1482 DeviceExtension
->MiniPortDeviceExtension
))
1484 DPRINT1("HwInitialize() failed!\n");
1486 Status
= STATUS_ADAPTER_HARDWARE_ERROR
;
1490 /* Check if a notification is needed */
1491 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
1493 /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1494 ScsiPortDpcForIsr(NULL
,
1495 DeviceExtension
->DeviceObject
,
1500 /* Lower irql back to what it was */
1503 /* Start our timer */
1504 IoStartTimer(PortDeviceObject
);
1506 /* Initialize bus scanning information */
1507 DeviceExtension
->BusesConfig
= ExAllocatePoolWithTag(PagedPool
,
1508 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1509 + sizeof(ULONG
), TAG_SCSIPORT
);
1511 if (!DeviceExtension
->BusesConfig
)
1513 DPRINT1("Out of resources!\n");
1514 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1519 RtlZeroMemory(DeviceExtension
->BusesConfig
,
1520 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1523 /* Store number of buses there */
1524 DeviceExtension
->BusesConfig
->NumberOfBuses
= (UCHAR
)DeviceExtension
->BusNum
;
1526 /* Scan the adapter for devices */
1527 SpiScanAdapter(DeviceExtension
);
1529 /* Build the registry device map */
1530 SpiBuildDeviceMap(DeviceExtension
,
1531 (PUNICODE_STRING
)Argument2
);
1533 /* Create the dos device link */
1534 swprintf(DosNameBuffer
,
1536 SystemConfig
->ScsiPortCount
);
1537 RtlInitUnicodeString(&DosDeviceName
, DosNameBuffer
);
1538 IoCreateSymbolicLink(&DosDeviceName
, &DeviceName
);
1540 /* Increase the port count */
1541 SystemConfig
->ScsiPortCount
++;
1542 FirstConfigCall
= FALSE
;
1544 /* Increase adapter number and bus number respectively */
1545 ConfigInfo
.AdapterNumber
++;
1548 ConfigInfo
.BusNumber
++;
1550 DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber
, MaxBus
);
1555 /* Clean up the mess */
1556 SpiCleanupAfterInit(DeviceExtension
);
1558 /* Close registry keys */
1559 if (ConfigInfo
.ServiceKey
!= NULL
)
1560 ZwClose(ConfigInfo
.ServiceKey
);
1562 if (ConfigInfo
.DeviceKey
!= NULL
)
1563 ZwClose(ConfigInfo
.DeviceKey
);
1565 if (ConfigInfo
.BusKey
!= NULL
)
1566 ZwClose(ConfigInfo
.BusKey
);
1568 if (ConfigInfo
.AccessRanges
!= NULL
)
1569 ExFreePool(ConfigInfo
.AccessRanges
);
1571 if (ConfigInfo
.Parameter
!= NULL
)
1572 ExFreePool(ConfigInfo
.Parameter
);
1574 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1575 Status
, DeviceFound
);
1577 return (DeviceFound
== FALSE
) ? Status
: STATUS_SUCCESS
;
1581 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1583 PSCSI_LUN_INFO LunInfo
;
1587 /* Check if we have something to clean up */
1588 if (DeviceExtension
== NULL
)
1591 /* Stop the timer and disconnect the interrupt */
1592 if (DeviceExtension
->Interrupt
)
1594 IoStopTimer(DeviceExtension
->DeviceObject
);
1595 IoDisconnectInterrupt(DeviceExtension
->Interrupt
);
1598 /* Delete ConfigInfo */
1599 if (DeviceExtension
->BusesConfig
)
1601 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
1603 if (!DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
])
1606 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
1610 /* Free current, but save pointer to the next one */
1611 Ptr
= LunInfo
->Next
;
1612 ExFreePool(LunInfo
);
1616 ExFreePool(DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]);
1619 ExFreePool(DeviceExtension
->BusesConfig
);
1622 /* Free PortConfig */
1623 if (DeviceExtension
->PortConfig
)
1624 ExFreePool(DeviceExtension
->PortConfig
);
1627 for(Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
1629 while (DeviceExtension
->LunExtensionList
[Lun
])
1631 Ptr
= DeviceExtension
->LunExtensionList
[Lun
];
1632 DeviceExtension
->LunExtensionList
[Lun
] = DeviceExtension
->LunExtensionList
[Lun
]->Next
;
1638 /* Free common buffer (if it exists) */
1639 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
&&
1640 DeviceExtension
->CommonBufferLength
!= 0)
1642 if (!DeviceExtension
->AdapterObject
)
1644 ExFreePool(DeviceExtension
->SrbExtensionBuffer
);
1649 HalFreeCommonBuffer(DeviceExtension
->AdapterObject
,
1650 DeviceExtension
->CommonBufferLength
,
1651 DeviceExtension
->PhysicalCommonBuffer
,
1652 DeviceExtension
->SrbExtensionBuffer
,
1659 if (DeviceExtension
->SrbInfo
!= NULL
)
1660 ExFreePool(DeviceExtension
->SrbInfo
);
1662 /* Unmap mapped addresses */
1663 while (DeviceExtension
->MappedAddressList
!= NULL
)
1665 MmUnmapIoSpace(DeviceExtension
->MappedAddressList
->MappedAddress
,
1666 DeviceExtension
->MappedAddressList
->NumberOfBytes
);
1668 Ptr
= DeviceExtension
->MappedAddressList
;
1669 DeviceExtension
->MappedAddressList
= DeviceExtension
->MappedAddressList
->NextMappedAddress
;
1674 /* Finally delete the device object */
1675 DPRINT("Deleting device %p\n", DeviceExtension
->DeviceObject
);
1676 IoDeleteDevice(DeviceExtension
->DeviceObject
);
1685 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
1686 IN PSCSI_REQUEST_BLOCK Srb
,
1687 IN PVOID LogicalAddress
,
1690 DPRINT1("ScsiPortIoMapTransfer()\n");
1699 ScsiPortLogError(IN PVOID HwDeviceExtension
,
1700 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
1707 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1709 DPRINT1("ScsiPortLogError() called\n");
1711 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1712 SCSI_PORT_DEVICE_EXTENSION
,
1713 MiniPortDeviceExtension
);
1716 DPRINT("ScsiPortLogError() done\n");
1724 ScsiPortMoveMemory(OUT PVOID Destination
,
1728 RtlMoveMemory(Destination
,
1738 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
1739 IN PVOID HwDeviceExtension
,
1742 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1745 DPRINT("ScsiPortNotification() called\n");
1747 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1748 SCSI_PORT_DEVICE_EXTENSION
,
1749 MiniPortDeviceExtension
);
1751 DPRINT("DeviceExtension %p\n", DeviceExtension
);
1753 va_start(ap
, HwDeviceExtension
);
1755 switch (NotificationType
)
1757 case RequestComplete
:
1759 PSCSI_REQUEST_BLOCK Srb
;
1760 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1762 Srb
= (PSCSI_REQUEST_BLOCK
) va_arg (ap
, PSCSI_REQUEST_BLOCK
);
1764 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb
);
1766 /* Make sure Srb is allright */
1767 ASSERT(Srb
->SrbStatus
!= SRB_STATUS_PENDING
);
1768 ASSERT(Srb
->Function
!= SRB_FUNCTION_EXECUTE_SCSI
|| Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
|| Srb
->ScsiStatus
== SCSISTAT_GOOD
);
1770 if (!(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
1772 /* It's been already completed */
1777 /* It's not active anymore */
1778 Srb
->SrbFlags
&= ~SRB_FLAGS_IS_ACTIVE
;
1780 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
1782 /* TODO: Treat it specially */
1787 /* Get the SRB data */
1788 SrbData
= SpiGetSrbData(DeviceExtension
,
1794 /* Make sure there are no CompletedRequests and there is a Srb */
1795 ASSERT(SrbData
->CompletedRequests
== NULL
&& SrbData
->Srb
!= NULL
);
1797 /* If it's a read/write request, make sure it has data inside it */
1798 if ((Srb
->SrbStatus
== SRB_STATUS_SUCCESS
) &&
1799 ((Srb
->Cdb
[0] == SCSIOP_READ
) || (Srb
->Cdb
[0] == SCSIOP_WRITE
)))
1801 ASSERT(Srb
->DataTransferLength
);
1804 SrbData
->CompletedRequests
= DeviceExtension
->InterruptData
.CompletedRequests
;
1805 DeviceExtension
->InterruptData
.CompletedRequests
= SrbData
;
1811 DPRINT("Notify: NextRequest\n");
1812 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1821 PathId
= (UCHAR
) va_arg (ap
, int);
1822 TargetId
= (UCHAR
) va_arg (ap
, int);
1823 Lun
= (UCHAR
) va_arg (ap
, int);
1825 DPRINT1 ("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1826 PathId
, TargetId
, Lun
);
1827 /* FIXME: Implement it! */
1830 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
1831 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT_LU;
1834 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
1839 DPRINT1("Notify: ResetDetected\n");
1844 DPRINT1 ("Unsupported notification %lu\n", NotificationType
);
1850 /* Request a DPC after we're done with the interrupt */
1851 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NOTIFICATION_NEEDED
;
1859 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
1860 IN ULONG BusDataType
,
1861 IN ULONG SystemIoBusNumber
,
1862 IN ULONG SlotNumber
,
1867 DPRINT("ScsiPortSetBusDataByOffset()\n");
1868 return(HalSetBusDataByOffset(BusDataType
,
1881 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
1882 IN INTERFACE_TYPE BusType
,
1883 IN ULONG SystemIoBusNumber
,
1884 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
1885 IN ULONG NumberOfBytes
,
1886 IN BOOLEAN InIoSpace
)
1888 DPRINT("ScsiPortValidateRange()\n");
1893 /* INTERNAL FUNCTIONS ********************************************************/
1896 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
1897 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
1898 IN PPORT_CONFIGURATION_INFORMATION PortConfig
)
1900 PACCESS_RANGE AccessRange
;
1901 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData
;
1907 /* Loop through all entries */
1908 for (Index
= 0; Index
< ResourceDescriptor
->PartialResourceList
.Count
; Index
++)
1910 PartialData
= &ResourceDescriptor
->PartialResourceList
.PartialDescriptors
[Index
];
1912 switch (PartialData
->Type
)
1914 case CmResourceTypePort
:
1915 /* Copy access ranges */
1916 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
1918 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
1920 AccessRange
->RangeStart
= PartialData
->u
.Port
.Start
;
1921 AccessRange
->RangeLength
= PartialData
->u
.Port
.Length
;
1923 AccessRange
->RangeInMemory
= FALSE
;
1928 case CmResourceTypeMemory
:
1929 /* Copy access ranges */
1930 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
1932 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
1934 AccessRange
->RangeStart
= PartialData
->u
.Memory
.Start
;
1935 AccessRange
->RangeLength
= PartialData
->u
.Memory
.Length
;
1937 AccessRange
->RangeInMemory
= TRUE
;
1942 case CmResourceTypeInterrupt
:
1943 /* Copy interrupt data */
1944 PortConfig
->BusInterruptLevel
= PartialData
->u
.Interrupt
.Level
;
1945 PortConfig
->BusInterruptVector
= PartialData
->u
.Interrupt
.Vector
;
1947 /* Set interrupt mode accordingly to the resource */
1948 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
1950 PortConfig
->InterruptMode
= Latched
;
1952 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
1954 PortConfig
->InterruptMode
= LevelSensitive
;
1958 case CmResourceTypeDma
:
1959 PortConfig
->DmaChannel
= PartialData
->u
.Dma
.Channel
;
1960 PortConfig
->DmaPort
= PartialData
->u
.Dma
.Port
;
1966 static PCM_RESOURCE_LIST
1967 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1968 PPORT_CONFIGURATION_INFORMATION PortConfig
)
1970 PCONFIGURATION_INFORMATION ConfigInfo
;
1971 PCM_RESOURCE_LIST ResourceList
;
1972 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
1973 PACCESS_RANGE AccessRange
;
1975 ULONG ListLength
= 0, i
, FullSize
;
1978 /* Get current Atdisk usage from the system */
1979 ConfigInfo
= IoGetConfigurationInformation();
1981 if (PortConfig
->AtdiskPrimaryClaimed
)
1982 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
1984 if (PortConfig
->AtdiskSecondaryClaimed
)
1985 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
1987 /* Do we use DMA? */
1988 if (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
||
1989 PortConfig
->DmaPort
!= SP_UNINITIALIZED_VALUE
)
1999 /* How many interrupts to we have? */
2000 if (DeviceExtension
->HwInterrupt
== NULL
||
2001 (PortConfig
->BusInterruptLevel
== 0 &&
2002 PortConfig
->BusInterruptVector
== 0))
2012 if (DeviceExtension
->HwInterrupt
!= NULL
&&
2013 (PortConfig
->BusInterruptLevel2
!= 0 ||
2014 PortConfig
->BusInterruptVector2
!= 0))
2020 /* How many access ranges do we use? */
2021 AccessRange
= &((*(PortConfig
->AccessRanges
))[0]);
2022 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2024 if (AccessRange
->RangeLength
!= 0)
2030 /* Allocate the resource list, since we know its size now */
2031 FullSize
= sizeof(CM_RESOURCE_LIST
) + (ListLength
- 1) *
2032 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
2034 ResourceList
= (PCM_RESOURCE_LIST
)ExAllocatePoolWithTag(PagedPool
, FullSize
, TAG_SCSIPORT
);
2040 RtlZeroMemory(ResourceList
, FullSize
);
2043 ResourceList
->Count
= 1;
2044 ResourceList
->List
[0].InterfaceType
= PortConfig
->AdapterInterfaceType
;
2045 ResourceList
->List
[0].BusNumber
= PortConfig
->SystemIoBusNumber
;
2046 ResourceList
->List
[0].PartialResourceList
.Count
= ListLength
;
2047 ResourceDescriptor
= ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
;
2049 /* Copy access ranges array over */
2050 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2052 AccessRange
= &((*(PortConfig
->AccessRanges
))[i
]);
2054 /* If the range is empty - skip it */
2055 if (AccessRange
->RangeLength
== 0)
2058 if (AccessRange
->RangeInMemory
)
2060 ResourceDescriptor
->Type
= CmResourceTypeMemory
;
2061 ResourceDescriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
;
2065 ResourceDescriptor
->Type
= CmResourceTypePort
;
2066 ResourceDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
2069 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2071 ResourceDescriptor
->u
.Memory
.Start
= AccessRange
->RangeStart
;
2072 ResourceDescriptor
->u
.Memory
.Length
= AccessRange
->RangeLength
;
2074 ResourceDescriptor
++;
2077 /* If we use interrupt(s), copy them */
2080 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2082 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2083 PortConfig
->InterruptMode
== LevelSensitive
)
2085 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2086 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2090 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2091 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2094 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
2095 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
2096 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2098 ResourceDescriptor
++;
2102 /* Copy 2nd interrupt
2103 FIXME: Stupid code duplication, remove */
2106 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2108 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2109 PortConfig
->InterruptMode
== LevelSensitive
)
2111 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2112 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2116 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2117 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2120 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
2121 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
2122 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2124 ResourceDescriptor
++;
2130 ResourceDescriptor
->Type
= CmResourceTypeDma
;
2131 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2132 ResourceDescriptor
->u
.Dma
.Channel
= PortConfig
->DmaChannel
;
2133 ResourceDescriptor
->u
.Dma
.Port
= PortConfig
->DmaPort
;
2134 ResourceDescriptor
->Flags
= 0;
2136 if (PortConfig
->DmaChannel
== SP_UNINITIALIZED_VALUE
)
2137 ResourceDescriptor
->u
.Dma
.Channel
= 0;
2139 if (PortConfig
->DmaPort
== SP_UNINITIALIZED_VALUE
)
2140 ResourceDescriptor
->u
.Dma
.Port
= 0;
2143 return ResourceList
;
2148 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
2149 IN PDEVICE_OBJECT DeviceObject
,
2150 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
2151 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
2152 IN PUNICODE_STRING RegistryPath
,
2154 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
)
2156 PCI_COMMON_CONFIG PciConfig
;
2157 PCI_SLOT_NUMBER SlotNumber
;
2160 ULONG FunctionNumber
;
2161 CHAR VendorIdString
[8];
2162 CHAR DeviceIdString
[8];
2163 UNICODE_STRING UnicodeStr
;
2164 PCM_RESOURCE_LIST ResourceList
;
2167 DPRINT ("SpiGetPciConfiguration() called\n");
2169 RtlZeroMemory(&ResourceList
, sizeof(PCM_RESOURCE_LIST
));
2170 SlotNumber
.u
.AsULONG
= 0;
2172 /* Loop through all devices */
2173 for (DeviceNumber
= NextSlotNumber
->u
.bits
.DeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
2175 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
2177 /* Loop through all functions */
2178 for (FunctionNumber
= NextSlotNumber
->u
.bits
.FunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
2180 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
2182 /* Get PCI config bytes */
2183 DataSize
= HalGetBusData(PCIConfiguration
,
2185 SlotNumber
.u
.AsULONG
,
2189 /* If result of HalGetBusData is 0, then the bus is wrong */
2193 /* If result is PCI_INVALID_VENDORID, then this device has no more
2195 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
2198 sprintf (VendorIdString
, "%04hx", PciConfig
.VendorID
);
2199 sprintf (DeviceIdString
, "%04hx", PciConfig
.DeviceID
);
2201 if (_strnicmp(VendorIdString
, HwInitializationData
->VendorId
, HwInitializationData
->VendorIdLength
) ||
2202 _strnicmp(DeviceIdString
, HwInitializationData
->DeviceId
, HwInitializationData
->DeviceIdLength
))
2204 /* It is not our device */
2208 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2212 SlotNumber
.u
.bits
.DeviceNumber
,
2213 SlotNumber
.u
.bits
.FunctionNumber
);
2216 RtlInitUnicodeString(&UnicodeStr
, L
"ScsiAdapter");
2217 Status
= HalAssignSlotResources(RegistryPath
,
2223 SlotNumber
.u
.AsULONG
,
2226 if (!NT_SUCCESS(Status
))
2229 /* Create configuration information */
2230 SpiResourceToConfig(HwInitializationData
,
2234 /* Free the resource list */
2235 ExFreePool(ResourceList
);
2237 /* Set dev & fn numbers */
2238 NextSlotNumber
->u
.bits
.DeviceNumber
= DeviceNumber
;
2239 NextSlotNumber
->u
.bits
.FunctionNumber
= FunctionNumber
+ 1;
2241 /* Save the slot number */
2242 PortConfig
->SlotNumber
= SlotNumber
.u
.AsULONG
;
2246 NextSlotNumber
->u
.bits
.FunctionNumber
= 0;
2249 NextSlotNumber
->u
.bits
.DeviceNumber
= 0;
2250 DPRINT ("No device found\n");
2257 /**********************************************************************
2259 * ScsiPortCreateClose
2262 * Answer requests for Create/Close calls: a null operation.
2269 * Pointer to a device object.
2272 * Pointer to an IRP.
2278 static NTSTATUS STDCALL
2279 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
2282 DPRINT("ScsiPortCreateClose()\n");
2284 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2285 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2287 return STATUS_SUCCESS
;
2291 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2294 PSCSI_LUN_INFO LunInfo
;
2295 PIO_STACK_LOCATION IrpStack
;
2296 PDEVICE_OBJECT DeviceObject
;
2297 PSCSI_REQUEST_BLOCK Srb
;
2300 /* Get pointer to the SRB */
2301 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2302 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
2304 /* Check if PathId matches number of buses */
2305 if (DeviceExtension
->BusesConfig
== NULL
||
2306 DeviceExtension
->BusesConfig
->NumberOfBuses
<= Srb
->PathId
)
2308 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2309 return STATUS_DEVICE_DOES_NOT_EXIST
;
2312 /* Get pointer to LunInfo */
2313 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Srb
->PathId
]->LunInfo
;
2315 /* Find matching LunInfo */
2318 if (LunInfo
->PathId
== Srb
->PathId
&&
2319 LunInfo
->TargetId
== Srb
->TargetId
&&
2320 LunInfo
->Lun
== Srb
->Lun
)
2325 LunInfo
= LunInfo
->Next
;
2328 /* If we couldn't find it - exit */
2329 if (LunInfo
== NULL
)
2330 return STATUS_DEVICE_DOES_NOT_EXIST
;
2334 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2336 /* Release, if asked */
2337 if (Srb
->Function
== SRB_FUNCTION_RELEASE_DEVICE
)
2339 LunInfo
->DeviceClaimed
= FALSE
;
2340 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2341 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2343 return STATUS_SUCCESS
;
2346 /* Attach, if not already claimed */
2347 if (LunInfo
->DeviceClaimed
)
2349 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2350 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
2352 return STATUS_DEVICE_BUSY
;
2355 /* Save the device object */
2356 DeviceObject
= LunInfo
->DeviceObject
;
2358 if (Srb
->Function
== SRB_FUNCTION_CLAIM_DEVICE
)
2359 LunInfo
->DeviceClaimed
= TRUE
;
2361 if (Srb
->Function
== SRB_FUNCTION_ATTACH_DEVICE
)
2362 LunInfo
->DeviceObject
= Srb
->DataBuffer
;
2364 Srb
->DataBuffer
= DeviceObject
;
2366 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2367 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2369 return STATUS_SUCCESS
;
2373 /**********************************************************************
2375 * ScsiPortDispatchScsi
2378 * Answer requests for SCSI calls
2384 * Standard dispatch arguments
2390 static NTSTATUS STDCALL
2391 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
2394 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2395 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2396 PIO_STACK_LOCATION Stack
;
2397 PSCSI_REQUEST_BLOCK Srb
;
2399 NTSTATUS Status
= STATUS_SUCCESS
;
2400 PIRP NextIrp
, IrpList
;
2401 PKDEVICE_QUEUE_ENTRY Entry
;
2403 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2406 DeviceExtension
= DeviceObject
->DeviceExtension
;
2407 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2409 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2412 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2413 Status
= STATUS_UNSUCCESSFUL
;
2415 Irp
->IoStatus
.Status
= Status
;
2416 Irp
->IoStatus
.Information
= 0;
2418 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2423 DPRINT("Srb: %p\n", Srb
);
2424 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
2425 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
2427 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2431 if (LunExtension
== NULL
)
2433 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2434 Status
= STATUS_NO_SUCH_DEVICE
;
2436 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2437 Irp
->IoStatus
.Status
= Status
;
2438 Irp
->IoStatus
.Information
= 0;
2440 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2445 switch (Srb
->Function
)
2447 case SRB_FUNCTION_SHUTDOWN
:
2448 case SRB_FUNCTION_FLUSH
:
2449 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2450 if (DeviceExtension
->CachesData
== FALSE
)
2452 /* All success here */
2453 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2454 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2455 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2456 return STATUS_SUCCESS
;
2458 /* Fall through to a usual execute operation */
2460 case SRB_FUNCTION_EXECUTE_SCSI
:
2461 case SRB_FUNCTION_IO_CONTROL
:
2462 /* Mark IRP as pending in all cases */
2463 IoMarkIrpPending(Irp
);
2465 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2467 /* Start IO directly */
2468 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2474 /* We need to be at DISPATCH_LEVEL */
2475 KeRaiseIrql (DISPATCH_LEVEL
, &oldIrql
);
2477 /* Insert IRP into the queue */
2478 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
2479 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
2482 /* It means the queue is empty, and we just start this request */
2483 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2486 /* Back to the old IRQL */
2487 KeLowerIrql (oldIrql
);
2489 return STATUS_PENDING
;
2491 case SRB_FUNCTION_CLAIM_DEVICE
:
2492 case SRB_FUNCTION_ATTACH_DEVICE
:
2493 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2495 /* Reference device object and keep the device object */
2496 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2499 case SRB_FUNCTION_RELEASE_DEVICE
:
2500 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2502 /* Dereference device object and clear the device object */
2503 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2506 case SRB_FUNCTION_RELEASE_QUEUE
:
2507 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2509 /* Guard with the spinlock */
2510 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2512 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2514 DPRINT("Queue is not frozen really\n");
2516 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2517 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2518 Status
= STATUS_SUCCESS
;
2523 /* Unfreeze the queue */
2524 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2526 if (LunExtension
->SrbInfo
.Srb
== NULL
)
2528 /* Get next logical unit request */
2529 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
2531 /* SpiGetNextRequestFromLun() releases the spinlock */
2536 DPRINT("The queue has active request\n");
2537 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2541 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2542 Status
= STATUS_SUCCESS
;
2545 case SRB_FUNCTION_FLUSH_QUEUE
:
2546 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2548 /* Guard with the spinlock */
2549 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2551 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2553 DPRINT("Queue is not frozen really\n");
2555 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2556 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2560 /* Make sure there is no active request */
2561 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
2563 /* Compile a list from the device queue */
2565 while ((Entry
= KeRemoveDeviceQueue(&LunExtension
->DeviceQueue
)) != NULL
)
2567 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
2570 Stack
= IoGetCurrentIrpStackLocation(NextIrp
);
2571 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2574 Srb
->SrbStatus
= SRB_STATUS_REQUEST_FLUSHED
;
2575 NextIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2577 /* Add then to the list */
2578 NextIrp
->Tail
.Overlay
.ListEntry
.Flink
= (PLIST_ENTRY
)IrpList
;
2582 /* Unfreeze the queue */
2583 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2585 /* Release the spinlock */
2586 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2588 /* Complete those requests */
2592 IrpList
= (PIRP
)NextIrp
->Tail
.Overlay
.ListEntry
.Flink
;
2594 IoCompleteRequest(NextIrp
, 0);
2597 Status
= STATUS_SUCCESS
;
2601 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
2602 Status
= STATUS_NOT_IMPLEMENTED
;
2606 Irp
->IoStatus
.Status
= Status
;
2608 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2614 /**********************************************************************
2616 * ScsiPortDeviceControl
2619 * Answer requests for device control calls
2625 * Standard dispatch arguments
2631 static NTSTATUS STDCALL
2632 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
2635 PIO_STACK_LOCATION Stack
;
2636 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2637 NTSTATUS Status
= STATUS_SUCCESS
;;
2639 DPRINT("ScsiPortDeviceControl()\n");
2641 Irp
->IoStatus
.Information
= 0;
2643 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2644 DeviceExtension
= DeviceObject
->DeviceExtension
;
2646 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
2648 case IOCTL_SCSI_GET_DUMP_POINTERS
:
2650 PDUMP_POINTERS DumpPointers
;
2651 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2652 DumpPointers
= (PDUMP_POINTERS
)Irp
->AssociatedIrp
.SystemBuffer
;
2653 DumpPointers
->DeviceObject
= DeviceObject
;
2655 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2659 case IOCTL_SCSI_GET_CAPABILITIES
:
2660 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2661 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
== sizeof(PVOID
))
2663 *((PVOID
*)Irp
->AssociatedIrp
.SystemBuffer
) = &DeviceExtension
->PortCapabilities
;
2665 Irp
->IoStatus
.Information
= sizeof(PVOID
);
2666 Status
= STATUS_SUCCESS
;
2670 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(IO_SCSI_CAPABILITIES
))
2672 Status
= STATUS_BUFFER_TOO_SMALL
;
2676 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2677 &DeviceExtension
->PortCapabilities
,
2678 sizeof(IO_SCSI_CAPABILITIES
));
2680 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
2681 Status
= STATUS_SUCCESS
;
2684 case IOCTL_SCSI_GET_INQUIRY_DATA
:
2685 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2687 /* Copy inquiry data to the port device extension */
2688 Status
= SpiGetInquiryData(DeviceExtension
, Irp
);
2692 DPRINT1(" unknown ioctl code: 0x%lX\n",
2693 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2697 /* Complete the request with the given status */
2698 Irp
->IoStatus
.Status
= Status
;
2699 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2706 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
2709 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2710 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2711 PIO_STACK_LOCATION IrpStack
;
2712 PSCSI_REQUEST_BLOCK Srb
;
2713 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2717 DPRINT("ScsiPortStartIo() called!\n");
2719 DeviceExtension
= DeviceObject
->DeviceExtension
;
2720 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2722 DPRINT("DeviceExtension %p\n", DeviceExtension
);
2724 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2726 /* Apply "default" flags */
2727 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
2729 /* Get LUN extension */
2730 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2735 if (DeviceExtension
->NeedSrbDataAlloc
||
2736 DeviceExtension
->NeedSrbExtensionAlloc
)
2739 SrbInfo
= SpiAllocateSrbStructures(DeviceExtension
,
2743 /* Couldn't alloc one or both data structures, return */
2744 if (SrbInfo
== NULL
)
2746 /* We have to call IoStartNextPacket, because this request
2748 if (LunExtension
->Flags
& LUNEX_REQUEST_PENDING
)
2749 IoStartNextPacket(DeviceObject
, FALSE
);
2756 /* No allocations are needed */
2757 SrbInfo
= &LunExtension
->SrbInfo
;
2758 Srb
->SrbExtension
= NULL
;
2759 Srb
->QueueTag
= SP_UNTAGGED
;
2762 /* Increase sequence number of SRB */
2763 if (!SrbInfo
->SequenceNumber
)
2765 /* Increase global sequence number */
2766 DeviceExtension
->SequenceNumber
++;
2769 SrbInfo
->SequenceNumber
= DeviceExtension
->SequenceNumber
;
2772 /* Check some special SRBs */
2773 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2775 /* Some special handling */
2776 DPRINT1("Abort command! Unimplemented now\n");
2783 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
)
2785 // Store the MDL virtual address in SrbInfo structure
2786 SrbInfo
->DataOffset
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2788 if (DeviceExtension
->MapBuffers
&& Irp
->MdlAddress
)
2790 /* Calculate offset within DataBuffer */
2791 SrbInfo
->DataOffset
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
2792 Srb
->DataBuffer
= SrbInfo
->DataOffset
+
2793 (ULONG
)((PUCHAR
)Srb
->DataBuffer
-
2794 (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2797 if (DeviceExtension
->AdapterObject
)
2800 KeFlushIoBuffers(Irp
->MdlAddress
,
2801 Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? TRUE
: FALSE
,
2805 if (DeviceExtension
->MapRegisters
)
2807 /* Calculate number of needed map registers */
2808 SrbInfo
->NumberOfMapRegisters
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
2810 Srb
->DataTransferLength
);
2812 /* Allocate adapter channel */
2813 Status
= IoAllocateAdapterChannel(DeviceExtension
->AdapterObject
,
2814 DeviceExtension
->DeviceObject
,
2815 SrbInfo
->NumberOfMapRegisters
,
2819 if (!NT_SUCCESS(Status
))
2821 DPRINT1("IoAllocateAdapterChannel() failed!\n");
2823 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
2824 ScsiPortNotification(RequestComplete
,
2825 DeviceExtension
+ 1,
2828 ScsiPortNotification(NextRequest
,
2829 DeviceExtension
+ 1);
2831 /* Request DPC for that work */
2832 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2835 /* Control goes to SpiAdapterControl */
2840 /* Increase active request counter */
2841 CounterResult
= InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
2843 if (CounterResult
== 0 &&
2844 DeviceExtension
->AdapterObject
!= NULL
&&
2845 !DeviceExtension
->MapRegisters
)
2848 IoAllocateAdapterChannel(
2849 DeviceExtension
->AdapterObject
,
2851 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
,
2852 ScsiPortAllocationRoutine
,
2858 /* TODO: DMA is not implemented yet */
2864 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
2866 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
2867 ScsiPortStartPacket
,
2870 DPRINT("Synchronization failed!\n");
2872 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2873 Irp
->IoStatus
.Information
= 0;
2874 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
2876 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2879 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
2881 DPRINT("ScsiPortStartIo() done\n");
2885 static BOOLEAN STDCALL
2886 ScsiPortStartPacket(IN OUT PVOID Context
)
2888 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2889 PIO_STACK_LOCATION IrpStack
;
2890 PSCSI_REQUEST_BLOCK Srb
;
2891 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)Context
;
2892 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2893 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2897 DPRINT("ScsiPortStartPacket() called\n");
2899 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
2901 IrpStack
= IoGetCurrentIrpStackLocation(DeviceObject
->CurrentIrp
);
2902 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2904 /* Get LUN extension */
2905 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2910 /* Check if we are in a reset state */
2911 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
2913 /* Mark the we've got requests while being in the reset state */
2914 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET_REQUEST
;
2918 /* Set the time out value */
2919 DeviceExtension
->TimerCount
= Srb
->TimeOutValue
;
2922 DeviceExtension
->Flags
|= SCSI_PORT_DEVICE_BUSY
;
2924 if (LunExtension
->RequestTimeout
!= -1)
2926 /* Timer already active */
2931 /* It hasn't been initialized yet */
2932 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
2936 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2938 /* Handle bypass-requests */
2940 /* Is this an abort request? */
2941 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2943 /* Get pointer to SRB info structure */
2944 SrbInfo
= SpiGetSrbData(DeviceExtension
,
2950 /* Check if the request is still "active" */
2951 if (SrbInfo
== NULL
||
2952 SrbInfo
->Srb
== NULL
||
2953 !(SrbInfo
->Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
2955 /* It's not, mark it as active then */
2956 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
2959 LunExtension
->RequestTimeout
= -1;
2961 DPRINT("Request has been already completed, but abort request came\n");
2962 Srb
->SrbStatus
= SRB_STATUS_ABORT_FAILED
;
2964 /* Notify about request complete */
2965 ScsiPortNotification(RequestComplete
,
2966 DeviceExtension
->MiniPortDeviceExtension
,
2969 /* and about readiness for the next request */
2970 ScsiPortNotification(NextRequest
,
2971 DeviceExtension
->MiniPortDeviceExtension
);
2973 /* They might ask for some work, so queue the DPC for them */
2974 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2976 /* We're done in this branch */
2982 /* Add number of queued requests */
2983 LunExtension
->QueueCount
++;
2986 /* Bypass requests don't need request sense */
2987 LunExtension
->Flags
&= ~LUNEX_NEED_REQUEST_SENSE
;
2989 /* Is disconnect disabled for this request? */
2990 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
2992 /* Set the corresponding flag */
2993 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
2996 /* Transfer timeout value from Srb to Lun */
2997 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
3001 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3003 /* It's a disconnect, so no more requests can go */
3004 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3007 LunExtension
->Flags
|= SCSI_PORT_LU_ACTIVE
;
3009 /* Increment queue count */
3010 LunExtension
->QueueCount
++;
3012 /* If it's tagged - special thing */
3013 if (Srb
->QueueTag
!= SP_UNTAGGED
)
3015 SrbInfo
= &DeviceExtension
->SrbInfo
[Srb
->QueueTag
- 1];
3017 /* Chek for consistency */
3018 ASSERT(SrbInfo
->Requests
.Blink
== NULL
);
3020 /* Insert it into the list of requests */
3021 InsertTailList(&LunExtension
->SrbInfo
.Requests
, &SrbInfo
->Requests
);
3025 /* Mark this Srb active */
3026 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
3028 /* Call HwStartIo routine */
3029 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
3032 /* If notification is needed, then request a DPC */
3033 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
3034 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3039 IO_ALLOCATION_ACTION
3041 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
,
3043 PVOID MapRegisterBase
,
3046 PSCSI_REQUEST_BLOCK Srb
;
3047 PSCSI_SG_ADDRESS ScatterGatherList
;
3049 PIO_STACK_LOCATION IrpStack
;
3050 ULONG TotalLength
= 0;
3051 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3052 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3054 BOOLEAN WriteToDevice
;
3056 /* Get pointers to SrbInfo and DeviceExtension */
3057 SrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)Context
;
3058 DeviceExtension
= DeviceObject
->DeviceExtension
;
3060 /* Get pointer to SRB */
3061 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3062 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
3064 /* Depending on the map registers number, we allocate
3065 either from NonPagedPool, or from our static list */
3066 if (SrbInfo
->NumberOfMapRegisters
> MAX_SG_LIST
)
3068 SrbInfo
->ScatterGather
= ExAllocatePoolWithTag(
3069 NonPagedPool
, SrbInfo
->NumberOfMapRegisters
* sizeof(SCSI_SG_ADDRESS
), TAG_SCSIPORT
);
3071 if (SrbInfo
->ScatterGather
== NULL
)
3074 Srb
->SrbFlags
|= SRB_FLAGS_SGLIST_FROM_POOL
;
3078 SrbInfo
->ScatterGather
= SrbInfo
->ScatterGatherList
;
3081 /* Use chosen SG list source */
3082 ScatterGatherList
= SrbInfo
->ScatterGather
;
3084 /* Save map registers base */
3085 SrbInfo
->BaseOfMapRegister
= MapRegisterBase
;
3087 /* Determine WriteToDevice flag */
3088 WriteToDevice
= Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
? TRUE
: FALSE
;
3090 /* Get virtual address of the data buffer */
3091 DataVA
= (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
3092 ((PCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
3094 /* Build the actual SG list */
3095 while (TotalLength
< Srb
->DataTransferLength
)
3097 if (!ScatterGatherList
)
3100 ScatterGatherList
->Length
= Srb
->DataTransferLength
- TotalLength
;
3101 ScatterGatherList
->PhysicalAddress
= IoMapTransfer(DeviceExtension
->AdapterObject
,
3104 DataVA
+ TotalLength
,
3105 &ScatterGatherList
->Length
,
3108 TotalLength
+= ScatterGatherList
->Length
;
3109 ScatterGatherList
++;
3112 /* Schedule an active request */
3113 InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
3114 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &CurrentIrql
);
3115 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
3116 ScsiPortStartPacket
,
3118 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, CurrentIrql
);
3120 return DeallocateObjectKeepRegisters
;
3123 static PSCSI_PORT_LUN_EXTENSION
3124 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3126 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3127 ULONG LunExtensionSize
;
3129 DPRINT("SpiAllocateLunExtension (%p)\n",
3132 /* Round LunExtensionSize first to the sizeof LONGLONG */
3133 LunExtensionSize
= (DeviceExtension
->LunExtensionSize
+
3134 sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
3136 LunExtensionSize
+= sizeof(SCSI_PORT_LUN_EXTENSION
);
3137 DPRINT("LunExtensionSize %lu\n", LunExtensionSize
);
3139 LunExtension
= ExAllocatePoolWithTag(NonPagedPool
, LunExtensionSize
, TAG_SCSIPORT
);
3140 if (LunExtension
== NULL
)
3142 DPRINT1("Out of resources!\n");
3146 /* Zero everything */
3147 RtlZeroMemory(LunExtension
, LunExtensionSize
);
3149 /* Initialize a list of requests */
3150 InitializeListHead(&LunExtension
->SrbInfo
.Requests
);
3152 /* Initialize timeout counter */
3153 LunExtension
->RequestTimeout
= -1;
3155 /* Set maximum queue size */
3156 LunExtension
->MaxQueueCount
= 256;
3158 /* Initialize request queue */
3159 KeInitializeDeviceQueue (&LunExtension
->DeviceQueue
);
3161 return LunExtension
;
3164 static PSCSI_PORT_LUN_EXTENSION
3165 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3170 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3172 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3173 DeviceExtension
, PathId
, TargetId
, Lun
);
3175 /* Get appropriate list */
3176 LunExtension
= DeviceExtension
->LunExtensionList
[(TargetId
+ Lun
) % LUS_NUMBER
];
3178 /* Iterate it until we find what we need */
3179 while (LunExtension
)
3181 if (LunExtension
->TargetId
== TargetId
&&
3182 LunExtension
->Lun
== Lun
&&
3183 LunExtension
->PathId
== PathId
)
3185 /* All matches, return */
3186 return LunExtension
;
3189 /* Advance to the next item */
3190 LunExtension
= LunExtension
->Next
;
3193 /* We did not find anything */
3194 DPRINT("Nothing found\n");
3198 static PSCSI_REQUEST_BLOCK_INFO
3199 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3200 PSCSI_PORT_LUN_EXTENSION LunExtension
,
3201 PSCSI_REQUEST_BLOCK Srb
)
3204 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3206 /* Spinlock must be held while this function executes */
3207 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3209 /* Allocate SRB data structure */
3210 if (DeviceExtension
->NeedSrbDataAlloc
)
3212 /* Treat the abort request in a special way */
3213 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
3215 SrbInfo
= SpiGetSrbData(DeviceExtension
,
3221 else if (Srb
->SrbFlags
&
3222 (SRB_FLAGS_QUEUE_ACTION_ENABLE
| SRB_FLAGS_NO_QUEUE_FREEZE
) &&
3223 !(Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3226 /* Do not process tagged commands if need request sense is set */
3227 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
3229 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3231 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3232 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3234 /* Relese the spinlock and return */
3235 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3239 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
3240 SrbInfo
= DeviceExtension
->FreeSrbInfo
;
3242 if (SrbInfo
== NULL
)
3244 /* No SRB structures left in the list. We have to leave
3245 and wait while we are called again */
3247 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3248 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3252 DeviceExtension
->FreeSrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)SrbInfo
->Requests
.Flink
;
3254 /* QueueTag must never be 0, so +1 to it */
3255 Srb
->QueueTag
= (UCHAR
)(SrbInfo
- DeviceExtension
->SrbInfo
) + 1;
3259 /* Usual untagged command */
3261 (!IsListEmpty(&LunExtension
->SrbInfo
.Requests
) ||
3262 LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
) &&
3263 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
3266 /* Mark it as pending and leave */
3267 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3268 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3269 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3271 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3275 Srb
->QueueTag
= SP_UNTAGGED
;
3276 SrbInfo
= &LunExtension
->SrbInfo
;
3281 Srb
->QueueTag
= SP_UNTAGGED
;
3282 SrbInfo
= &LunExtension
->SrbInfo
;
3285 /* Allocate SRB extension structure */
3286 if (DeviceExtension
->NeedSrbExtensionAlloc
)
3288 /* Check the list of free extensions */
3289 SrbExtension
= DeviceExtension
->FreeSrbExtensions
;
3291 /* If no free extensions... */
3292 if (SrbExtension
== NULL
)
3295 if (Srb
->Function
!= SRB_FUNCTION_ABORT_COMMAND
&&
3296 Srb
->QueueTag
!= SP_UNTAGGED
)
3298 SrbInfo
->Requests
.Blink
= NULL
;
3299 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
3300 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
3303 /* Return, in order to be called again later */
3304 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3305 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3309 /* Remove that free SRB extension from the list (since
3310 we're going to use it) */
3311 DeviceExtension
->FreeSrbExtensions
= *((PVOID
*)SrbExtension
);
3313 /* Spinlock can be released now */
3314 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3316 Srb
->SrbExtension
= SrbExtension
;
3318 if (Srb
->SenseInfoBuffer
!= NULL
&&
3319 DeviceExtension
->SupportsAutoSense
)
3321 /* Store pointer to the SenseInfo buffer */
3322 SrbInfo
->SaveSenseRequest
= Srb
->SenseInfoBuffer
;
3324 /* Does data fit the buffer? */
3325 if (Srb
->SenseInfoBufferLength
> sizeof(SENSE_DATA
))
3327 /* No, disabling autosense at all */
3328 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_AUTOSENSE
;
3332 /* Yes, update the buffer pointer */
3333 Srb
->SenseInfoBuffer
= SrbExtension
+ DeviceExtension
->SrbExtensionSize
;
3340 Srb
->SrbExtension
= NULL
;
3341 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3349 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
3350 IN PSCSI_LUN_INFO LunInfo
)
3352 IO_STATUS_BLOCK IoStatusBlock
;
3353 PIO_STACK_LOCATION IrpStack
;
3358 PINQUIRYDATA InquiryBuffer
;
3359 PSENSE_DATA SenseBuffer
;
3360 BOOLEAN KeepTrying
= TRUE
;
3361 ULONG RetryCount
= 0;
3362 SCSI_REQUEST_BLOCK Srb
;
3364 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3365 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3367 DPRINT ("SpiSendInquiry() called\n");
3369 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3371 InquiryBuffer
= ExAllocatePoolWithTag (NonPagedPool
, INQUIRYDATABUFFERSIZE
, TAG_SCSIPORT
);
3372 if (InquiryBuffer
== NULL
)
3373 return STATUS_INSUFFICIENT_RESOURCES
;
3375 SenseBuffer
= ExAllocatePoolWithTag (NonPagedPool
, SENSE_BUFFER_SIZE
, TAG_SCSIPORT
);
3376 if (SenseBuffer
== NULL
)
3378 ExFreePool(InquiryBuffer
);
3379 return STATUS_INSUFFICIENT_RESOURCES
;
3384 /* Initialize event for waiting */
3385 KeInitializeEvent(&Event
,
3390 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN
,
3395 INQUIRYDATABUFFERSIZE
,
3401 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3402 return STATUS_INSUFFICIENT_RESOURCES
;
3406 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3408 Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
3409 Srb
.OriginalRequest
= Irp
;
3410 Srb
.PathId
= LunInfo
->PathId
;
3411 Srb
.TargetId
= LunInfo
->TargetId
;
3412 Srb
.Lun
= LunInfo
->Lun
;
3413 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3414 Srb
.SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3415 Srb
.TimeOutValue
= 4;
3418 Srb
.SenseInfoBuffer
= SenseBuffer
;
3419 Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3421 Srb
.DataBuffer
= InquiryBuffer
;
3422 Srb
.DataTransferLength
= INQUIRYDATABUFFERSIZE
;
3424 /* Attach Srb to the Irp */
3425 IrpStack
= IoGetNextIrpStackLocation (Irp
);
3426 IrpStack
->Parameters
.Scsi
.Srb
= &Srb
;
3429 Cdb
= (PCDB
)Srb
.Cdb
;
3430 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_INQUIRY
;
3431 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= LunInfo
->Lun
;
3432 Cdb
->CDB6INQUIRY
.AllocationLength
= INQUIRYDATABUFFERSIZE
;
3434 /* Call the driver */
3435 Status
= IoCallDriver(DeviceObject
, Irp
);
3437 /* Wait for it to complete */
3438 if (Status
== STATUS_PENDING
)
3440 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3441 KeWaitForSingleObject(&Event
,
3446 Status
= IoStatusBlock
.Status
;
3449 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status
);
3451 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_SUCCESS
)
3453 /* All fine, copy data over */
3454 RtlCopyMemory(LunInfo
->InquiryData
,
3456 INQUIRYDATABUFFERSIZE
);
3458 Status
= STATUS_SUCCESS
;
3463 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb
.SrbStatus
);
3464 /* Check if the queue is frozen */
3465 if (Srb
.SrbStatus
& SRB_STATUS_QUEUE_FROZEN
)
3467 /* Something weird happened, deal with it (unfreeze the queue) */
3470 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb
.TargetId
);
3472 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3477 /* Clear frozen flag */
3478 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
3480 /* Acquire the spinlock */
3481 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
3483 /* Process the request */
3484 SpiGetNextRequestFromLun(DeviceObject
->DeviceExtension
, LunExtension
);
3486 /* SpiGetNextRequestFromLun() releases the spinlock,
3487 so we just lower irql back to what it was before */
3491 /* Check if data overrun happened */
3492 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
3494 DPRINT("Data overrun at TargetId %d\n", LunInfo
->TargetId
);
3495 /* Nothing dramatic, just copy data, but limiting the size */
3496 RtlCopyMemory(LunInfo
->InquiryData
,
3498 (Srb
.DataTransferLength
> INQUIRYDATABUFFERSIZE
) ?
3499 INQUIRYDATABUFFERSIZE
: Srb
.DataTransferLength
);
3501 Status
= STATUS_SUCCESS
;
3504 else if ((Srb
.SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3505 SenseBuffer
->SenseKey
== SCSI_SENSE_ILLEGAL_REQUEST
)
3507 /* LUN is not valid, but some device responds there.
3508 Mark it as invalid anyway */
3510 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3515 /* Retry a couple of times if no timeout happened */
3516 if ((RetryCount
< 2) &&
3517 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_NO_DEVICE
) &&
3518 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_SELECTION_TIMEOUT
))
3525 /* That's all, go to exit */
3528 /* Set status according to SRB status */
3529 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_FUNCTION
||
3530 SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH
)
3532 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3536 Status
= STATUS_IO_DEVICE_ERROR
;
3544 ExFreePool(InquiryBuffer
);
3545 ExFreePool(SenseBuffer
);
3547 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status
);
3553 /* Scans all SCSI buses */
3555 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3557 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3561 PSCSI_BUS_SCAN_INFO BusScanInfo
;
3562 PSCSI_LUN_INFO LastLunInfo
, LunInfo
, LunInfoExists
;
3563 BOOLEAN DeviceExists
;
3568 DPRINT("SpiScanAdapter() called\n");
3570 /* Scan all buses */
3571 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
3573 DPRINT(" Scanning bus %d\n", Bus
);
3576 /* Get pointer to the scan information */
3577 BusScanInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
];
3581 /* Find the last LUN info in the list */
3582 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3583 LastLunInfo
= LunInfo
;
3585 while (LunInfo
!= NULL
)
3587 LastLunInfo
= LunInfo
;
3588 LunInfo
= LunInfo
->Next
;
3593 /* We need to allocate this buffer */
3594 BusScanInfo
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_BUS_SCAN_INFO
), TAG_SCSIPORT
);
3598 DPRINT1("Out of resources!\n");
3602 /* Store the pointer in the BusScanInfo array */
3603 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
] = BusScanInfo
;
3605 /* Fill this struct (length and bus ids for now) */
3606 BusScanInfo
->Length
= sizeof(SCSI_BUS_SCAN_INFO
);
3607 BusScanInfo
->LogicalUnitsCount
= 0;
3608 BusScanInfo
->BusIdentifier
= DeviceExtension
->PortConfig
->InitiatorBusId
[Bus
];
3609 BusScanInfo
->LunInfo
= NULL
;
3611 /* Set pointer to the last LUN info to NULL */
3615 /* Create LUN information structure */
3616 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3618 if (LunInfo
== NULL
)
3620 DPRINT1("Out of resources!\n");
3624 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3626 /* Create LunExtension */
3627 LunExtension
= SpiAllocateLunExtension (DeviceExtension
);
3629 /* And send INQUIRY to every target */
3630 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
3632 /* TODO: Support scan bottom-up */
3634 /* Skip if it's the same address */
3635 if (Target
== BusScanInfo
->BusIdentifier
)
3638 /* Try to find an existing device here */
3639 DeviceExists
= FALSE
;
3640 LunInfoExists
= BusScanInfo
->LunInfo
;
3642 /* Find matching address on this bus */
3643 while (LunInfoExists
)
3645 if (LunInfoExists
->TargetId
== Target
)
3647 DeviceExists
= TRUE
;
3651 /* Advance to the next one */
3652 LunInfoExists
= LunInfoExists
->Next
;
3655 /* No need to bother rescanning, since we already did that before */
3659 /* Scan all logical units */
3660 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
3662 if ((!LunExtension
) || (!LunInfo
))
3665 /* Add extension to the list */
3666 Hint
= (Target
+ Lun
) % LUS_NUMBER
;
3667 LunExtension
->Next
= DeviceExtension
->LunExtensionList
[Hint
];
3668 DeviceExtension
->LunExtensionList
[Hint
] = LunExtension
;
3670 /* Fill Path, Target, Lun fields */
3671 LunExtension
->PathId
= LunInfo
->PathId
= (UCHAR
)Bus
;
3672 LunExtension
->TargetId
= LunInfo
->TargetId
= (UCHAR
) Target
;
3673 LunExtension
->Lun
= LunInfo
->Lun
= (UCHAR
)Lun
;
3675 /* Set flag to prevent race conditions */
3676 LunExtension
->Flags
|= SCSI_PORT_SCAN_IN_PROGRESS
;
3678 /* Zero LU extension contents */
3679 if (DeviceExtension
->LunExtensionSize
)
3681 RtlZeroMemory(LunExtension
+ 1,
3682 DeviceExtension
->LunExtensionSize
);
3685 /* Finally send the inquiry command */
3686 Status
= SpiSendInquiry(DeviceExtension
->DeviceObject
, LunInfo
);
3688 if (NT_SUCCESS(Status
))
3690 /* Let's see if we really found a device */
3691 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3693 /* Check if this device is unsupported */
3694 if (InquiryData
->DeviceTypeQualifier
== DEVICE_QUALIFIER_NOT_SUPPORTED
)
3696 DeviceExtension
->LunExtensionList
[Hint
] =
3697 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3702 /* Clear the "in scan" flag */
3703 LunExtension
->Flags
&= ~SCSI_PORT_SCAN_IN_PROGRESS
;
3705 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3706 InquiryData
->DeviceType
, Bus
, Target
, Lun
);
3708 /* Add this info to the linked list */
3709 LunInfo
->Next
= NULL
;
3711 LastLunInfo
->Next
= LunInfo
;
3713 BusScanInfo
->LunInfo
= LunInfo
;
3715 /* Store the last LUN info */
3716 LastLunInfo
= LunInfo
;
3718 /* Store DeviceObject */
3719 LunInfo
->DeviceObject
= DeviceExtension
->DeviceObject
;
3721 /* Allocate another buffer */
3722 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3726 DPRINT1("Out of resources!\n");
3730 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3732 /* Create a new LU extension */
3733 LunExtension
= SpiAllocateLunExtension(DeviceExtension
);
3739 /* Remove this LUN from the list */
3740 DeviceExtension
->LunExtensionList
[Hint
] =
3741 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3743 /* Decide whether we are continuing or not */
3744 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
3752 /* Free allocated buffers */
3754 ExFreePool(LunExtension
);
3757 ExFreePool(LunInfo
);
3759 /* Sum what we found */
3760 BusScanInfo
->LogicalUnitsCount
+= (UCHAR
) DevicesFound
;
3761 DPRINT(" Found %d devices on bus %d\n", DevicesFound
, Bus
);
3764 DPRINT ("SpiScanAdapter() done\n");
3769 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3772 ULONG InquiryDataSize
;
3773 PSCSI_LUN_INFO LunInfo
;
3774 ULONG BusCount
, LunCount
, Length
;
3775 PIO_STACK_LOCATION IrpStack
;
3776 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
3777 PSCSI_INQUIRY_DATA InquiryData
;
3778 PSCSI_BUS_DATA BusData
;
3782 DPRINT("SpiGetInquiryData() called\n");
3784 /* Get pointer to the buffer */
3785 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3786 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3788 /* Initialize bus and LUN counters */
3789 BusCount
= DeviceExtension
->BusesConfig
->NumberOfBuses
;
3792 /* Calculate total number of LUNs */
3793 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3794 LunCount
+= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3796 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
3798 ((sizeof(SCSI_INQUIRY_DATA
) - 1 + INQUIRYDATABUFFERSIZE
+
3799 sizeof(ULONG
) - 1) & ~(sizeof(ULONG
) - 1));
3801 /* Calculate data size */
3802 Length
= sizeof(SCSI_ADAPTER_BUS_INFO
) + (BusCount
- 1) *
3803 sizeof(SCSI_BUS_DATA
);
3805 Length
+= InquiryDataSize
* LunCount
;
3807 /* Check, if all data is going to fit into provided buffer */
3808 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< Length
)
3810 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3811 return STATUS_BUFFER_TOO_SMALL
;
3814 /* Store data size in the IRP */
3815 Irp
->IoStatus
.Information
= Length
;
3817 DPRINT("Data size: %lu\n", Length
);
3819 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
3821 AdapterBusInfo
->NumberOfBuses
= (UCHAR
)BusCount
;
3823 /* Point InquiryData to the corresponding place inside Buffer */
3824 InquiryData
= (PSCSI_INQUIRY_DATA
)(Buffer
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
3825 (BusCount
- 1) * sizeof(SCSI_BUS_DATA
));
3828 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3830 BusData
= &AdapterBusInfo
->BusData
[Bus
];
3832 /* Calculate and save an offset of the inquiry data */
3833 BusData
->InquiryDataOffset
= (PUCHAR
)InquiryData
- Buffer
;
3835 /* Get a pointer to the LUN information structure */
3836 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3838 /* Store Initiator Bus Id */
3839 BusData
->InitiatorBusId
=
3840 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->BusIdentifier
;
3842 /* Store LUN count */
3843 BusData
->NumberOfLogicalUnits
=
3844 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3847 while (LunInfo
!= NULL
)
3849 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
3850 Bus
, LunInfo
->TargetId
, LunInfo
->Lun
);
3852 /* Fill InquiryData with values */
3853 InquiryData
->PathId
= LunInfo
->PathId
;
3854 InquiryData
->TargetId
= LunInfo
->TargetId
;
3855 InquiryData
->Lun
= LunInfo
->Lun
;
3856 InquiryData
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
3857 InquiryData
->DeviceClaimed
= LunInfo
->DeviceClaimed
;
3858 InquiryData
->NextInquiryDataOffset
=
3859 (PUCHAR
)InquiryData
+ InquiryDataSize
- Buffer
;
3861 /* Copy data in it */
3862 RtlCopyMemory(InquiryData
->InquiryData
,
3863 LunInfo
->InquiryData
,
3864 INQUIRYDATABUFFERSIZE
);
3866 /* Move to the next LUN */
3867 LunInfo
= LunInfo
->Next
;
3868 InquiryData
= (PSCSI_INQUIRY_DATA
) ((PCHAR
)InquiryData
+ InquiryDataSize
);
3871 /* Either mark the end, or set offset to 0 */
3872 if (BusData
->NumberOfLogicalUnits
!= 0)
3873 ((PSCSI_INQUIRY_DATA
) ((PCHAR
) InquiryData
- InquiryDataSize
))->NextInquiryDataOffset
= 0;
3875 BusData
->InquiryDataOffset
= 0;
3878 /* Finish with success */
3879 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3880 return STATUS_SUCCESS
;
3883 static PSCSI_REQUEST_BLOCK_INFO
3884 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3890 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3892 if (QueueTag
== SP_UNTAGGED
)
3894 /* Untagged request, get LU and return pointer to SrbInfo */
3895 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3900 /* Return NULL in case of error */
3904 /* Return the pointer to SrbInfo */
3905 return &LunExtension
->SrbInfo
;
3909 /* Make sure the tag is valid, if it is - return the data */
3910 if (QueueTag
> DeviceExtension
->SrbDataCount
|| QueueTag
< 1)
3913 return &DeviceExtension
->SrbInfo
[QueueTag
-1];
3918 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3919 IN PSCSI_REQUEST_BLOCK InitialSrb
)
3921 PSCSI_REQUEST_BLOCK Srb
;
3924 PIO_STACK_LOCATION IrpStack
;
3925 LARGE_INTEGER LargeInt
;
3928 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb
);
3931 Srb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
) + sizeof(PVOID
), TAG_SCSIPORT
);
3932 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3935 LargeInt
.QuadPart
= (LONGLONG
) 1;
3936 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_READ
,
3937 DeviceExtension
->DeviceObject
,
3938 InitialSrb
->SenseInfoBuffer
,
3939 InitialSrb
->SenseInfoBufferLength
,
3943 IoSetCompletionRoutine(Irp
,
3944 (PIO_COMPLETION_ROUTINE
)SpiCompletionRoutine
,
3952 DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb
);
3956 IrpStack
= IoGetNextIrpStackLocation(Irp
);
3957 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3959 /* Put Srb address into Irp... */
3960 IrpStack
->Parameters
.Others
.Argument1
= (PVOID
)Srb
;
3962 /* ...and vice versa */
3963 Srb
->OriginalRequest
= Irp
;
3966 Ptr
= (PVOID
*)(Srb
+1);
3969 /* Build CDB for REQUEST SENSE */
3971 Cdb
= (PCDB
)Srb
->Cdb
;
3973 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
3974 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= 0;
3975 Cdb
->CDB6INQUIRY
.Reserved1
= 0;
3976 Cdb
->CDB6INQUIRY
.PageCode
= 0;
3977 Cdb
->CDB6INQUIRY
.IReserved
= 0;
3978 Cdb
->CDB6INQUIRY
.AllocationLength
= (UCHAR
)InitialSrb
->SenseInfoBufferLength
;
3979 Cdb
->CDB6INQUIRY
.Control
= 0;
3982 Srb
->TargetId
= InitialSrb
->TargetId
;
3983 Srb
->Lun
= InitialSrb
->Lun
;
3984 Srb
->PathId
= InitialSrb
->PathId
;
3986 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3987 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
3989 /* Timeout will be 2 seconds */
3990 Srb
->TimeOutValue
= 2;
3992 /* No auto request sense */
3993 Srb
->SenseInfoBufferLength
= 0;
3994 Srb
->SenseInfoBuffer
= NULL
;
3996 /* Set necessary flags */
3997 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_BYPASS_FROZEN_QUEUE
|
3998 SRB_FLAGS_DISABLE_DISCONNECT
;
4000 /* Transfer disable synch transfer flag */
4001 if (InitialSrb
->SrbFlags
& SRB_FLAGS_DISABLE_SYNCH_TRANSFER
)
4002 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4004 Srb
->DataBuffer
= InitialSrb
->SenseInfoBuffer
;
4006 /* Fill the transfer length */
4007 Srb
->DataTransferLength
= InitialSrb
->SenseInfoBufferLength
;
4009 /* Clear statuses */
4010 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
4013 /* Call the driver */
4014 (VOID
)IoCallDriver(DeviceExtension
->DeviceObject
, Irp
);
4016 DPRINT("SpiSendRequestSense() done\n");
4023 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4024 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
4025 OUT PBOOLEAN NeedToCallStartIo
)
4027 PSCSI_REQUEST_BLOCK Srb
;
4028 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4031 ULONG SequenceNumber
;
4034 Irp
= Srb
->OriginalRequest
;
4036 /* Get Lun extension */
4037 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4042 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
&&
4043 DeviceExtension
->MapBuffers
&&
4046 /* MDL is shared if transfer is broken into smaller parts */
4047 Srb
->DataBuffer
= (PCCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
4048 ((PCCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
4050 /* In case of data going in, flush the buffers */
4051 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
4053 KeFlushIoBuffers(Irp
->MdlAddress
,
4060 /* Flush adapter if needed */
4061 if (SrbInfo
->BaseOfMapRegister
)
4063 /* TODO: Implement */
4067 /* Clear the request */
4068 SrbInfo
->Srb
= NULL
;
4070 /* If disconnect is disabled... */
4071 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
4073 /* Acquire the spinlock since we mess with flags */
4074 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4076 /* Set corresponding flag */
4077 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
4079 /* Clear the timer if needed */
4080 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
))
4081 DeviceExtension
->TimerCount
= -1;
4083 /* Spinlock is not needed anymore */
4084 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4086 if (!(DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
) &&
4087 !(DeviceExtension
->Flags
& SCSI_PORT_DEVICE_BUSY
) &&
4088 !(*NeedToCallStartIo
))
4090 /* We're not busy, but we have a request pending */
4091 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4095 /* Scatter/gather */
4096 if (Srb
->SrbFlags
& SRB_FLAGS_SGLIST_FROM_POOL
)
4098 /* TODO: Implement */
4102 /* Acquire spinlock (we're freeing SrbExtension) */
4103 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4105 /* Free it (if needed) */
4106 if (Srb
->SrbExtension
)
4108 if (Srb
->SenseInfoBuffer
!= NULL
&& DeviceExtension
->SupportsAutoSense
)
4110 ASSERT(Srb
->SenseInfoBuffer
== NULL
|| SrbInfo
->SaveSenseRequest
!= NULL
);
4112 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)
4114 /* Copy sense data to the buffer */
4115 RtlCopyMemory(SrbInfo
->SaveSenseRequest
,
4116 Srb
->SenseInfoBuffer
,
4117 Srb
->SenseInfoBufferLength
);
4120 /* And restore the pointer */
4121 Srb
->SenseInfoBuffer
= SrbInfo
->SaveSenseRequest
;
4124 /* Put it into the free srb extensions list */
4125 *((PVOID
*)Srb
->SrbExtension
) = DeviceExtension
->FreeSrbExtensions
;
4126 DeviceExtension
->FreeSrbExtensions
= Srb
->SrbExtension
;
4129 /* Save transfer length in the IRP */
4130 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
4132 SequenceNumber
= SrbInfo
->SequenceNumber
;
4133 SrbInfo
->SequenceNumber
= 0;
4135 /* Decrement the queue count */
4136 LunExtension
->QueueCount
--;
4138 /* Free Srb, if needed*/
4139 if (Srb
->QueueTag
!= SP_UNTAGGED
)
4141 /* Put it into the free list */
4142 SrbInfo
->Requests
.Blink
= NULL
;
4143 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
4144 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
4147 /* SrbInfo is not used anymore */
4150 if (DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
)
4152 /* Clear the flag */
4153 DeviceExtension
->Flags
&= ~SCSI_PORT_REQUEST_PENDING
;
4155 /* Note the caller about StartIo */
4156 *NeedToCallStartIo
= TRUE
;
4159 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
4161 /* Start the packet */
4162 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4164 if (!(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
) &&
4165 LunExtension
->RequestTimeout
== -1)
4167 /* Start the next packet */
4168 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4172 /* Release the spinlock */
4173 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4176 DPRINT("IoCompleting request IRP 0x%p\n", Irp
);
4178 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4180 /* Decrement number of active requests, and analyze the result */
4181 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4184 !DeviceExtension
->MapRegisters
&&
4185 DeviceExtension
->AdapterObject
!= NULL
)
4187 /* Nullify map registers */
4188 DeviceExtension
->MapRegisterBase
= NULL
;
4189 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4192 /* Exit, we're done */
4196 /* Decrement number of active requests, and analyze the result */
4197 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4200 !DeviceExtension
->MapRegisters
&&
4201 DeviceExtension
->AdapterObject
!= NULL
)
4203 /* Result is negative, so this is a slave, free map registers */
4204 DeviceExtension
->MapRegisterBase
= NULL
;
4205 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4208 /* Convert status */
4209 Irp
->IoStatus
.Status
= SpiStatusSrbToNt(Srb
->SrbStatus
);
4211 /* It's not a bypass, it's busy or the queue is full? */
4212 if ((Srb
->ScsiStatus
== SCSISTAT_BUSY
||
4213 Srb
->SrbStatus
== SRB_STATUS_BUSY
||
4214 Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
) &&
4215 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
))
4218 DPRINT("Busy SRB status %x\n", Srb
->SrbStatus
);
4220 /* Requeu, if needed */
4221 if (LunExtension
->Flags
& (LUNEX_FROZEN_QUEUE
| LUNEX_BUSY
))
4223 DPRINT("it's being requeued\n");
4225 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4226 Srb
->ScsiStatus
= 0;
4228 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4229 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
4232 /* It's a big f.ck up if we got here */
4233 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
4234 Srb
->ScsiStatus
= SCSISTAT_BUSY
;
4240 /* Release the spinlock */
4241 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4244 else if (LunExtension
->AttemptCount
++ < 20)
4246 /* LUN is still busy */
4247 Srb
->ScsiStatus
= 0;
4248 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4250 LunExtension
->BusyRequest
= Irp
;
4251 LunExtension
->Flags
|= LUNEX_BUSY
;
4253 /* Release the spinlock */
4254 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4259 /* Freeze the queue*/
4260 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4261 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4263 /* "Unfull" the queue */
4264 LunExtension
->Flags
&= ~LUNEX_FULL_QUEUE
;
4266 /* Release the spinlock */
4267 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4269 /* Return status that the device is not ready */
4270 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
4271 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4277 /* Start the next request, if LUN is idle, and this is sense request */
4278 if (((Srb
->ScsiStatus
!= SCSISTAT_CHECK_CONDITION
) ||
4279 (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) ||
4280 !Srb
->SenseInfoBuffer
|| !Srb
->SenseInfoBufferLength
)
4281 && (Srb
->SrbFlags
& SRB_FLAGS_NO_QUEUE_FREEZE
))
4283 if (LunExtension
->RequestTimeout
== -1)
4284 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4286 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4290 /* Freeze the queue */
4291 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4292 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4294 /* Do we need a request sense? */
4295 if (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4296 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
4297 Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
)
4299 /* If LUN is busy, we have to requeue it in order to allow request sense */
4300 if (LunExtension
->Flags
& LUNEX_BUSY
)
4302 DPRINT("Requeueing busy request to allow request sense\n");
4304 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4305 &LunExtension
->BusyRequest
->Tail
.Overlay
.DeviceQueueEntry
,
4308 /* We should never get here */
4311 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4312 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4317 /* Clear busy flags */
4318 LunExtension
->Flags
&= ~(LUNEX_FULL_QUEUE
| LUNEX_BUSY
);
4321 /* Release the spinlock */
4322 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4324 /* Send RequestSense */
4325 SpiSendRequestSense(DeviceExtension
, Srb
);
4331 /* Release the spinlock */
4332 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4335 /* Complete the request */
4336 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4341 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
4345 PSCSI_REQUEST_BLOCK Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
4346 PSCSI_REQUEST_BLOCK InitialSrb
;
4349 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp
);
4351 if ((Srb
->Function
== SRB_FUNCTION_RESET_BUS
) ||
4352 (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
))
4354 /* Deallocate SRB and IRP and exit */
4358 return STATUS_MORE_PROCESSING_REQUIRED
;
4361 /* Get a pointer to the SRB and IRP which were initially sent */
4362 InitialSrb
= *((PVOID
*)(Srb
+1));
4363 InitialIrp
= InitialSrb
->OriginalRequest
;
4365 if ((SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
) ||
4366 (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_DATA_OVERRUN
))
4368 /* Sense data is OK */
4369 InitialSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
4371 /* Set length to be the same */
4372 InitialSrb
->SenseInfoBufferLength
= (UCHAR
)Srb
->DataTransferLength
;
4375 /* Make sure initial SRB's queue is frozen */
4376 ASSERT(InitialSrb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
);
4378 /* Complete this request */
4379 IoCompleteRequest(InitialIrp
, IO_DISK_INCREMENT
);
4381 /* Deallocate everything (internal) */
4384 if (Irp
->MdlAddress
!= NULL
)
4386 MmUnlockPages(Irp
->MdlAddress
);
4387 IoFreeMdl(Irp
->MdlAddress
);
4388 Irp
->MdlAddress
= NULL
;
4392 return STATUS_MORE_PROCESSING_REQUIRED
;
4397 static BOOLEAN STDCALL
4398 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
4399 IN PVOID ServiceContext
)
4401 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4404 DPRINT("ScsiPortIsr() called!\n");
4406 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
4408 /* If interrupts are disabled - we don't expect any */
4409 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_DISABLE_INTERRUPTS
)
4412 /* Call miniport's HwInterrupt routine */
4413 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
4415 /* If flag of notification is set - queue a DPC */
4416 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4418 IoRequestDpc(DeviceExtension
->DeviceObject
,
4419 DeviceExtension
->CurrentIrp
,
4428 SpiSaveInterruptData(IN PVOID Context
)
4430 PSCSI_PORT_SAVE_INTERRUPT InterruptContext
= Context
;
4431 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4432 PSCSI_REQUEST_BLOCK Srb
;
4433 PSCSI_REQUEST_BLOCK_INFO SrbInfo
, NextSrbInfo
;
4434 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4437 /* Get pointer to the device extension */
4438 DeviceExtension
= InterruptContext
->DeviceExtension
;
4440 /* If we don't have anything pending - return */
4441 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
))
4444 /* Actually save the interrupt data */
4445 *InterruptContext
->InterruptData
= DeviceExtension
->InterruptData
;
4447 /* Clear the data stored in the device extension */
4448 DeviceExtension
->InterruptData
.Flags
&=
4449 (SCSI_PORT_RESET
| SCSI_PORT_RESET_REQUEST
| SCSI_PORT_DISABLE_INTERRUPTS
);
4450 DeviceExtension
->InterruptData
.CompletedAbort
= NULL
;
4451 DeviceExtension
->InterruptData
.ReadyLun
= NULL
;
4452 DeviceExtension
->InterruptData
.CompletedRequests
= NULL
;
4454 /* Loop through the list of completed requests */
4455 SrbInfo
= InterruptContext
->InterruptData
->CompletedRequests
;
4459 /* Make sure we have SRV */
4460 ASSERT(SrbInfo
->Srb
);
4462 /* Get SRB and LunExtension */
4465 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4470 /* We have to check special cases if request is unsuccessfull*/
4471 if (Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
)
4473 /* Check if we need request sense by a few conditions */
4474 if (Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
&&
4475 Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4476 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
))
4478 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
4480 /* It means: we tried to send REQUEST SENSE, but failed */
4482 Srb
->ScsiStatus
= 0;
4483 Srb
->SrbStatus
= SRB_STATUS_REQUEST_SENSE_FAILED
;
4487 /* Set the corresponding flag, so that REQUEST SENSE
4489 LunExtension
->Flags
|= LUNEX_NEED_REQUEST_SENSE
;
4494 /* Check for a full queue */
4495 if (Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
)
4497 /* TODO: Implement when it's encountered */
4502 /* Let's decide if we need to watch timeout or not */
4503 if (Srb
->QueueTag
== SP_UNTAGGED
)
4509 if (LunExtension
->SrbInfo
.Requests
.Flink
== &SrbInfo
->Requests
)
4514 /* Remove it from the queue */
4515 RemoveEntryList(&SrbInfo
->Requests
);
4520 /* We have to maintain timeout counter */
4521 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
))
4523 LunExtension
->RequestTimeout
= -1;
4527 NextSrbInfo
= CONTAINING_RECORD(LunExtension
->SrbInfo
.Requests
.Flink
,
4528 SCSI_REQUEST_BLOCK_INFO
,
4531 Srb
= NextSrbInfo
->Srb
;
4533 /* Update timeout counter */
4534 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
4538 SrbInfo
= SrbInfo
->CompletedRequests
;
4546 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4547 IN PSCSI_PORT_LUN_EXTENSION LunExtension
)
4549 PIO_STACK_LOCATION IrpStack
;
4551 PKDEVICE_QUEUE_ENTRY Entry
;
4552 PSCSI_REQUEST_BLOCK Srb
;
4555 /* If LUN is not active or queue is more than maximum allowed */
4556 if (LunExtension
->QueueCount
>= LunExtension
->MaxQueueCount
||
4557 !(LunExtension
->Flags
& SCSI_PORT_LU_ACTIVE
))
4559 /* Release the spinlock and exit */
4560 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4564 /* Check if we can get a next request */
4565 if (LunExtension
->Flags
&
4566 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_BUSY
|
4567 LUNEX_FULL_QUEUE
| LUNEX_FROZEN_QUEUE
| LUNEX_REQUEST_PENDING
))
4569 /* Pending requests can only be started if the queue is empty */
4570 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
) &&
4571 !(LunExtension
->Flags
&
4572 (LUNEX_BUSY
| LUNEX_FROZEN_QUEUE
| LUNEX_FULL_QUEUE
| LUNEX_NEED_REQUEST_SENSE
)))
4574 /* Make sure we have SRB */
4575 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
4577 /* Clear active and pending flags */
4578 LunExtension
->Flags
&= ~(LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
);
4580 /* Get next Irp, and clear pending requests list */
4581 NextIrp
= LunExtension
->PendingRequest
;
4582 LunExtension
->PendingRequest
= NULL
;
4584 /* Set attempt counter to zero */
4585 LunExtension
->AttemptCount
= 0;
4587 /* Release the spinlock */
4588 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4590 /* Start the next pending request */
4591 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4597 /* Release the spinlock, without clearing any flags and exit */
4598 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4604 /* Reset active flag */
4605 LunExtension
->Flags
&= ~SCSI_PORT_LU_ACTIVE
;
4607 /* Set attempt counter to zero */
4608 LunExtension
->AttemptCount
= 0;
4610 /* Remove packet from the device queue */
4611 Entry
= KeRemoveByKeyDeviceQueue(&LunExtension
->DeviceQueue
, LunExtension
->SortKey
);
4615 /* Get pointer to the next irp */
4616 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
4618 /* Get point to the SRB */
4619 IrpStack
= IoGetCurrentIrpStackLocation(NextIrp
);
4620 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
4623 LunExtension
->SortKey
= Srb
->QueueSortKey
;
4624 LunExtension
->SortKey
++;
4626 /* Release the spinlock */
4627 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4629 /* Start the next pending request */
4630 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4634 /* Release the spinlock */
4635 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4641 // ScsiPortDpcForIsr
4648 // IN PDEVICE_OBJECT DpcDeviceObject
4650 // IN PVOID DpcContext
4653 ScsiPortDpcForIsr(IN PKDPC Dpc
,
4654 IN PDEVICE_OBJECT DpcDeviceObject
,
4656 IN PVOID DpcContext
)
4658 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DpcDeviceObject
->DeviceExtension
;
4659 SCSI_PORT_INTERRUPT_DATA InterruptData
;
4660 SCSI_PORT_SAVE_INTERRUPT Context
;
4661 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4662 BOOLEAN NeedToStartIo
;
4663 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
4665 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4666 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
4668 /* We need to acquire spinlock */
4669 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4671 RtlZeroMemory(&InterruptData
, sizeof(SCSI_PORT_INTERRUPT_DATA
));
4675 /* Interrupt structure must be snapshotted, and only then analyzed */
4676 Context
.InterruptData
= &InterruptData
;
4677 Context
.DeviceExtension
= DeviceExtension
;
4679 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4680 SpiSaveInterruptData
,
4683 /* Nothing - just return (don't forget to release the spinlock */
4684 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4685 DPRINT("ScsiPortDpcForIsr() done\n");
4689 /* If flush of adapters is needed - do it */
4690 if (InterruptData
.Flags
& SCSI_PORT_FLUSH_ADAPTERS
)
4692 /* TODO: Implement */
4696 /* Check for IoMapTransfer */
4697 if (InterruptData
.Flags
& SCSI_PORT_MAP_TRANSFER
)
4699 /* TODO: Implement */
4703 /* Check if timer is needed */
4704 if (InterruptData
.Flags
& SCIS_PORT_TIMER_NEEDED
)
4706 /* TODO: Implement */
4710 /* If it's ready for the next request */
4711 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4713 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4714 if ((DeviceExtension
->Flags
&
4715 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
)) ==
4716 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
))
4718 /* Clear busy flag set by ScsiPortStartPacket() */
4719 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4721 if (!(InterruptData
.Flags
& SCSI_PORT_RESET
))
4723 /* Ready for next, and no reset is happening */
4724 DeviceExtension
->TimerCount
= -1;
4729 /* Not busy, but not ready for the next request */
4730 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4731 InterruptData
.Flags
&= ~SCSI_PORT_NEXT_REQUEST_READY
;
4736 if (InterruptData
.Flags
& SCSI_PORT_RESET_REPORTED
)
4738 /* Hold for a bit */
4739 DeviceExtension
->TimerCount
= 4;
4742 /* Any ready LUN? */
4743 if (InterruptData
.ReadyLun
!= NULL
)
4746 /* Process all LUNs from the list*/
4749 /* Remove it from the list first (as processed) */
4750 LunExtension
= InterruptData
.ReadyLun
;
4751 InterruptData
.ReadyLun
= LunExtension
->ReadyLun
;
4752 LunExtension
->ReadyLun
= NULL
;
4754 /* Get next request for this LUN */
4755 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4757 /* Still ready requests exist?
4758 If yes - get spinlock, if no - stop here */
4759 if (InterruptData
.ReadyLun
!= NULL
)
4760 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4767 /* Release the spinlock */
4768 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4771 /* If we ready for next packet, start it */
4772 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4773 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4775 NeedToStartIo
= FALSE
;
4777 /* Loop the completed request list */
4778 while (InterruptData
.CompletedRequests
)
4780 /* Remove the request */
4781 SrbInfo
= InterruptData
.CompletedRequests
;
4782 InterruptData
.CompletedRequests
= SrbInfo
->CompletedRequests
;
4783 SrbInfo
->CompletedRequests
= NULL
;
4786 SpiProcessCompletedRequest(DeviceExtension
,
4791 /* Loop abort request list */
4792 while (InterruptData
.CompletedAbort
)
4794 LunExtension
= InterruptData
.CompletedAbort
;
4796 /* Remove the request */
4797 InterruptData
.CompletedAbort
= LunExtension
->CompletedAbortRequests
;
4799 /* Get spinlock since we're going to change flags */
4800 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4802 /* TODO: Put SrbExtension to the list of free extensions */
4806 /* If we need - call StartIo routine */
4809 /* Make sure CurrentIrp is not null! */
4810 ASSERT(DpcDeviceObject
->CurrentIrp
!= NULL
);
4811 ScsiPortStartIo(DpcDeviceObject
, DpcDeviceObject
->CurrentIrp
);
4814 /* Everything has been done, check */
4815 if (InterruptData
.Flags
& SCSI_PORT_ENABLE_INT_REQUEST
)
4817 /* Synchronize using spinlock */
4818 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4820 /* Request an interrupt */
4821 DeviceExtension
->HwInterrupt(DeviceExtension
->MiniPortDeviceExtension
);
4823 ASSERT(DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
);
4825 /* Should interrupts be enabled again? */
4826 if (DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
)
4828 /* Clear this flag */
4829 DeviceExtension
->Flags
&= ~SCSI_PORT_DISABLE_INT_REQUESET
;
4831 /* Call a special routine to do this */
4834 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4835 SpiEnableInterrupts
,
4840 /* If we need a notification again - loop */
4841 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4844 /* Release the spinlock */
4845 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4848 DPRINT("ScsiPortDpcForIsr() done\n");
4853 SpiProcessTimeout(PVOID ServiceContext
)
4855 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
4856 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
4859 DPRINT("SpiProcessTimeout() entered\n");
4861 DeviceExtension
->TimerCount
= -1;
4863 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
4865 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET
;
4867 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET_REQUEST
)
4869 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET_REQUEST
;
4870 ScsiPortStartPacket(ServiceContext
);
4877 DPRINT("Resetting the bus\n");
4879 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
4881 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
, Bus
);
4883 /* Reset flags and set reset timeout to 4 seconds */
4884 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
4885 DeviceExtension
->TimerCount
= 4;
4888 /* If miniport requested - request a dpc for it */
4889 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4890 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
4899 SpiResetBus(PVOID ServiceContext
)
4901 PRESETBUS_PARAMS ResetParams
= (PRESETBUS_PARAMS
)ServiceContext
;
4902 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4904 /* Perform the bus reset */
4905 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ResetParams
->DeviceExtension
;
4906 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
,
4907 ResetParams
->PathId
);
4909 /* Set flags and start the timer */
4910 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
4911 DeviceExtension
->TimerCount
= 4;
4913 /* If miniport requested - give him a DPC */
4914 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4915 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
4922 // This function handles timeouts and other time delayed processing
4927 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
4928 // IN PVOID Context the Controller extension for the
4929 // controller the device is on
4932 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
4935 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4936 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4940 DPRINT("ScsiPortIoTimer()\n");
4942 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
4944 /* Protect with the spinlock */
4945 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4947 /* Check timeouts */
4948 if (DeviceExtension
->TimerCount
> 0)
4950 /* Decrease the timeout counter */
4951 DeviceExtension
->TimerCount
--;
4953 if (DeviceExtension
->TimerCount
== 0)
4955 /* Timeout, process it */
4956 if (KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4958 DeviceExtension
->DeviceObject
))
4960 DPRINT("Error happened during processing timeout, but nothing critical\n");
4964 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4966 /* We should exit now, since timeout is processed */
4970 /* Per-Lun scanning of timeouts is needed... */
4971 for (Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
4973 LunExtension
= DeviceExtension
->LunExtensionList
[Lun
];
4975 while (LunExtension
)
4977 if (LunExtension
->Flags
& LUNEX_BUSY
)
4979 if (!(LunExtension
->Flags
&
4980 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_FROZEN_QUEUE
)))
4982 DPRINT("Retrying busy request\n");
4984 /* Clear flags, and retry busy request */
4985 LunExtension
->Flags
&= ~(LUNEX_BUSY
| LUNEX_FULL_QUEUE
);
4986 Irp
= LunExtension
->BusyRequest
;
4988 /* Clearing busy request */
4989 LunExtension
->BusyRequest
= NULL
;
4991 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4993 IoStartPacket(DeviceObject
, Irp
, (PULONG
)NULL
, NULL
);
4995 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4998 else if (LunExtension
->RequestTimeout
== 0)
5000 RESETBUS_PARAMS ResetParams
;
5002 LunExtension
->RequestTimeout
= -1;
5004 DPRINT("Request timed out, resetting bus\n");
5006 /* Pass params to the bus reset routine */
5007 ResetParams
.PathId
= LunExtension
->PathId
;
5008 ResetParams
.DeviceExtension
= DeviceExtension
;
5010 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
5014 DPRINT1("Reset failed\n");
5017 else if (LunExtension
->RequestTimeout
> 0)
5019 /* Decrement the timeout counter */
5020 LunExtension
->RequestTimeout
--;
5023 LunExtension
= LunExtension
->Next
;
5027 /* Release the spinlock */
5028 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5031 /**********************************************************************
5036 * Builds the registry device map of all device which are attached
5037 * to the given SCSI HBA port. The device map is located at:
5038 * \Registry\Machine\DeviceMap\Scsi
5048 * Name of registry driver service key.
5055 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5056 PUNICODE_STRING RegistryPath
)
5058 PSCSI_PORT_LUN_EXTENSION LunExtension
;
5059 OBJECT_ATTRIBUTES ObjectAttributes
;
5060 UNICODE_STRING KeyName
;
5061 UNICODE_STRING ValueName
;
5062 WCHAR NameBuffer
[64];
5065 HANDLE ScsiPortKey
= NULL
;
5066 HANDLE ScsiBusKey
= NULL
;
5067 HANDLE ScsiInitiatorKey
= NULL
;
5068 HANDLE ScsiTargetKey
= NULL
;
5069 HANDLE ScsiLunKey
= NULL
;
5072 ULONG CurrentTarget
;
5079 DPRINT("SpiBuildDeviceMap() called\n");
5081 if (DeviceExtension
== NULL
|| RegistryPath
== NULL
)
5083 DPRINT1("Invalid parameter\n");
5084 return(STATUS_INVALID_PARAMETER
);
5087 /* Open or create the 'Scsi' subkey */
5088 RtlInitUnicodeString(&KeyName
,
5089 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
5090 InitializeObjectAttributes(&ObjectAttributes
,
5092 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
5095 Status
= ZwCreateKey(&ScsiKey
,
5100 REG_OPTION_VOLATILE
,
5102 if (!NT_SUCCESS(Status
))
5104 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5108 /* Create new 'Scsi Port X' subkey */
5109 DPRINT("Scsi Port %lu\n",
5110 DeviceExtension
->PortNumber
);
5112 swprintf(NameBuffer
,
5114 DeviceExtension
->PortNumber
);
5115 RtlInitUnicodeString(&KeyName
,
5117 InitializeObjectAttributes(&ObjectAttributes
,
5122 Status
= ZwCreateKey(&ScsiPortKey
,
5127 REG_OPTION_VOLATILE
,
5130 if (!NT_SUCCESS(Status
))
5132 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5137 * Create port-specific values
5140 /* Set 'DMA Enabled' (REG_DWORD) value */
5141 UlongData
= (ULONG
)!DeviceExtension
->PortCapabilities
.AdapterUsesPio
;
5142 DPRINT(" DMA Enabled = %s\n", (UlongData
) ? "TRUE" : "FALSE");
5143 RtlInitUnicodeString(&ValueName
,
5145 Status
= ZwSetValueKey(ScsiPortKey
,
5151 if (!NT_SUCCESS(Status
))
5153 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status
);
5154 ZwClose(ScsiPortKey
);
5158 /* Set 'Driver' (REG_SZ) value */
5159 DriverName
= wcsrchr(RegistryPath
->Buffer
, L
'\\') + 1;
5160 RtlInitUnicodeString(&ValueName
,
5162 Status
= ZwSetValueKey(ScsiPortKey
,
5167 (wcslen(DriverName
) + 1) * sizeof(WCHAR
));
5168 if (!NT_SUCCESS(Status
))
5170 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status
);
5171 ZwClose(ScsiPortKey
);
5175 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
5176 UlongData
= (ULONG
)DeviceExtension
->PortConfig
->BusInterruptLevel
;
5177 DPRINT(" Interrupt = %lu\n", UlongData
);
5178 RtlInitUnicodeString(&ValueName
,
5180 Status
= ZwSetValueKey(ScsiPortKey
,
5186 if (!NT_SUCCESS(Status
))
5188 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status
);
5189 ZwClose(ScsiPortKey
);
5193 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
5194 UlongData
= ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension
->PortConfig
->AccessRanges
)[0].RangeStart
);
5195 DPRINT(" IOAddress = %lx\n", UlongData
);
5196 RtlInitUnicodeString(&ValueName
,
5198 Status
= ZwSetValueKey(ScsiPortKey
,
5204 if (!NT_SUCCESS(Status
))
5206 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status
);
5207 ZwClose(ScsiPortKey
);
5211 /* Enumerate buses */
5212 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
->NumberOfBuses
; BusNumber
++)
5214 /* Create 'Scsi Bus X' key */
5215 DPRINT(" Scsi Bus %lu\n", BusNumber
);
5216 swprintf(NameBuffer
,
5219 RtlInitUnicodeString(&KeyName
,
5221 InitializeObjectAttributes(&ObjectAttributes
,
5226 Status
= ZwCreateKey(&ScsiBusKey
,
5231 REG_OPTION_VOLATILE
,
5233 if (!NT_SUCCESS(Status
))
5235 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5239 /* Create 'Initiator Id X' key */
5240 DPRINT(" Initiator Id %u\n",
5241 DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5242 swprintf(NameBuffer
,
5244 (unsigned int)(UCHAR
)DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5245 RtlInitUnicodeString(&KeyName
,
5247 InitializeObjectAttributes(&ObjectAttributes
,
5252 Status
= ZwCreateKey(&ScsiInitiatorKey
,
5257 REG_OPTION_VOLATILE
,
5259 if (!NT_SUCCESS(Status
))
5261 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5265 /* FIXME: Are there any initiator values (??) */
5267 ZwClose(ScsiInitiatorKey
);
5268 ScsiInitiatorKey
= NULL
;
5271 /* Enumerate targets */
5272 CurrentTarget
= (ULONG
)-1;
5273 ScsiTargetKey
= NULL
;
5274 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
5276 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
5278 LunExtension
= SpiGetLunExtension(DeviceExtension
,
5282 if (LunExtension
!= NULL
)
5284 if (Target
!= CurrentTarget
)
5286 /* Close old target key */
5287 if (ScsiTargetKey
!= NULL
)
5289 ZwClose(ScsiTargetKey
);
5290 ScsiTargetKey
= NULL
;
5293 /* Create 'Target Id X' key */
5294 DPRINT(" Target Id %lu\n", Target
);
5295 swprintf(NameBuffer
,
5298 RtlInitUnicodeString(&KeyName
,
5300 InitializeObjectAttributes(&ObjectAttributes
,
5305 Status
= ZwCreateKey(&ScsiTargetKey
,
5310 REG_OPTION_VOLATILE
,
5312 if (!NT_SUCCESS(Status
))
5314 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5318 CurrentTarget
= Target
;
5321 /* Create 'Logical Unit Id X' key */
5322 DPRINT(" Logical Unit Id %lu\n", Lun
);
5323 swprintf(NameBuffer
,
5324 L
"Logical Unit Id %lu",
5326 RtlInitUnicodeString(&KeyName
,
5328 InitializeObjectAttributes(&ObjectAttributes
,
5333 Status
= ZwCreateKey(&ScsiLunKey
,
5338 REG_OPTION_VOLATILE
,
5340 if (!NT_SUCCESS(Status
))
5342 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5346 /* Set 'Identifier' (REG_SZ) value */
5347 swprintf(NameBuffer
,
5349 LunExtension
->InquiryData
.VendorId
,
5350 LunExtension
->InquiryData
.ProductId
,
5351 LunExtension
->InquiryData
.ProductRevisionLevel
);
5352 DPRINT(" Identifier = '%S'\n", NameBuffer
);
5353 RtlInitUnicodeString(&ValueName
,
5355 Status
= ZwSetValueKey(ScsiLunKey
,
5360 (wcslen(NameBuffer
) + 1) * sizeof(WCHAR
));
5361 if (!NT_SUCCESS(Status
))
5363 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status
);
5367 /* Set 'Type' (REG_SZ) value */
5368 switch (LunExtension
->InquiryData
.DeviceType
)
5371 TypeName
= L
"DiskPeripheral";
5374 TypeName
= L
"TapePeripheral";
5377 TypeName
= L
"PrinterPeripheral";
5380 TypeName
= L
"WormPeripheral";
5383 TypeName
= L
"CdRomPeripheral";
5386 TypeName
= L
"ScannerPeripheral";
5389 TypeName
= L
"OpticalDiskPeripheral";
5392 TypeName
= L
"MediumChangerPeripheral";
5395 TypeName
= L
"CommunicationPeripheral";
5398 TypeName
= L
"OtherPeripheral";
5401 DPRINT(" Type = '%S'\n", TypeName
);
5402 RtlInitUnicodeString(&ValueName
,
5404 Status
= ZwSetValueKey(ScsiLunKey
,
5409 (wcslen(TypeName
) + 1) * sizeof(WCHAR
));
5410 if (!NT_SUCCESS(Status
))
5412 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status
);
5416 ZwClose(ScsiLunKey
);
5421 /* Close old target key */
5422 if (ScsiTargetKey
!= NULL
)
5424 ZwClose(ScsiTargetKey
);
5425 ScsiTargetKey
= NULL
;
5429 ZwClose(ScsiBusKey
);
5434 if (ScsiLunKey
!= NULL
)
5435 ZwClose (ScsiLunKey
);
5437 if (ScsiInitiatorKey
!= NULL
)
5438 ZwClose (ScsiInitiatorKey
);
5440 if (ScsiTargetKey
!= NULL
)
5441 ZwClose (ScsiTargetKey
);
5443 if (ScsiBusKey
!= NULL
)
5444 ZwClose (ScsiBusKey
);
5446 if (ScsiPortKey
!= NULL
)
5447 ZwClose (ScsiPortKey
);
5449 DPRINT("SpiBuildDeviceMap() done\n");
5456 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
5457 IN PVOID DeviceObject
,
5458 IN PVOID SystemArgument1
,
5459 IN PVOID SystemArgument2
)
5461 DPRINT1("Miniport timer DPC\n");
5465 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5466 PHW_INITIALIZATION_DATA HwInitData
,
5467 PCONFIGURATION_INFO InternalConfigInfo
,
5468 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5471 UNICODE_STRING UnicodeString
;
5472 OBJECT_ATTRIBUTES ObjectAttributes
;
5473 PCONFIGURATION_INFORMATION DdkConfigInformation
;
5474 HANDLE RootKey
, Key
;
5476 WCHAR DeviceBuffer
[16];
5477 WCHAR StrBuffer
[512];
5481 /* Zero out the struct if told so */
5484 /* First zero the portconfig */
5485 RtlZeroMemory(ConfigInfo
, sizeof(PORT_CONFIGURATION_INFORMATION
));
5487 /* Then access ranges */
5488 RtlZeroMemory(InternalConfigInfo
->AccessRanges
,
5489 HwInitData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
5491 /* Initialize the struct */
5492 ConfigInfo
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
5493 ConfigInfo
->AdapterInterfaceType
= HwInitData
->AdapterInterfaceType
;
5494 ConfigInfo
->InterruptMode
= Latched
;
5495 ConfigInfo
->DmaChannel
= SP_UNINITIALIZED_VALUE
;
5496 ConfigInfo
->DmaPort
= SP_UNINITIALIZED_VALUE
;
5497 ConfigInfo
->MaximumTransferLength
= SP_UNINITIALIZED_VALUE
;
5498 ConfigInfo
->NumberOfAccessRanges
= HwInitData
->NumberOfAccessRanges
;
5499 ConfigInfo
->MaximumNumberOfTargets
= 8;
5501 /* Store parameters */
5502 ConfigInfo
->NeedPhysicalAddresses
= HwInitData
->NeedPhysicalAddresses
;
5503 ConfigInfo
->MapBuffers
= HwInitData
->MapBuffers
;
5504 ConfigInfo
->AutoRequestSense
= HwInitData
->AutoRequestSense
;
5505 ConfigInfo
->ReceiveEvent
= HwInitData
->ReceiveEvent
;
5506 ConfigInfo
->TaggedQueuing
= HwInitData
->TaggedQueuing
;
5507 ConfigInfo
->MultipleRequestPerLu
= HwInitData
->MultipleRequestPerLu
;
5509 /* Get the disk usage */
5510 DdkConfigInformation
= IoGetConfigurationInformation();
5511 ConfigInfo
->AtdiskPrimaryClaimed
= DdkConfigInformation
->AtDiskPrimaryAddressClaimed
;
5512 ConfigInfo
->AtdiskSecondaryClaimed
= DdkConfigInformation
->AtDiskSecondaryAddressClaimed
;
5514 /* Initiator bus id is not set */
5515 for (Bus
= 0; Bus
< 8; Bus
++)
5516 ConfigInfo
->InitiatorBusId
[Bus
] = (CCHAR
)SP_UNINITIALIZED_VALUE
;
5519 ConfigInfo
->NumberOfPhysicalBreaks
= 17;
5521 /* Clear this information */
5522 InternalConfigInfo
->DisableTaggedQueueing
= FALSE
;
5523 InternalConfigInfo
->DisableMultipleLun
= FALSE
;
5525 /* Store Bus Number */
5526 ConfigInfo
->SystemIoBusNumber
= InternalConfigInfo
->BusNumber
;
5530 if (ConfigInfo
->AdapterInterfaceType
== Internal
)
5532 /* Open registry key for HW database */
5533 InitializeObjectAttributes(&ObjectAttributes
,
5534 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
5535 OBJ_CASE_INSENSITIVE
,
5539 Status
= ZwOpenKey(&RootKey
,
5543 if (NT_SUCCESS(Status
))
5545 /* Create name for it */
5546 swprintf(StrBuffer
, L
"ScsiAdapter\\%lu",
5547 InternalConfigInfo
->AdapterNumber
);
5549 RtlInitUnicodeString(&UnicodeString
, StrBuffer
);
5551 /* Open device key */
5552 InitializeObjectAttributes(&ObjectAttributes
,
5554 OBJ_CASE_INSENSITIVE
,
5558 Status
= ZwOpenKey(&Key
,
5564 if (NT_SUCCESS(Status
))
5566 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5568 DPRINT("Hardware info found at %S\n", StrBuffer
);
5571 SpiParseDeviceInfo(DeviceExtension
,
5577 InternalConfigInfo
->BusNumber
= 0;
5581 /* Try the next adapter */
5582 InternalConfigInfo
->AdapterNumber
++;
5588 /* Info was not found, exit */
5589 return STATUS_DEVICE_DOES_NOT_EXIST
;
5595 /* Look at device params */
5597 if (InternalConfigInfo
->Parameter
)
5599 ExFreePool(InternalConfigInfo
->Parameter
);
5600 InternalConfigInfo
->Parameter
= NULL
;
5603 if (InternalConfigInfo
->ServiceKey
!= NULL
)
5605 swprintf(DeviceBuffer
, L
"Device%lu", InternalConfigInfo
->AdapterNumber
);
5606 RtlInitUnicodeString(&UnicodeString
, DeviceBuffer
);
5608 /* Open the service key */
5609 InitializeObjectAttributes(&ObjectAttributes
,
5611 OBJ_CASE_INSENSITIVE
,
5612 InternalConfigInfo
->ServiceKey
,
5615 Status
= ZwOpenKey(&Key
,
5620 /* Parse device key */
5621 if (InternalConfigInfo
->DeviceKey
!= NULL
)
5623 SpiParseDeviceInfo(DeviceExtension
,
5624 InternalConfigInfo
->DeviceKey
,
5630 /* Then parse hw info */
5633 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5635 SpiParseDeviceInfo(DeviceExtension
,
5646 /* Adapter not found, go try the next one */
5647 InternalConfigInfo
->AdapterNumber
++;
5656 /* Update the last adapter number */
5657 InternalConfigInfo
->LastAdapterNumber
= InternalConfigInfo
->AdapterNumber
;
5659 /* Do we have this kind of bus at all? */
5661 Status
= IoQueryDeviceDescription(&HwInitData
->AdapterInterfaceType
,
5662 &InternalConfigInfo
->BusNumber
,
5667 SpQueryDeviceCallout
,
5670 /* This bus was not found */
5673 INTERFACE_TYPE InterfaceType
= Eisa
;
5675 /* Check for EISA */
5676 if (HwInitData
->AdapterInterfaceType
== Isa
)
5678 Status
= IoQueryDeviceDescription(&InterfaceType
,
5679 &InternalConfigInfo
->BusNumber
,
5684 SpQueryDeviceCallout
,
5687 /* Return respectively */
5689 return STATUS_SUCCESS
;
5691 return STATUS_DEVICE_DOES_NOT_EXIST
;
5695 return STATUS_DEVICE_DOES_NOT_EXIST
;
5700 return STATUS_SUCCESS
;
5705 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5707 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5708 IN PCONFIGURATION_INFO InternalConfigInfo
,
5711 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
5712 PCM_FULL_RESOURCE_DESCRIPTOR FullResource
;
5713 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
5714 PCM_SCSI_DEVICE_DATA ScsiDeviceData
;
5715 ULONG Length
, Count
;
5716 ULONG Index
= 0, RangeCount
= 0;
5717 UNICODE_STRING UnicodeString
;
5718 ANSI_STRING AnsiString
;
5719 NTSTATUS Status
= STATUS_SUCCESS
;
5722 KeyValueInformation
= (PKEY_VALUE_FULL_INFORMATION
) Buffer
;
5724 /* Loop through all values in the device node */
5727 Status
= ZwEnumerateValueKey(Key
,
5729 KeyValueFullInformation
,
5734 if (!NT_SUCCESS(Status
))
5739 /* Length for DWORD is ok? */
5740 if (KeyValueInformation
->Type
== REG_DWORD
&&
5741 KeyValueInformation
->DataLength
!= sizeof(ULONG
))
5746 /* Get MaximumLogicalUnit */
5747 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumLogicalUnit",
5748 KeyValueInformation
->NameLength
/2) == 0)
5751 if (KeyValueInformation
->Type
!= REG_DWORD
)
5753 DPRINT("Bad data type for MaximumLogicalUnit\n");
5757 DeviceExtension
->MaxLunCount
= *((PUCHAR
)
5758 (Buffer
+ KeyValueInformation
->DataOffset
));
5760 /* Check / reset if needed */
5761 if (DeviceExtension
->MaxLunCount
> SCSI_MAXIMUM_LOGICAL_UNITS
)
5762 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
5764 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension
->MaxLunCount
);
5767 /* Get InitiatorTargetId */
5768 if (_wcsnicmp(KeyValueInformation
->Name
, L
"InitiatorTargetId",
5769 KeyValueInformation
->NameLength
/ 2) == 0)
5772 if (KeyValueInformation
->Type
!= REG_DWORD
)
5774 DPRINT("Bad data type for InitiatorTargetId\n");
5778 ConfigInfo
->InitiatorBusId
[0] = *((PUCHAR
)
5779 (Buffer
+ KeyValueInformation
->DataOffset
));
5781 /* Check / reset if needed */
5782 if (ConfigInfo
->InitiatorBusId
[0] > ConfigInfo
->MaximumNumberOfTargets
- 1)
5783 ConfigInfo
->InitiatorBusId
[0] = (CCHAR
)-1;
5785 DPRINT("InitiatorTargetId = %d\n", ConfigInfo
->InitiatorBusId
[0]);
5789 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ScsiDebug",
5790 KeyValueInformation
->NameLength
/2) == 0)
5792 DPRINT("ScsiDebug key not supported\n");
5795 /* Check for a breakpoint */
5796 if (_wcsnicmp(KeyValueInformation
->Name
, L
"BreakPointOnEntry",
5797 KeyValueInformation
->NameLength
/2) == 0)
5799 DPRINT1("Breakpoint on entry requested!\n");
5803 /* Get DisableSynchronousTransfers */
5804 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableSynchronousTransfers",
5805 KeyValueInformation
->NameLength
/2) == 0)
5807 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5808 DPRINT("Synch transfers disabled\n");
5811 /* Get DisableDisconnects */
5812 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableDisconnects",
5813 KeyValueInformation
->NameLength
/2) == 0)
5815 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
5816 DPRINT("Disconnects disabled\n");
5819 /* Get DisableTaggedQueuing */
5820 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableTaggedQueuing",
5821 KeyValueInformation
->NameLength
/2) == 0)
5823 InternalConfigInfo
->DisableTaggedQueueing
= TRUE
;
5824 DPRINT("Tagged queueing disabled\n");
5827 /* Get DisableMultipleRequests */
5828 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableMultipleRequests",
5829 KeyValueInformation
->NameLength
/2) == 0)
5831 InternalConfigInfo
->DisableMultipleLun
= TRUE
;
5832 DPRINT("Multiple requests disabled\n");
5835 /* Get DriverParameters */
5836 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DriverParameters",
5837 KeyValueInformation
->NameLength
/2) == 0)
5839 /* Skip if nothing */
5840 if (KeyValueInformation
->DataLength
== 0)
5843 /* If there was something previously allocated - free it */
5844 if (InternalConfigInfo
->Parameter
!= NULL
)
5845 ExFreePool(InternalConfigInfo
->Parameter
);
5848 InternalConfigInfo
->Parameter
= ExAllocatePoolWithTag(NonPagedPool
,
5849 KeyValueInformation
->DataLength
, TAG_SCSIPORT
);
5851 if (InternalConfigInfo
->Parameter
!= NULL
)
5853 if (KeyValueInformation
->Type
!= REG_SZ
)
5857 InternalConfigInfo
->Parameter
,
5858 (PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
,
5859 KeyValueInformation
->DataLength
);
5863 /* If it's a unicode string, convert it to ansi */
5864 UnicodeString
.Length
= (USHORT
)KeyValueInformation
->DataLength
;
5865 UnicodeString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
5866 UnicodeString
.Buffer
=
5867 (PWSTR
)((PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
5869 AnsiString
.Length
= 0;
5870 AnsiString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
5871 AnsiString
.Buffer
= (PCHAR
)InternalConfigInfo
->Parameter
;
5873 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
5877 /* In case of error, free the allocated space */
5878 if (!NT_SUCCESS(Status
))
5880 ExFreePool(InternalConfigInfo
->Parameter
);
5881 InternalConfigInfo
->Parameter
= NULL
;
5887 DPRINT("Found driver parameter\n");
5890 /* Get MaximumSGList */
5891 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumSGList",
5892 KeyValueInformation
->NameLength
/2) == 0)
5894 if (KeyValueInformation
->Type
!= REG_DWORD
)
5896 DPRINT("Bad data type for MaximumSGList\n");
5900 ConfigInfo
->NumberOfPhysicalBreaks
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
5903 if (ConfigInfo
->NumberOfPhysicalBreaks
> SCSI_MAXIMUM_PHYSICAL_BREAKS
)
5905 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MAXIMUM_PHYSICAL_BREAKS
;
5907 else if (ConfigInfo
->NumberOfPhysicalBreaks
< SCSI_MINIMUM_PHYSICAL_BREAKS
)
5909 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MINIMUM_PHYSICAL_BREAKS
;
5912 DPRINT("MaximumSGList = %d\n", ConfigInfo
->NumberOfPhysicalBreaks
);
5915 /* Get NumberOfRequests */
5916 if (_wcsnicmp(KeyValueInformation
->Name
, L
"NumberOfRequests",
5917 KeyValueInformation
->NameLength
/2) == 0)
5919 if (KeyValueInformation
->Type
!= REG_DWORD
)
5921 DPRINT("NumberOfRequests has wrong data type\n");
5925 DeviceExtension
->RequestsNumber
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
5928 if (DeviceExtension
->RequestsNumber
< 16)
5930 DeviceExtension
->RequestsNumber
= 16;
5932 else if (DeviceExtension
->RequestsNumber
> 512)
5934 DeviceExtension
->RequestsNumber
= 512;
5937 DPRINT("Number Of Requests = %d\n", DeviceExtension
->RequestsNumber
);
5940 /* Get resource list */
5941 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ResourceList",
5942 KeyValueInformation
->NameLength
/2) == 0 ||
5943 _wcsnicmp(KeyValueInformation
->Name
, L
"Configuration Data",
5944 KeyValueInformation
->NameLength
/2) == 0 )
5946 if (KeyValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
||
5947 KeyValueInformation
->DataLength
< sizeof(REG_FULL_RESOURCE_DESCRIPTOR
))
5949 DPRINT("Bad data type for ResourceList\n");
5954 DPRINT("Found ResourceList\n");
5957 FullResource
= (PCM_FULL_RESOURCE_DESCRIPTOR
)(Buffer
+ KeyValueInformation
->DataOffset
);
5959 /* Copy some info from it */
5960 InternalConfigInfo
->BusNumber
= FullResource
->BusNumber
;
5961 ConfigInfo
->SystemIoBusNumber
= FullResource
->BusNumber
;
5963 /* Loop through it */
5964 for (Count
= 0; Count
< FullResource
->PartialResourceList
.Count
; Count
++)
5966 /* Get partial descriptor */
5968 &FullResource
->PartialResourceList
.PartialDescriptors
[Count
];
5970 /* Check datalength */
5971 if ((ULONG
)((PCHAR
)(PartialDescriptor
+ 1) -
5972 (PCHAR
)FullResource
) > KeyValueInformation
->DataLength
)
5974 DPRINT("Resource data is of incorrect size\n");
5978 switch (PartialDescriptor
->Type
)
5980 case CmResourceTypePort
:
5981 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
5983 DPRINT("Too many access ranges\n");
5987 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= FALSE
;
5988 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Port
.Start
;
5989 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Port
.Length
;
5994 case CmResourceTypeMemory
:
5995 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
5997 DPRINT("Too many access ranges\n");
6001 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= TRUE
;
6002 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Memory
.Start
;
6003 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Memory
.Length
;
6008 case CmResourceTypeInterrupt
:
6009 ConfigInfo
->BusInterruptLevel
=
6010 PartialDescriptor
->u
.Interrupt
.Level
;
6012 ConfigInfo
->BusInterruptVector
=
6013 PartialDescriptor
->u
.Interrupt
.Vector
;
6016 case CmResourceTypeDma
:
6017 ConfigInfo
->DmaChannel
= PartialDescriptor
->u
.Dma
.Channel
;
6018 ConfigInfo
->DmaPort
= PartialDescriptor
->u
.Dma
.Port
;
6021 case CmResourceTypeDeviceSpecific
:
6022 if (PartialDescriptor
->u
.DeviceSpecificData
.DataSize
<
6023 sizeof(CM_SCSI_DEVICE_DATA
) ||
6024 (PCHAR
) (PartialDescriptor
+ 1) - (PCHAR
)FullResource
+
6025 PartialDescriptor
->u
.DeviceSpecificData
.DataSize
>
6026 KeyValueInformation
->DataLength
)
6028 DPRINT("Resource data length is incorrect");
6032 /* Set only one field from it */
6033 ScsiDeviceData
= (PCM_SCSI_DEVICE_DATA
) (PartialDescriptor
+1);
6034 ConfigInfo
->InitiatorBusId
[0] = ScsiDeviceData
->HostIdentifier
;
6045 SpQueryDeviceCallout(IN PVOID Context
,
6046 IN PUNICODE_STRING PathName
,
6047 IN INTERFACE_TYPE BusType
,
6049 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
6050 IN CONFIGURATION_TYPE ControllerType
,
6051 IN ULONG ControllerNumber
,
6052 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
6053 IN CONFIGURATION_TYPE PeripheralType
,
6054 IN ULONG PeripheralNumber
,
6055 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
6057 PBOOLEAN Found
= (PBOOLEAN
)Context
;
6058 /* We just set our Found variable to TRUE */
6061 return STATUS_SUCCESS
;
6068 SpiStatusSrbToNt(UCHAR SrbStatus
)
6070 switch (SRB_STATUS(SrbStatus
))
6072 case SRB_STATUS_TIMEOUT
:
6073 case SRB_STATUS_COMMAND_TIMEOUT
:
6074 return STATUS_IO_TIMEOUT
;
6076 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH
:
6077 case SRB_STATUS_BAD_FUNCTION
:
6078 return STATUS_INVALID_DEVICE_REQUEST
;
6080 case SRB_STATUS_NO_DEVICE
:
6081 case SRB_STATUS_INVALID_LUN
:
6082 case SRB_STATUS_INVALID_TARGET_ID
:
6083 case SRB_STATUS_NO_HBA
:
6084 return STATUS_DEVICE_DOES_NOT_EXIST
;
6086 case SRB_STATUS_DATA_OVERRUN
:
6087 return STATUS_BUFFER_OVERFLOW
;
6089 case SRB_STATUS_SELECTION_TIMEOUT
:
6090 return STATUS_DEVICE_NOT_CONNECTED
;
6093 return STATUS_IO_DEVICE_ERROR
;
6096 return STATUS_IO_DEVICE_ERROR
;
6100 #undef ScsiPortConvertPhysicalAddressToUlong
6105 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
6107 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
6108 return(Address
.u
.LowPart
);