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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS Storage Stack
22 * FILE: drivers/storage/scsiport/scsiport.c
23 * PURPOSE: SCSI port driver
24 * PROGRAMMER: Eric Kohl
25 * Aleksey Bragin (aleksey reactos org)
28 /* INCLUDES *****************************************************************/
37 ULONG InternalDebugLevel
= 0x00;
39 #undef ScsiPortMoveMemory
41 /* TYPES *********************************************************************/
43 /* GLOBALS *******************************************************************/
46 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
47 IN PDEVICE_OBJECT DeviceObject
,
48 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
49 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
50 IN PUNICODE_STRING RegistryPath
,
52 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
);
55 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
58 static DRIVER_DISPATCH ScsiPortDispatchScsi
;
60 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
64 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
67 static DRIVER_STARTIO ScsiPortStartIo
;
69 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
73 ScsiPortStartPacket(IN OUT PVOID Context
);
77 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
78 PVOID MapRegisterBase
, PVOID Context
);
80 static PSCSI_PORT_LUN_EXTENSION
81 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
83 static PSCSI_PORT_LUN_EXTENSION
84 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
89 static PSCSI_REQUEST_BLOCK_INFO
90 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
91 PSCSI_PORT_LUN_EXTENSION LunExtension
,
92 PSCSI_REQUEST_BLOCK Srb
);
95 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
96 IN PSCSI_LUN_INFO LunInfo
);
99 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
102 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
105 static PSCSI_REQUEST_BLOCK_INFO
106 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
113 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
114 IN PVOID ServiceContext
);
117 ScsiPortDpcForIsr(IN PKDPC Dpc
,
118 IN PDEVICE_OBJECT DpcDeviceObject
,
120 IN PVOID DpcContext
);
123 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
128 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject
,
130 IN PVOID MapRegisterBase
,
134 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
135 PUNICODE_STRING RegistryPath
);
138 SpiStatusSrbToNt(UCHAR SrbStatus
);
141 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
142 IN PSCSI_REQUEST_BLOCK Srb
);
144 static IO_COMPLETION_ROUTINE SpiCompletionRoutine
;
146 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
152 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
153 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
154 OUT PBOOLEAN NeedToCallStartIo
);
157 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
158 IN PSCSI_PORT_LUN_EXTENSION LunExtension
);
161 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
162 IN PVOID DeviceObject
,
163 IN PVOID SystemArgument1
,
164 IN PVOID SystemArgument2
);
167 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
168 PHW_INITIALIZATION_DATA HwInitData
,
169 PCONFIGURATION_INFO InternalConfigInfo
,
170 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
174 SpQueryDeviceCallout(IN PVOID Context
,
175 IN PUNICODE_STRING PathName
,
176 IN INTERFACE_TYPE BusType
,
178 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
179 IN CONFIGURATION_TYPE ControllerType
,
180 IN ULONG ControllerNumber
,
181 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
182 IN CONFIGURATION_TYPE PeripheralType
,
183 IN ULONG PeripheralNumber
,
184 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
);
187 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
189 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
190 IN PCONFIGURATION_INFO InternalConfigInfo
,
194 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
195 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
196 IN PPORT_CONFIGURATION_INFORMATION PortConfig
);
198 static PCM_RESOURCE_LIST
199 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
200 PPORT_CONFIGURATION_INFORMATION PortConfig
);
203 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
206 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
210 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
);
212 NTHALAPI ULONG NTAPI
HalGetBusData(BUS_DATA_TYPE
, ULONG
, ULONG
, PVOID
, ULONG
);
213 NTHALAPI ULONG NTAPI
HalGetInterruptVector(INTERFACE_TYPE
, ULONG
, ULONG
, ULONG
, PKIRQL
, PKAFFINITY
);
214 NTHALAPI NTSTATUS NTAPI
HalAssignSlotResources(PUNICODE_STRING
, PUNICODE_STRING
, PDRIVER_OBJECT
, PDEVICE_OBJECT
, INTERFACE_TYPE
, ULONG
, ULONG
, PCM_RESOURCE_LIST
*);
216 /* FUNCTIONS *****************************************************************/
218 /**********************************************************************
223 * This function initializes the driver.
230 * System allocated Driver Object for this driver.
233 * Name of registry driver service key.
240 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
241 IN PUNICODE_STRING RegistryPath
)
243 DPRINT("ScsiPort Driver %s\n", VERSION
);
244 return(STATUS_SUCCESS
);
248 /**********************************************************************
253 * Prints debugging messages.
260 * Debug level of the given message.
263 * Pointer to printf()-compatible format string.
266 Additional output data (see printf()).
275 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
276 IN PCHAR DebugMessage
,
282 if (DebugPrintLevel
> InternalDebugLevel
)
285 va_start(ap
, DebugMessage
);
286 vsprintf(Buffer
, DebugMessage
, ap
);
292 /* An internal helper function for ScsiPortCompleteRequest */
295 SpiCompleteRequest(IN PVOID HwDeviceExtension
,
296 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
299 PSCSI_REQUEST_BLOCK Srb
;
301 /* Get current SRB */
304 /* Return if there is no SRB or it is not active */
305 if (!Srb
|| !(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
)) return;
308 Srb
->SrbStatus
= SrbStatus
;
310 /* Set data transfered to 0 */
311 Srb
->DataTransferLength
= 0;
314 ScsiPortNotification(RequestComplete
,
323 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
329 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
330 PSCSI_PORT_LUN_EXTENSION LunExtension
;
331 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
332 PLIST_ENTRY ListEntry
;
336 DPRINT("ScsiPortCompleteRequest() called\n");
338 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
339 SCSI_PORT_DEVICE_EXTENSION
,
340 MiniPortDeviceExtension
);
342 /* Go through all buses */
343 for (BusNumber
= 0; BusNumber
< 8; BusNumber
++)
345 /* Go through all targets */
346 for (Target
= 0; Target
< DeviceExtension
->MaxTargedIds
; Target
++)
348 /* Get logical unit list head */
349 LunExtension
= DeviceExtension
->LunExtensionList
[Target
% 8];
351 /* Go through all logical units */
354 /* Now match what caller asked with what we are at now */
355 if ((PathId
== SP_UNTAGGED
|| PathId
== LunExtension
->PathId
) &&
356 (TargetId
== SP_UNTAGGED
|| TargetId
== LunExtension
->TargetId
) &&
357 (Lun
== SP_UNTAGGED
|| Lun
== LunExtension
->Lun
))
359 /* Yes, that's what caller asked for. Complete abort requests */
360 if (LunExtension
->CompletedAbortRequests
)
362 /* TODO: Save SrbStatus in this request */
363 DPRINT1("Completing abort request without setting SrbStatus!\n");
365 /* Issue a notification request */
366 ScsiPortNotification(RequestComplete
,
368 LunExtension
->CompletedAbortRequests
);
371 /* Complete the request using our helper */
372 SpiCompleteRequest(HwDeviceExtension
,
373 &LunExtension
->SrbInfo
,
376 /* Go through the queue and complete everything there too */
377 ListEntry
= LunExtension
->SrbInfo
.Requests
.Flink
;
378 while (ListEntry
!= &LunExtension
->SrbInfo
.Requests
)
380 /* Get the actual SRB info entry */
381 SrbInfo
= CONTAINING_RECORD(ListEntry
,
382 SCSI_REQUEST_BLOCK_INFO
,
386 SpiCompleteRequest(HwDeviceExtension
,
390 /* Advance to the next request in queue */
391 ListEntry
= SrbInfo
->Requests
.Flink
;
395 /* Advance to the next one */
396 LunExtension
= LunExtension
->Next
;
406 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
408 DPRINT("ScsiPortFlushDma()\n");
417 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
418 IN PVOID MappedAddress
)
420 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
421 PMAPPED_ADDRESS NextMa
, LastMa
;
423 //DPRINT("ScsiPortFreeDeviceBase() called\n");
425 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
426 SCSI_PORT_DEVICE_EXTENSION
,
427 MiniPortDeviceExtension
);
429 /* Initialize our pointers */
430 NextMa
= DeviceExtension
->MappedAddressList
;
435 if (NextMa
->MappedAddress
== MappedAddress
)
438 MmUnmapIoSpace(MappedAddress
, NextMa
->NumberOfBytes
);
440 /* Remove it from the list */
441 if (NextMa
== DeviceExtension
->MappedAddressList
)
443 /* Remove the first entry */
444 DeviceExtension
->MappedAddressList
= NextMa
->NextMappedAddress
;
448 LastMa
->NextMappedAddress
= NextMa
->NextMappedAddress
;
451 /* Free the resources and quit */
459 NextMa
= NextMa
->NextMappedAddress
;
469 ScsiPortGetBusData(IN PVOID DeviceExtension
,
470 IN ULONG BusDataType
,
471 IN ULONG SystemIoBusNumber
,
476 DPRINT("ScsiPortGetBusData()\n");
480 /* If Length is non-zero, just forward the call to
481 HalGetBusData() function */
482 return HalGetBusData(BusDataType
,
489 /* We have a more complex case here */
498 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
499 IN ULONG BusDataType
,
500 IN ULONG SystemIoBusNumber
,
506 DPRINT("ScsiPortSetBusDataByOffset()\n");
507 return HalSetBusDataByOffset(BusDataType
,
519 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
520 IN INTERFACE_TYPE BusType
,
521 IN ULONG SystemIoBusNumber
,
522 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
523 IN ULONG NumberOfBytes
,
524 IN BOOLEAN InIoSpace
)
526 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
527 PHYSICAL_ADDRESS TranslatedAddress
;
528 PMAPPED_ADDRESS DeviceBase
;
532 //DPRINT ("ScsiPortGetDeviceBase() called\n");
534 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
535 SCSI_PORT_DEVICE_EXTENSION
,
536 MiniPortDeviceExtension
);
538 AddressSpace
= (ULONG
)InIoSpace
;
539 if (HalTranslateBusAddress(BusType
,
543 &TranslatedAddress
) == FALSE
)
549 if (AddressSpace
!= 0)
550 return((PVOID
)(ULONG_PTR
)TranslatedAddress
.QuadPart
);
552 MappedAddress
= MmMapIoSpace(TranslatedAddress
,
556 DeviceBase
= ExAllocatePoolWithTag(NonPagedPool
,
557 sizeof(MAPPED_ADDRESS
), TAG_SCSIPORT
);
559 if (DeviceBase
== NULL
)
560 return MappedAddress
;
562 DeviceBase
->MappedAddress
= MappedAddress
;
563 DeviceBase
->NumberOfBytes
= NumberOfBytes
;
564 DeviceBase
->IoAddress
= IoAddress
;
565 DeviceBase
->BusNumber
= SystemIoBusNumber
;
567 /* Link it to the Device Extension list */
568 DeviceBase
->NextMappedAddress
= DeviceExtension
->MappedAddressList
;
569 DeviceExtension
->MappedAddressList
= DeviceBase
;
571 return MappedAddress
;
578 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
583 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
584 PSCSI_PORT_LUN_EXTENSION LunExtension
;
586 DPRINT("ScsiPortGetLogicalUnit() called\n");
588 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
589 SCSI_PORT_DEVICE_EXTENSION
,
590 MiniPortDeviceExtension
);
592 /* Check the extension size */
593 if (!DeviceExtension
->LunExtensionSize
)
595 /* They didn't want one */
599 LunExtension
= SpiGetLunExtension(DeviceExtension
,
603 /* Check that the logical unit exists */
606 /* Nope, return NULL */
610 /* Return the logical unit miniport extension */
611 return (LunExtension
+ 1);
618 SCSI_PHYSICAL_ADDRESS NTAPI
619 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
620 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
621 IN PVOID VirtualAddress
,
624 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
625 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
626 SIZE_T BufferLength
= 0;
628 PSCSI_SG_ADDRESS SGList
;
629 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
631 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
632 HwDeviceExtension
, Srb
, VirtualAddress
, Length
);
634 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
635 SCSI_PORT_DEVICE_EXTENSION
,
636 MiniPortDeviceExtension
);
638 if (Srb
== NULL
|| Srb
->SenseInfoBuffer
== VirtualAddress
)
640 /* Simply look it up in the allocated common buffer */
641 Offset
= (PUCHAR
)VirtualAddress
- (PUCHAR
)DeviceExtension
->SrbExtensionBuffer
;
643 BufferLength
= DeviceExtension
->CommonBufferLength
- Offset
;
644 PhysicalAddress
.QuadPart
= DeviceExtension
->PhysicalAddress
.QuadPart
+ Offset
;
646 else if (DeviceExtension
->MapRegisters
)
648 /* Scatter-gather list must be used */
649 SrbInfo
= SpiGetSrbData(DeviceExtension
,
655 SGList
= SrbInfo
->ScatterGather
;
657 /* Find needed item in the SG list */
658 Offset
= (PCHAR
)VirtualAddress
- (PCHAR
)Srb
->DataBuffer
;
659 while (Offset
>= SGList
->Length
)
661 Offset
-= SGList
->Length
;
665 /* We're done, store length and physical address */
666 BufferLength
= SGList
->Length
- Offset
;
667 PhysicalAddress
.QuadPart
= SGList
->PhysicalAddress
.QuadPart
+ Offset
;
673 PhysicalAddress
.QuadPart
= (LONGLONG
)(SP_UNINITIALIZED_VALUE
);
676 *Length
= (ULONG
)BufferLength
;
677 return PhysicalAddress
;
684 PSCSI_REQUEST_BLOCK NTAPI
685 ScsiPortGetSrb(IN PVOID DeviceExtension
,
691 DPRINT1("ScsiPortGetSrb() unimplemented\n");
701 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
702 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
703 IN ULONG NumberOfBytes
)
705 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
706 DEVICE_DESCRIPTION DeviceDescription
;
707 ULONG MapRegistersCount
;
710 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
711 HwDeviceExtension
, ConfigInfo
, NumberOfBytes
);
713 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
714 SCSI_PORT_DEVICE_EXTENSION
,
715 MiniPortDeviceExtension
);
717 /* Check for allocated common DMA buffer */
718 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
)
720 DPRINT1("The HBA has already got a common DMA buffer!\n");
724 /* Check for DMA adapter object */
725 if (DeviceExtension
->AdapterObject
== NULL
)
727 /* Initialize DMA adapter description */
728 RtlZeroMemory(&DeviceDescription
, sizeof(DEVICE_DESCRIPTION
));
730 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
731 DeviceDescription
.Master
= ConfigInfo
->Master
;
732 DeviceDescription
.ScatterGather
= ConfigInfo
->ScatterGather
;
733 DeviceDescription
.DemandMode
= ConfigInfo
->DemandMode
;
734 DeviceDescription
.Dma32BitAddresses
= ConfigInfo
->Dma32BitAddresses
;
735 DeviceDescription
.BusNumber
= ConfigInfo
->SystemIoBusNumber
;
736 DeviceDescription
.DmaChannel
= ConfigInfo
->DmaChannel
;
737 DeviceDescription
.InterfaceType
= ConfigInfo
->AdapterInterfaceType
;
738 DeviceDescription
.DmaWidth
= ConfigInfo
->DmaWidth
;
739 DeviceDescription
.DmaSpeed
= ConfigInfo
->DmaSpeed
;
740 DeviceDescription
.MaximumLength
= ConfigInfo
->MaximumTransferLength
;
741 DeviceDescription
.DmaPort
= ConfigInfo
->DmaPort
;
743 /* Get a DMA adapter object */
744 DeviceExtension
->AdapterObject
=
745 HalGetAdapter(&DeviceDescription
, &MapRegistersCount
);
747 /* Fail in case of error */
748 if (DeviceExtension
->AdapterObject
== NULL
)
750 DPRINT1("HalGetAdapter() failed\n");
754 /* Set number of physical breaks */
755 if (ConfigInfo
->NumberOfPhysicalBreaks
!= 0 &&
756 MapRegistersCount
> ConfigInfo
->NumberOfPhysicalBreaks
)
758 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
=
759 ConfigInfo
->NumberOfPhysicalBreaks
;
763 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
= MapRegistersCount
;
767 /* Update auto request sense feature */
768 DeviceExtension
->SupportsAutoSense
= ConfigInfo
->AutoRequestSense
;
770 /* Update Srb extension size */
771 if (DeviceExtension
->SrbExtensionSize
!= ConfigInfo
->SrbExtensionSize
)
772 DeviceExtension
->SrbExtensionSize
= ConfigInfo
->SrbExtensionSize
;
774 /* Update Srb extension alloc flag */
775 if (ConfigInfo
->AutoRequestSense
|| DeviceExtension
->SrbExtensionSize
)
776 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
778 /* Allocate a common DMA buffer */
779 Status
= SpiAllocateCommonBuffer(DeviceExtension
, NumberOfBytes
);
781 if (!NT_SUCCESS(Status
))
783 DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status
);
787 return DeviceExtension
->NonCachedExtension
;
791 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
)
793 PVOID
*SrbExtension
, CommonBuffer
;
794 ULONG CommonBufferLength
, BufSize
;
796 /* If size is 0, set it to 16 */
797 if (!DeviceExtension
->SrbExtensionSize
)
798 DeviceExtension
->SrbExtensionSize
= 16;
801 BufSize
= DeviceExtension
->SrbExtensionSize
;
803 /* Add autosense data size if needed */
804 if (DeviceExtension
->SupportsAutoSense
)
805 BufSize
+= sizeof(SENSE_DATA
);
809 BufSize
= (BufSize
+ sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
811 /* Sum up into the total common buffer length, and round it to page size */
813 ROUND_TO_PAGES(NonCachedSize
+ BufSize
* DeviceExtension
->RequestsNumber
);
816 if (!DeviceExtension
->AdapterObject
)
818 /* From nonpaged pool if there is no DMA */
819 CommonBuffer
= ExAllocatePoolWithTag(NonPagedPool
, CommonBufferLength
, TAG_SCSIPORT
);
823 /* Perform a full request since we have a DMA adapter*/
824 CommonBuffer
= HalAllocateCommonBuffer(DeviceExtension
->AdapterObject
,
826 &DeviceExtension
->PhysicalAddress
,
830 /* Fail in case of error */
832 return STATUS_INSUFFICIENT_RESOURCES
;
835 RtlZeroMemory(CommonBuffer
, CommonBufferLength
);
837 /* Store its size in Device Extension */
838 DeviceExtension
->CommonBufferLength
= CommonBufferLength
;
840 /* SrbExtension buffer is located at the beginning of the buffer */
841 DeviceExtension
->SrbExtensionBuffer
= CommonBuffer
;
843 /* Non-cached extension buffer is located at the end of
847 CommonBufferLength
-= NonCachedSize
;
848 DeviceExtension
->NonCachedExtension
= (PUCHAR
)CommonBuffer
+ CommonBufferLength
;
852 DeviceExtension
->NonCachedExtension
= NULL
;
855 if (DeviceExtension
->NeedSrbExtensionAlloc
)
857 /* Look up how many SRB data structures we need */
858 DeviceExtension
->SrbDataCount
= CommonBufferLength
/ BufSize
;
860 /* Initialize the free SRB extensions list */
861 SrbExtension
= (PVOID
*)CommonBuffer
;
862 DeviceExtension
->FreeSrbExtensions
= SrbExtension
;
864 /* Fill the remainding pointers (if we have more than 1 SRB) */
865 while (CommonBufferLength
>= 2 * BufSize
)
867 *SrbExtension
= (PVOID
*)((PCHAR
)SrbExtension
+ BufSize
);
868 SrbExtension
= *SrbExtension
;
870 CommonBufferLength
-= BufSize
;
874 return STATUS_SUCCESS
;
883 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
884 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
886 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
889 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
890 HwDeviceExtension
, PhysicalAddress
.QuadPart
);
892 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
893 SCSI_PORT_DEVICE_EXTENSION
,
894 MiniPortDeviceExtension
);
896 if (DeviceExtension
->PhysicalAddress
.QuadPart
> PhysicalAddress
.QuadPart
)
899 Offset
= (ULONG
)(PhysicalAddress
.QuadPart
- DeviceExtension
->PhysicalAddress
.QuadPart
);
901 if (Offset
>= DeviceExtension
->CommonBufferLength
)
904 return (PVOID
)((ULONG_PTR
)DeviceExtension
->SrbExtensionBuffer
+ Offset
);
908 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo
, PUNICODE_STRING RegistryPath
)
910 OBJECT_ATTRIBUTES ObjectAttributes
;
911 UNICODE_STRING KeyName
;
914 /* Open the service key */
915 InitializeObjectAttributes(&ObjectAttributes
,
917 OBJ_CASE_INSENSITIVE
,
921 Status
= ZwOpenKey(&ConfigInfo
->ServiceKey
,
925 if (!NT_SUCCESS(Status
))
927 DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath
, Status
);
928 ConfigInfo
->ServiceKey
= NULL
;
931 /* If we could open driver's service key, then proceed to the Parameters key */
932 if (ConfigInfo
->ServiceKey
!= NULL
)
934 RtlInitUnicodeString(&KeyName
, L
"Parameters");
935 InitializeObjectAttributes(&ObjectAttributes
,
937 OBJ_CASE_INSENSITIVE
,
938 ConfigInfo
->ServiceKey
,
939 (PSECURITY_DESCRIPTOR
) NULL
);
942 Status
= ZwOpenKey(&ConfigInfo
->DeviceKey
,
946 if (NT_SUCCESS(Status
))
948 /* Yes, Parameters key exist, and it must be used instead of
950 ZwClose(ConfigInfo
->ServiceKey
);
951 ConfigInfo
->ServiceKey
= ConfigInfo
->DeviceKey
;
952 ConfigInfo
->DeviceKey
= NULL
;
956 if (ConfigInfo
->ServiceKey
!= NULL
)
958 /* Open the Device key */
959 RtlInitUnicodeString(&KeyName
, L
"Device");
960 InitializeObjectAttributes(&ObjectAttributes
,
962 OBJ_CASE_INSENSITIVE
,
963 ConfigInfo
->ServiceKey
,
966 /* We don't check for failure here - not needed */
967 ZwOpenKey(&ConfigInfo
->DeviceKey
,
974 /**********************************************************************
979 * Initializes SCSI port driver specific data.
986 * Pointer to the miniport driver's driver object.
989 * Pointer to the miniport driver's registry path.
991 * HwInitializationData
992 * Pointer to port driver specific configuration data.
995 Miniport driver specific context.
1004 ScsiPortInitialize(IN PVOID Argument1
,
1006 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
1009 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
1010 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
1011 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
1012 PCONFIGURATION_INFORMATION SystemConfig
;
1013 PPORT_CONFIGURATION_INFORMATION PortConfig
;
1014 PORT_CONFIGURATION_INFORMATION InitialPortConfig
;
1015 CONFIGURATION_INFO ConfigInfo
;
1016 ULONG DeviceExtensionSize
;
1017 ULONG PortConfigSize
;
1019 BOOLEAN DeviceFound
= FALSE
;
1020 BOOLEAN FirstConfigCall
= TRUE
;
1024 ULONG BusNumber
= 0;
1025 PCI_SLOT_NUMBER SlotNumber
;
1027 PDEVICE_OBJECT PortDeviceObject
;
1028 WCHAR NameBuffer
[80];
1029 UNICODE_STRING DeviceName
;
1030 WCHAR DosNameBuffer
[80];
1031 UNICODE_STRING DosDeviceName
;
1032 PIO_SCSI_CAPABILITIES PortCapabilities
;
1035 PCM_RESOURCE_LIST ResourceList
;
1037 SIZE_T BusConfigSize
;
1040 DPRINT ("ScsiPortInitialize() called!\n");
1042 /* Check params for validity */
1043 if ((HwInitializationData
->HwInitialize
== NULL
) ||
1044 (HwInitializationData
->HwStartIo
== NULL
) ||
1045 (HwInitializationData
->HwInterrupt
== NULL
) ||
1046 (HwInitializationData
->HwFindAdapter
== NULL
) ||
1047 (HwInitializationData
->HwResetBus
== NULL
))
1049 return STATUS_INVALID_PARAMETER
;
1053 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
1054 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
1055 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
1056 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
1057 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
1059 /* Obtain configuration information */
1060 SystemConfig
= IoGetConfigurationInformation();
1062 /* Zero the internal configuration info structure */
1063 RtlZeroMemory(&ConfigInfo
, sizeof(CONFIGURATION_INFO
));
1065 /* Zero starting slot number */
1066 SlotNumber
.u
.AsULONG
= 0;
1068 /* Allocate space for access ranges */
1069 if (HwInitializationData
->NumberOfAccessRanges
)
1071 ConfigInfo
.AccessRanges
=
1072 ExAllocatePoolWithTag(PagedPool
,
1073 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
), TAG_SCSIPORT
);
1075 /* Fail if failed */
1076 if (ConfigInfo
.AccessRanges
== NULL
)
1077 return STATUS_INSUFFICIENT_RESOURCES
;
1080 /* Open registry keys */
1081 SpiInitOpenKeys(&ConfigInfo
, (PUNICODE_STRING
)Argument2
);
1083 /* Last adapter number = not known */
1084 ConfigInfo
.LastAdapterNumber
= SP_UNINITIALIZED_VALUE
;
1086 /* Calculate sizes of DeviceExtension and PortConfig */
1087 DeviceExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
1088 HwInitializationData
->DeviceExtensionSize
;
1090 MaxBus
= (HwInitializationData
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
1091 DPRINT("MaxBus: %lu\n", MaxBus
);
1095 /* Create a unicode device name */
1096 swprintf(NameBuffer
,
1097 L
"\\Device\\ScsiPort%lu",
1098 SystemConfig
->ScsiPortCount
);
1099 RtlInitUnicodeString(&DeviceName
, NameBuffer
);
1101 DPRINT("Creating device: %wZ\n", &DeviceName
);
1103 /* Create the port device */
1104 Status
= IoCreateDevice(DriverObject
,
1105 DeviceExtensionSize
,
1107 FILE_DEVICE_CONTROLLER
,
1112 if (!NT_SUCCESS(Status
))
1114 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
1115 PortDeviceObject
= NULL
;
1119 DPRINT ("Created device: %wZ (%p)\n", &DeviceName
, PortDeviceObject
);
1121 /* Set the buffering strategy here... */
1122 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1123 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
; /* FIXME: Is this really needed? */
1125 /* Fill Device Extension */
1126 DeviceExtension
= PortDeviceObject
->DeviceExtension
;
1127 RtlZeroMemory(DeviceExtension
, DeviceExtensionSize
);
1128 DeviceExtension
->Length
= DeviceExtensionSize
;
1129 DeviceExtension
->DeviceObject
= PortDeviceObject
;
1130 DeviceExtension
->PortNumber
= SystemConfig
->ScsiPortCount
;
1132 /* Driver's routines... */
1133 DeviceExtension
->HwInitialize
= HwInitializationData
->HwInitialize
;
1134 DeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
1135 DeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
1136 DeviceExtension
->HwResetBus
= HwInitializationData
->HwResetBus
;
1137 DeviceExtension
->HwDmaStarted
= HwInitializationData
->HwDmaStarted
;
1139 /* Extensions sizes */
1140 DeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
1141 DeviceExtension
->LunExtensionSize
= HwInitializationData
->SpecificLuExtensionSize
;
1142 DeviceExtension
->SrbExtensionSize
= HwInitializationData
->SrbExtensionSize
;
1144 /* Round Srb extension size to the quadword */
1145 DeviceExtension
->SrbExtensionSize
=
1146 ~(sizeof(LONGLONG
) - 1) & (DeviceExtension
->SrbExtensionSize
+
1147 sizeof(LONGLONG
) - 1);
1149 /* Fill some numbers (bus count, lun count, etc) */
1150 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
1151 DeviceExtension
->RequestsNumber
= 16;
1153 /* Initialize the spin lock in the controller extension */
1154 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1155 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
1157 /* Initialize the DPC object */
1158 IoInitializeDpcRequest(PortDeviceObject
,
1161 /* Initialize the device timer */
1162 DeviceExtension
->TimerCount
= -1;
1163 IoInitializeTimer(PortDeviceObject
,
1167 /* Initialize miniport timer */
1168 KeInitializeTimer(&DeviceExtension
->MiniportTimer
);
1169 KeInitializeDpc(&DeviceExtension
->MiniportTimerDpc
,
1170 SpiMiniportTimerDpc
,
1175 Status
= SpiCreatePortConfig(DeviceExtension
,
1176 HwInitializationData
,
1181 if (!NT_SUCCESS(Status
))
1183 DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status
);
1187 /* Allocate and initialize port configuration info */
1188 PortConfigSize
= (sizeof(PORT_CONFIGURATION_INFORMATION
) +
1189 HwInitializationData
->NumberOfAccessRanges
*
1190 sizeof(ACCESS_RANGE
) + 7) & ~7;
1191 DeviceExtension
->PortConfig
= ExAllocatePoolWithTag(NonPagedPool
, PortConfigSize
, TAG_SCSIPORT
);
1193 /* Fail if failed */
1194 if (DeviceExtension
->PortConfig
== NULL
)
1196 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1200 PortConfig
= DeviceExtension
->PortConfig
;
1202 /* Copy information here */
1203 RtlCopyMemory(PortConfig
,
1205 sizeof(PORT_CONFIGURATION_INFORMATION
));
1208 /* Copy extension sizes into the PortConfig */
1209 PortConfig
->SpecificLuExtensionSize
= DeviceExtension
->LunExtensionSize
;
1210 PortConfig
->SrbExtensionSize
= DeviceExtension
->SrbExtensionSize
;
1212 /* Initialize Access ranges */
1213 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1215 PortConfig
->AccessRanges
= (PVOID
)(PortConfig
+1);
1217 /* Align to LONGLONG */
1218 PortConfig
->AccessRanges
= (PVOID
)((ULONG_PTR
)(PortConfig
->AccessRanges
) + 7);
1219 PortConfig
->AccessRanges
= (PVOID
)((ULONG_PTR
)(PortConfig
->AccessRanges
) & ~7);
1222 RtlCopyMemory(PortConfig
->AccessRanges
,
1223 ConfigInfo
.AccessRanges
,
1224 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
1227 /* Search for matching PCI device */
1228 if ((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1229 (HwInitializationData
->VendorIdLength
> 0) &&
1230 (HwInitializationData
->VendorId
!= NULL
) &&
1231 (HwInitializationData
->DeviceIdLength
> 0) &&
1232 (HwInitializationData
->DeviceId
!= NULL
))
1234 PortConfig
->BusInterruptLevel
= 0;
1236 /* Get PCI device data */
1237 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1238 HwInitializationData
->VendorIdLength
,
1239 HwInitializationData
->VendorId
,
1240 HwInitializationData
->DeviceIdLength
,
1241 HwInitializationData
->DeviceId
);
1243 if (!SpiGetPciConfigData(DriverObject
,
1245 HwInitializationData
,
1248 ConfigInfo
.BusNumber
,
1251 /* Continue to the next bus, nothing here */
1252 ConfigInfo
.BusNumber
++;
1253 DeviceExtension
->PortConfig
= NULL
;
1254 ExFreePool(PortConfig
);
1256 goto CreatePortConfig
;
1259 if (!PortConfig
->BusInterruptLevel
)
1261 /* Bypass this slot, because no interrupt was assigned */
1262 DeviceExtension
->PortConfig
= NULL
;
1263 ExFreePool(PortConfig
);
1264 goto CreatePortConfig
;
1269 DPRINT("Non-pci bus\n");
1272 /* Note: HwFindAdapter is called once for each bus */
1274 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
1275 Result
= (HwInitializationData
->HwFindAdapter
)(&DeviceExtension
->MiniPortDeviceExtension
,
1277 0, /* BusInformation */
1278 ConfigInfo
.Parameter
, /* ArgumentString */
1282 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1283 Result
, (Again
) ? "True" : "False");
1285 /* Free MapRegisterBase, it's not needed anymore */
1286 if (DeviceExtension
->MapRegisterBase
!= NULL
)
1288 ExFreePool(DeviceExtension
->MapRegisterBase
);
1289 DeviceExtension
->MapRegisterBase
= NULL
;
1292 /* If result is nothing good... */
1293 if (Result
!= SP_RETURN_FOUND
)
1295 DPRINT("HwFindAdapter() Result: %lu\n", Result
);
1297 if (Result
== SP_RETURN_NOT_FOUND
)
1299 /* We can continue on the next bus */
1300 ConfigInfo
.BusNumber
++;
1303 DeviceExtension
->PortConfig
= NULL
;
1304 ExFreePool(PortConfig
);
1305 goto CreatePortConfig
;
1308 /* Otherwise, break */
1309 Status
= STATUS_INTERNAL_ERROR
;
1313 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1314 PortConfig
->BusInterruptVector
, PortConfig
->InitiatorBusId
[0]);
1316 /* If the SRB extension size was updated */
1317 if (!DeviceExtension
->NonCachedExtension
&&
1318 (PortConfig
->SrbExtensionSize
!= DeviceExtension
->SrbExtensionSize
))
1320 /* Set it (rounding to LONGLONG again) */
1321 DeviceExtension
->SrbExtensionSize
=
1322 (PortConfig
->SrbExtensionSize
+
1323 sizeof(LONGLONG
)) & ~(sizeof(LONGLONG
) - 1);
1326 /* The same with LUN extension size */
1327 if (PortConfig
->SpecificLuExtensionSize
!= DeviceExtension
->LunExtensionSize
)
1328 DeviceExtension
->LunExtensionSize
= PortConfig
->SpecificLuExtensionSize
;
1331 if (!((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1332 (HwInitializationData
->VendorIdLength
> 0) &&
1333 (HwInitializationData
->VendorId
!= NULL
) &&
1334 (HwInitializationData
->DeviceIdLength
> 0) &&
1335 (HwInitializationData
->DeviceId
!= NULL
)))
1337 /* Construct a resource list */
1338 ResourceList
= SpiConfigToResource(DeviceExtension
,
1343 UNICODE_STRING UnicodeString
;
1344 RtlInitUnicodeString(&UnicodeString
, L
"ScsiAdapter");
1345 DPRINT("Reporting resources\n");
1346 Status
= IoReportResourceUsage(&UnicodeString
,
1352 FIELD_OFFSET(CM_RESOURCE_LIST
,
1353 List
[0].PartialResourceList
.PartialDescriptors
) +
1354 ResourceList
->List
[0].PartialResourceList
.Count
1355 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
1358 ExFreePool(ResourceList
);
1360 /* In case of a failure or a conflict, break */
1361 if (Conflict
|| (!NT_SUCCESS(Status
)))
1364 Status
= STATUS_CONFLICTING_ADDRESSES
;
1370 /* Reset the Conflict var */
1373 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1374 if (PortConfig
->MaximumNumberOfTargets
> SCSI_MAXIMUM_TARGETS_PER_BUS
)
1375 DeviceExtension
->MaxTargedIds
= SCSI_MAXIMUM_TARGETS_PER_BUS
;
1377 DeviceExtension
->MaxTargedIds
= PortConfig
->MaximumNumberOfTargets
;
1379 DeviceExtension
->BusNum
= PortConfig
->NumberOfBuses
;
1380 DeviceExtension
->CachesData
= PortConfig
->CachesData
;
1381 DeviceExtension
->ReceiveEvent
= PortConfig
->ReceiveEvent
;
1382 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->TaggedQueuing
;
1383 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
;
1385 /* If something was disabled via registry - apply it */
1386 if (ConfigInfo
.DisableMultipleLun
)
1387 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1389 if (ConfigInfo
.DisableTaggedQueueing
)
1390 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1392 /* Check if we need to alloc SRB data */
1393 if (DeviceExtension
->SupportsTaggedQueuing
||
1394 DeviceExtension
->MultipleReqsPerLun
)
1396 DeviceExtension
->NeedSrbDataAlloc
= TRUE
;
1400 DeviceExtension
->NeedSrbDataAlloc
= FALSE
;
1403 /* Get a pointer to the port capabilities */
1404 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1406 /* Copy one field there */
1407 DeviceExtension
->MapBuffers
= PortConfig
->MapBuffers
;
1408 PortCapabilities
->AdapterUsesPio
= PortConfig
->MapBuffers
;
1410 if (DeviceExtension
->AdapterObject
== NULL
&&
1411 (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
|| PortConfig
->Master
))
1413 DPRINT1("DMA is not supported yet\n");
1417 if (DeviceExtension
->SrbExtensionBuffer
== NULL
&&
1418 (DeviceExtension
->SrbExtensionSize
!= 0 ||
1419 PortConfig
->AutoRequestSense
))
1421 DeviceExtension
->SupportsAutoSense
= PortConfig
->AutoRequestSense
;
1422 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
1424 /* Allocate common buffer */
1425 Status
= SpiAllocateCommonBuffer(DeviceExtension
, 0);
1427 /* Check for failure */
1428 if (!NT_SUCCESS(Status
))
1432 /* Allocate SrbData, if needed */
1433 if (DeviceExtension
->NeedSrbDataAlloc
)
1436 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1438 if (DeviceExtension
->SrbDataCount
!= 0)
1439 Count
= DeviceExtension
->SrbDataCount
;
1441 Count
= DeviceExtension
->RequestsNumber
* 2;
1443 /* Allocate the data */
1444 SrbData
= ExAllocatePoolWithTag(NonPagedPool
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
), TAG_SCSIPORT
);
1445 if (SrbData
== NULL
)
1446 return STATUS_INSUFFICIENT_RESOURCES
;
1448 RtlZeroMemory(SrbData
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
));
1450 DeviceExtension
->SrbInfo
= SrbData
;
1451 DeviceExtension
->FreeSrbInfo
= SrbData
;
1452 DeviceExtension
->SrbDataCount
= Count
;
1454 /* Link it to the list */
1457 SrbData
->Requests
.Flink
= (PLIST_ENTRY
)(SrbData
+ 1);
1462 /* Mark the last entry of the list */
1464 SrbData
->Requests
.Flink
= NULL
;
1467 /* Initialize port capabilities */
1468 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1469 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1470 PortCapabilities
->MaximumTransferLength
= PortConfig
->MaximumTransferLength
;
1472 if (PortConfig
->ReceiveEvent
)
1473 PortCapabilities
->SupportedAsynchronousEvents
|= SRBEV_SCSI_ASYNC_NOTIFICATION
;
1475 PortCapabilities
->TaggedQueuing
= DeviceExtension
->SupportsTaggedQueuing
;
1476 PortCapabilities
->AdapterScansDown
= PortConfig
->AdapterScansDown
;
1478 if (PortConfig
->AlignmentMask
> PortDeviceObject
->AlignmentRequirement
)
1479 PortDeviceObject
->AlignmentRequirement
= PortConfig
->AlignmentMask
;
1481 PortCapabilities
->AlignmentMask
= PortDeviceObject
->AlignmentRequirement
;
1483 if (PortCapabilities
->MaximumPhysicalPages
== 0)
1485 PortCapabilities
->MaximumPhysicalPages
=
1486 BYTES_TO_PAGES(PortCapabilities
->MaximumTransferLength
);
1488 /* Apply miniport's limits */
1489 if (PortConfig
->NumberOfPhysicalBreaks
< PortCapabilities
->MaximumPhysicalPages
)
1491 PortCapabilities
->MaximumPhysicalPages
= PortConfig
->NumberOfPhysicalBreaks
;
1495 /* Deal with interrupts */
1496 if (DeviceExtension
->HwInterrupt
== NULL
||
1497 (PortConfig
->BusInterruptLevel
== 0 && PortConfig
->BusInterruptVector
== 0))
1500 DeviceExtension
->InterruptCount
= 0;
1502 DPRINT1("Interrupt Count: 0\n");
1506 /* This code path will ALWAYS crash so stop it now */
1511 BOOLEAN InterruptShareable
;
1512 KINTERRUPT_MODE InterruptMode
[2];
1513 ULONG InterruptVector
[2], i
, MappedIrq
[2];
1514 KIRQL Dirql
[2], MaxDirql
;
1515 KAFFINITY Affinity
[2];
1517 DeviceExtension
->InterruptLevel
[0] = PortConfig
->BusInterruptLevel
;
1518 DeviceExtension
->InterruptLevel
[1] = PortConfig
->BusInterruptLevel2
;
1520 InterruptVector
[0] = PortConfig
->BusInterruptVector
;
1521 InterruptVector
[1] = PortConfig
->BusInterruptVector2
;
1523 InterruptMode
[0] = PortConfig
->InterruptMode
;
1524 InterruptMode
[1] = PortConfig
->InterruptMode2
;
1526 DeviceExtension
->InterruptCount
= (PortConfig
->BusInterruptLevel2
!= 0 || PortConfig
->BusInterruptVector2
!= 0) ? 2 : 1;
1528 for (i
= 0; i
< DeviceExtension
->InterruptCount
; i
++)
1530 /* Register an interrupt handler for this device */
1531 MappedIrq
[i
] = HalGetInterruptVector(PortConfig
->AdapterInterfaceType
,
1532 PortConfig
->SystemIoBusNumber
,
1533 DeviceExtension
->InterruptLevel
[i
],
1539 if (DeviceExtension
->InterruptCount
== 1 || Dirql
[0] > Dirql
[1])
1540 MaxDirql
= Dirql
[0];
1542 MaxDirql
= Dirql
[1];
1544 for (i
= 0; i
< DeviceExtension
->InterruptCount
; i
++)
1546 /* Determing IRQ sharability as usual */
1547 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1548 InterruptMode
[i
] == LevelSensitive
)
1550 InterruptShareable
= TRUE
;
1554 InterruptShareable
= FALSE
;
1557 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
[i
],
1558 (PKSERVICE_ROUTINE
)ScsiPortIsr
,
1560 &DeviceExtension
->IrqLock
,
1569 if (!(NT_SUCCESS(Status
)))
1571 DPRINT1("Could not connect interrupt %d\n",
1572 InterruptVector
[i
]);
1573 DeviceExtension
->Interrupt
[i
] = NULL
;
1578 if (!NT_SUCCESS(Status
))
1582 /* Save IoAddress (from access ranges) */
1583 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1585 DeviceExtension
->IoAddress
=
1586 ((*(PortConfig
->AccessRanges
))[0]).RangeStart
.LowPart
;
1588 DPRINT("Io Address %x\n", DeviceExtension
->IoAddress
);
1591 /* Set flag that it's allowed to disconnect during this command */
1592 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
1594 /* Initialize counter of active requests (-1 means there are none) */
1595 DeviceExtension
->ActiveRequestCounter
= -1;
1597 /* Analyze what we have about DMA */
1598 if (DeviceExtension
->AdapterObject
!= NULL
&&
1599 PortConfig
->Master
&&
1600 PortConfig
->NeedPhysicalAddresses
)
1602 DeviceExtension
->MapRegisters
= TRUE
;
1606 DeviceExtension
->MapRegisters
= FALSE
;
1609 /* Call HwInitialize at DISPATCH_LEVEL */
1610 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1612 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
1613 DeviceExtension
->HwInitialize
,
1614 DeviceExtension
->MiniPortDeviceExtension
))
1616 DPRINT1("HwInitialize() failed!\n");
1617 KeLowerIrql(OldIrql
);
1618 Status
= STATUS_ADAPTER_HARDWARE_ERROR
;
1622 /* Check if a notification is needed */
1623 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
1625 /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1626 ScsiPortDpcForIsr(NULL
,
1627 DeviceExtension
->DeviceObject
,
1632 /* Lower irql back to what it was */
1633 KeLowerIrql(OldIrql
);
1635 /* Start our timer */
1636 IoStartTimer(PortDeviceObject
);
1638 /* Initialize bus scanning information */
1639 BusConfigSize
= FIELD_OFFSET(BUSES_CONFIGURATION_INFORMATION
,
1640 BusScanInfo
[DeviceExtension
->PortConfig
->NumberOfBuses
]);
1641 DeviceExtension
->BusesConfig
= ExAllocatePoolWithTag(PagedPool
,
1644 if (!DeviceExtension
->BusesConfig
)
1646 DPRINT1("Out of resources!\n");
1647 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1652 RtlZeroMemory(DeviceExtension
->BusesConfig
, BusConfigSize
);
1654 /* Store number of buses there */
1655 DeviceExtension
->BusesConfig
->NumberOfBuses
= (UCHAR
)DeviceExtension
->BusNum
;
1657 /* Scan the adapter for devices */
1658 SpiScanAdapter(DeviceExtension
);
1660 /* Build the registry device map */
1661 SpiBuildDeviceMap(DeviceExtension
,
1662 (PUNICODE_STRING
)Argument2
);
1664 /* Create the dos device link */
1665 swprintf(DosNameBuffer
,
1667 SystemConfig
->ScsiPortCount
);
1668 RtlInitUnicodeString(&DosDeviceName
, DosNameBuffer
);
1669 IoCreateSymbolicLink(&DosDeviceName
, &DeviceName
);
1671 /* Increase the port count */
1672 SystemConfig
->ScsiPortCount
++;
1673 FirstConfigCall
= FALSE
;
1675 /* Increase adapter number and bus number respectively */
1676 ConfigInfo
.AdapterNumber
++;
1679 ConfigInfo
.BusNumber
++;
1681 DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber
, MaxBus
);
1686 /* Clean up the mess */
1687 SpiCleanupAfterInit(DeviceExtension
);
1689 /* Close registry keys */
1690 if (ConfigInfo
.ServiceKey
!= NULL
)
1691 ZwClose(ConfigInfo
.ServiceKey
);
1693 if (ConfigInfo
.DeviceKey
!= NULL
)
1694 ZwClose(ConfigInfo
.DeviceKey
);
1696 if (ConfigInfo
.BusKey
!= NULL
)
1697 ZwClose(ConfigInfo
.BusKey
);
1699 if (ConfigInfo
.AccessRanges
!= NULL
)
1700 ExFreePool(ConfigInfo
.AccessRanges
);
1702 if (ConfigInfo
.Parameter
!= NULL
)
1703 ExFreePool(ConfigInfo
.Parameter
);
1705 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1706 Status
, DeviceFound
);
1708 return (DeviceFound
== FALSE
) ? Status
: STATUS_SUCCESS
;
1712 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1714 PSCSI_LUN_INFO LunInfo
;
1718 /* Check if we have something to clean up */
1719 if (DeviceExtension
== NULL
)
1722 /* Stop the timer */
1723 IoStopTimer(DeviceExtension
->DeviceObject
);
1725 /* Disconnect the interrupts */
1726 while (DeviceExtension
->InterruptCount
)
1728 if (DeviceExtension
->Interrupt
[--DeviceExtension
->InterruptCount
])
1729 IoDisconnectInterrupt(DeviceExtension
->Interrupt
[DeviceExtension
->InterruptCount
]);
1732 /* Delete ConfigInfo */
1733 if (DeviceExtension
->BusesConfig
)
1735 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
1737 if (!DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
])
1740 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
1744 /* Free current, but save pointer to the next one */
1745 Ptr
= LunInfo
->Next
;
1746 ExFreePool(LunInfo
);
1750 ExFreePool(DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]);
1753 ExFreePool(DeviceExtension
->BusesConfig
);
1756 /* Free PortConfig */
1757 if (DeviceExtension
->PortConfig
)
1758 ExFreePool(DeviceExtension
->PortConfig
);
1761 for(Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
1763 while (DeviceExtension
->LunExtensionList
[Lun
])
1765 Ptr
= DeviceExtension
->LunExtensionList
[Lun
];
1766 DeviceExtension
->LunExtensionList
[Lun
] = DeviceExtension
->LunExtensionList
[Lun
]->Next
;
1772 /* Free common buffer (if it exists) */
1773 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
&&
1774 DeviceExtension
->CommonBufferLength
!= 0)
1776 if (!DeviceExtension
->AdapterObject
)
1778 ExFreePool(DeviceExtension
->SrbExtensionBuffer
);
1782 HalFreeCommonBuffer(DeviceExtension
->AdapterObject
,
1783 DeviceExtension
->CommonBufferLength
,
1784 DeviceExtension
->PhysicalAddress
,
1785 DeviceExtension
->SrbExtensionBuffer
,
1791 if (DeviceExtension
->SrbInfo
!= NULL
)
1792 ExFreePool(DeviceExtension
->SrbInfo
);
1794 /* Unmap mapped addresses */
1795 while (DeviceExtension
->MappedAddressList
!= NULL
)
1797 MmUnmapIoSpace(DeviceExtension
->MappedAddressList
->MappedAddress
,
1798 DeviceExtension
->MappedAddressList
->NumberOfBytes
);
1800 Ptr
= DeviceExtension
->MappedAddressList
;
1801 DeviceExtension
->MappedAddressList
= DeviceExtension
->MappedAddressList
->NextMappedAddress
;
1806 /* Finally delete the device object */
1807 DPRINT("Deleting device %p\n", DeviceExtension
->DeviceObject
);
1808 IoDeleteDevice(DeviceExtension
->DeviceObject
);
1815 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
1816 IN PSCSI_REQUEST_BLOCK Srb
,
1817 IN PVOID LogicalAddress
,
1820 DPRINT1("ScsiPortIoMapTransfer()\n");
1828 ScsiPortLogError(IN PVOID HwDeviceExtension
,
1829 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
1836 //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1838 DPRINT1("ScsiPortLogError() called\n");
1840 //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1843 DPRINT("ScsiPortLogError() done\n");
1850 ScsiPortMoveMemory(OUT PVOID Destination
,
1854 RtlMoveMemory(Destination
,
1864 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
1865 IN PVOID HwDeviceExtension
,
1868 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1871 DPRINT("ScsiPortNotification() called\n");
1873 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1874 SCSI_PORT_DEVICE_EXTENSION
,
1875 MiniPortDeviceExtension
);
1877 DPRINT("DeviceExtension %p\n", DeviceExtension
);
1879 va_start(ap
, HwDeviceExtension
);
1881 switch (NotificationType
)
1883 case RequestComplete
:
1885 PSCSI_REQUEST_BLOCK Srb
;
1886 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1888 Srb
= (PSCSI_REQUEST_BLOCK
) va_arg (ap
, PSCSI_REQUEST_BLOCK
);
1890 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb
);
1892 /* Make sure Srb is allright */
1893 ASSERT(Srb
->SrbStatus
!= SRB_STATUS_PENDING
);
1894 ASSERT(Srb
->Function
!= SRB_FUNCTION_EXECUTE_SCSI
|| Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
|| Srb
->ScsiStatus
== SCSISTAT_GOOD
);
1896 if (!(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
1898 /* It's been already completed */
1903 /* It's not active anymore */
1904 Srb
->SrbFlags
&= ~SRB_FLAGS_IS_ACTIVE
;
1906 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
1908 /* TODO: Treat it specially */
1913 /* Get the SRB data */
1914 SrbData
= SpiGetSrbData(DeviceExtension
,
1920 /* Make sure there are no CompletedRequests and there is a Srb */
1921 ASSERT(SrbData
->CompletedRequests
== NULL
&& SrbData
->Srb
!= NULL
);
1923 /* If it's a read/write request, make sure it has data inside it */
1924 if ((Srb
->SrbStatus
== SRB_STATUS_SUCCESS
) &&
1925 ((Srb
->Cdb
[0] == SCSIOP_READ
) || (Srb
->Cdb
[0] == SCSIOP_WRITE
)))
1927 ASSERT(Srb
->DataTransferLength
);
1930 SrbData
->CompletedRequests
= DeviceExtension
->InterruptData
.CompletedRequests
;
1931 DeviceExtension
->InterruptData
.CompletedRequests
= SrbData
;
1937 DPRINT("Notify: NextRequest\n");
1938 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1946 PSCSI_PORT_LUN_EXTENSION LunExtension
;
1948 PathId
= (UCHAR
) va_arg (ap
, int);
1949 TargetId
= (UCHAR
) va_arg (ap
, int);
1950 Lun
= (UCHAR
) va_arg (ap
, int);
1952 DPRINT("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1953 PathId
, TargetId
, Lun
);
1955 /* Mark it in the flags field */
1956 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1958 /* Get the LUN extension */
1959 LunExtension
= SpiGetLunExtension(DeviceExtension
,
1964 /* If returned LunExtension is NULL, break out */
1965 if (!LunExtension
) break;
1967 /* This request should not be processed if */
1968 if ((LunExtension
->ReadyLun
) ||
1969 (LunExtension
->SrbInfo
.Srb
))
1971 /* Nothing to do here */
1975 /* Add this LUN to the list */
1976 LunExtension
->ReadyLun
= DeviceExtension
->InterruptData
.ReadyLun
;
1977 DeviceExtension
->InterruptData
.ReadyLun
= LunExtension
;
1982 DPRINT("Notify: ResetDetected\n");
1983 /* Add RESET flags */
1984 DeviceExtension
->InterruptData
.Flags
|=
1985 SCSI_PORT_RESET
| SCSI_PORT_RESET_REPORTED
;
1988 case CallDisableInterrupts
:
1989 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
1992 case CallEnableInterrupts
:
1993 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
1996 case RequestTimerCall
:
1997 DPRINT("Notify: RequestTimerCall\n");
1998 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_TIMER_NEEDED
;
1999 DeviceExtension
->InterruptData
.HwScsiTimer
= (PHW_TIMER
)va_arg(ap
, PHW_TIMER
);
2000 DeviceExtension
->InterruptData
.MiniportTimerValue
= (ULONG
)va_arg(ap
, ULONG
);
2003 case BusChangeDetected
:
2004 DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
2008 DPRINT1 ("Unsupported notification from WMI: %lu\n", NotificationType
);
2014 /* Request a DPC after we're done with the interrupt */
2015 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NOTIFICATION_NEEDED
;
2022 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
2023 IN INTERFACE_TYPE BusType
,
2024 IN ULONG SystemIoBusNumber
,
2025 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
2026 IN ULONG NumberOfBytes
,
2027 IN BOOLEAN InIoSpace
)
2029 DPRINT("ScsiPortValidateRange()\n");
2034 /* INTERNAL FUNCTIONS ********************************************************/
2037 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
2038 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
2039 IN PPORT_CONFIGURATION_INFORMATION PortConfig
)
2041 PACCESS_RANGE AccessRange
;
2042 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData
;
2045 ULONG Interrupt
= 0;
2050 /* Loop through all entries */
2051 for (Index
= 0; Index
< ResourceDescriptor
->PartialResourceList
.Count
; Index
++)
2053 PartialData
= &ResourceDescriptor
->PartialResourceList
.PartialDescriptors
[Index
];
2055 switch (PartialData
->Type
)
2057 case CmResourceTypePort
:
2058 /* Copy access ranges */
2059 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
2061 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
2063 AccessRange
->RangeStart
= PartialData
->u
.Port
.Start
;
2064 AccessRange
->RangeLength
= PartialData
->u
.Port
.Length
;
2066 AccessRange
->RangeInMemory
= FALSE
;
2071 case CmResourceTypeMemory
:
2072 /* Copy access ranges */
2073 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
2075 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
2077 AccessRange
->RangeStart
= PartialData
->u
.Memory
.Start
;
2078 AccessRange
->RangeLength
= PartialData
->u
.Memory
.Length
;
2080 AccessRange
->RangeInMemory
= TRUE
;
2085 case CmResourceTypeInterrupt
:
2089 /* Copy interrupt data */
2090 PortConfig
->BusInterruptLevel
= PartialData
->u
.Interrupt
.Level
;
2091 PortConfig
->BusInterruptVector
= PartialData
->u
.Interrupt
.Vector
;
2093 /* Set interrupt mode accordingly to the resource */
2094 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
2096 PortConfig
->InterruptMode
= Latched
;
2098 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
2100 PortConfig
->InterruptMode
= LevelSensitive
;
2103 else if (Interrupt
== 1)
2105 /* Copy interrupt data */
2106 PortConfig
->BusInterruptLevel2
= PartialData
->u
.Interrupt
.Level
;
2107 PortConfig
->BusInterruptVector2
= PartialData
->u
.Interrupt
.Vector
;
2109 /* Set interrupt mode accordingly to the resource */
2110 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
2112 PortConfig
->InterruptMode2
= Latched
;
2114 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
2116 PortConfig
->InterruptMode2
= LevelSensitive
;
2123 case CmResourceTypeDma
:
2127 PortConfig
->DmaChannel
= PartialData
->u
.Dma
.Channel
;
2128 PortConfig
->DmaPort
= PartialData
->u
.Dma
.Port
;
2130 if (PartialData
->Flags
& CM_RESOURCE_DMA_8
)
2131 PortConfig
->DmaWidth
= Width8Bits
;
2132 else if ((PartialData
->Flags
& CM_RESOURCE_DMA_16
) ||
2133 (PartialData
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
2134 PortConfig
->DmaWidth
= Width16Bits
;
2135 else if (PartialData
->Flags
& CM_RESOURCE_DMA_32
)
2136 PortConfig
->DmaWidth
= Width32Bits
;
2140 PortConfig
->DmaChannel2
= PartialData
->u
.Dma
.Channel
;
2141 PortConfig
->DmaPort2
= PartialData
->u
.Dma
.Port
;
2143 if (PartialData
->Flags
& CM_RESOURCE_DMA_8
)
2144 PortConfig
->DmaWidth2
= Width8Bits
;
2145 else if ((PartialData
->Flags
& CM_RESOURCE_DMA_16
) ||
2146 (PartialData
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
2147 PortConfig
->DmaWidth2
= Width16Bits
;
2148 else if (PartialData
->Flags
& CM_RESOURCE_DMA_32
)
2149 PortConfig
->DmaWidth2
= Width32Bits
;
2156 static PCM_RESOURCE_LIST
2157 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2158 PPORT_CONFIGURATION_INFORMATION PortConfig
)
2160 PCONFIGURATION_INFORMATION ConfigInfo
;
2161 PCM_RESOURCE_LIST ResourceList
;
2162 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
2163 PACCESS_RANGE AccessRange
;
2164 ULONG ListLength
= 0, i
, FullSize
;
2165 ULONG Interrupt
, Dma
;
2167 /* Get current Atdisk usage from the system */
2168 ConfigInfo
= IoGetConfigurationInformation();
2170 if (PortConfig
->AtdiskPrimaryClaimed
)
2171 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
2173 if (PortConfig
->AtdiskSecondaryClaimed
)
2174 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
2176 /* Do we use DMA? */
2177 if (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
||
2178 PortConfig
->DmaPort
!= SP_UNINITIALIZED_VALUE
)
2182 if (PortConfig
->DmaChannel2
!= SP_UNINITIALIZED_VALUE
||
2183 PortConfig
->DmaPort2
!= SP_UNINITIALIZED_VALUE
)
2192 /* How many interrupts to we have? */
2193 Interrupt
= DeviceExtension
->InterruptCount
;
2194 ListLength
+= Interrupt
;
2196 /* How many access ranges do we use? */
2197 AccessRange
= &((*(PortConfig
->AccessRanges
))[0]);
2198 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2200 if (AccessRange
->RangeLength
!= 0)
2206 /* Allocate the resource list, since we know its size now */
2207 FullSize
= sizeof(CM_RESOURCE_LIST
) + (ListLength
- 1) *
2208 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
2210 ResourceList
= (PCM_RESOURCE_LIST
)ExAllocatePoolWithTag(PagedPool
, FullSize
, TAG_SCSIPORT
);
2216 RtlZeroMemory(ResourceList
, FullSize
);
2219 ResourceList
->Count
= 1;
2220 ResourceList
->List
[0].InterfaceType
= PortConfig
->AdapterInterfaceType
;
2221 ResourceList
->List
[0].BusNumber
= PortConfig
->SystemIoBusNumber
;
2222 ResourceList
->List
[0].PartialResourceList
.Count
= ListLength
;
2223 ResourceDescriptor
= ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
;
2225 /* Copy access ranges array over */
2226 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2228 AccessRange
= &((*(PortConfig
->AccessRanges
))[i
]);
2230 /* If the range is empty - skip it */
2231 if (AccessRange
->RangeLength
== 0)
2234 if (AccessRange
->RangeInMemory
)
2236 ResourceDescriptor
->Type
= CmResourceTypeMemory
;
2237 ResourceDescriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
;
2241 ResourceDescriptor
->Type
= CmResourceTypePort
;
2242 ResourceDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
2245 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2247 ResourceDescriptor
->u
.Memory
.Start
= AccessRange
->RangeStart
;
2248 ResourceDescriptor
->u
.Memory
.Length
= AccessRange
->RangeLength
;
2250 ResourceDescriptor
++;
2253 /* If we use interrupt(s), copy them */
2256 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2258 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2259 ((Interrupt
== 2) ? PortConfig
->InterruptMode2
: PortConfig
->InterruptMode
) == LevelSensitive
)
2261 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2262 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2266 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2267 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2270 ResourceDescriptor
->u
.Interrupt
.Level
= (Interrupt
== 2) ? PortConfig
->BusInterruptLevel2
: PortConfig
->BusInterruptLevel
;
2271 ResourceDescriptor
->u
.Interrupt
.Vector
= (Interrupt
== 2) ? PortConfig
->BusInterruptVector2
: PortConfig
->BusInterruptVector
;
2272 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2274 ResourceDescriptor
++;
2281 ResourceDescriptor
->Type
= CmResourceTypeDma
;
2282 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2283 ResourceDescriptor
->u
.Dma
.Channel
= (Dma
== 2) ? PortConfig
->DmaChannel2
: PortConfig
->DmaChannel
;
2284 ResourceDescriptor
->u
.Dma
.Port
= (Dma
== 2) ? PortConfig
->DmaPort2
: PortConfig
->DmaPort
;
2285 ResourceDescriptor
->Flags
= 0;
2287 if (((Dma
== 2) ? PortConfig
->DmaWidth2
: PortConfig
->DmaWidth
) == Width8Bits
)
2288 ResourceDescriptor
->Flags
|= CM_RESOURCE_DMA_8
;
2289 else if (((Dma
== 2) ? PortConfig
->DmaWidth2
: PortConfig
->DmaWidth
) == Width16Bits
)
2290 ResourceDescriptor
->Flags
|= CM_RESOURCE_DMA_16
;
2292 ResourceDescriptor
->Flags
|= CM_RESOURCE_DMA_32
;
2294 if (((Dma
== 2) ? PortConfig
->DmaChannel2
: PortConfig
->DmaChannel
) == SP_UNINITIALIZED_VALUE
)
2295 ResourceDescriptor
->u
.Dma
.Channel
= 0;
2297 if (((Dma
== 2) ? PortConfig
->DmaPort2
: PortConfig
->DmaPort
) == SP_UNINITIALIZED_VALUE
)
2298 ResourceDescriptor
->u
.Dma
.Port
= 0;
2300 ResourceDescriptor
++;
2304 return ResourceList
;
2309 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
2310 IN PDEVICE_OBJECT DeviceObject
,
2311 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
2312 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
2313 IN PUNICODE_STRING RegistryPath
,
2315 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
)
2317 PCI_COMMON_CONFIG PciConfig
;
2318 PCI_SLOT_NUMBER SlotNumber
;
2321 ULONG FunctionNumber
;
2322 CHAR VendorIdString
[8];
2323 CHAR DeviceIdString
[8];
2324 UNICODE_STRING UnicodeStr
;
2325 PCM_RESOURCE_LIST ResourceList
= NULL
;
2328 DPRINT ("SpiGetPciConfiguration() called\n");
2330 SlotNumber
.u
.AsULONG
= 0;
2332 /* Loop through all devices */
2333 for (DeviceNumber
= NextSlotNumber
->u
.bits
.DeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
2335 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
2337 /* Loop through all functions */
2338 for (FunctionNumber
= NextSlotNumber
->u
.bits
.FunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
2340 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
2342 /* Get PCI config bytes */
2343 DataSize
= HalGetBusData(PCIConfiguration
,
2345 SlotNumber
.u
.AsULONG
,
2349 /* If result of HalGetBusData is 0, then the bus is wrong */
2353 /* Check if result is PCI_INVALID_VENDORID or too small */
2354 if ((DataSize
< sizeof(ULONG
)) ||
2355 (PciConfig
.VendorID
== PCI_INVALID_VENDORID
))
2357 /* Continue to try the next function */
2361 sprintf (VendorIdString
, "%04hx", PciConfig
.VendorID
);
2362 sprintf (DeviceIdString
, "%04hx", PciConfig
.DeviceID
);
2364 if (_strnicmp(VendorIdString
, HwInitializationData
->VendorId
, HwInitializationData
->VendorIdLength
) ||
2365 _strnicmp(DeviceIdString
, HwInitializationData
->DeviceId
, HwInitializationData
->DeviceIdLength
))
2367 /* It is not our device */
2371 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2375 SlotNumber
.u
.bits
.DeviceNumber
,
2376 SlotNumber
.u
.bits
.FunctionNumber
);
2379 RtlInitUnicodeString(&UnicodeStr
, L
"ScsiAdapter");
2380 Status
= HalAssignSlotResources(RegistryPath
,
2386 SlotNumber
.u
.AsULONG
,
2389 if (!NT_SUCCESS(Status
))
2392 /* Create configuration information */
2393 SpiResourceToConfig(HwInitializationData
,
2397 /* Free the resource list */
2398 ExFreePool(ResourceList
);
2400 /* Set dev & fn numbers */
2401 NextSlotNumber
->u
.bits
.DeviceNumber
= DeviceNumber
;
2402 NextSlotNumber
->u
.bits
.FunctionNumber
= FunctionNumber
+ 1;
2404 /* Save the slot number */
2405 PortConfig
->SlotNumber
= SlotNumber
.u
.AsULONG
;
2409 NextSlotNumber
->u
.bits
.FunctionNumber
= 0;
2412 NextSlotNumber
->u
.bits
.DeviceNumber
= 0;
2413 DPRINT ("No device found\n");
2420 /**********************************************************************
2422 * ScsiPortCreateClose
2425 * Answer requests for Create/Close calls: a null operation.
2432 * Pointer to a device object.
2435 * Pointer to an IRP.
2441 static NTSTATUS NTAPI
2442 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
2445 DPRINT("ScsiPortCreateClose()\n");
2447 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2448 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2450 return STATUS_SUCCESS
;
2454 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2457 PSCSI_LUN_INFO LunInfo
;
2458 PIO_STACK_LOCATION IrpStack
;
2459 PDEVICE_OBJECT DeviceObject
;
2460 PSCSI_REQUEST_BLOCK Srb
;
2463 /* Get pointer to the SRB */
2464 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2465 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
2467 /* Check if PathId matches number of buses */
2468 if (DeviceExtension
->BusesConfig
== NULL
||
2469 DeviceExtension
->BusesConfig
->NumberOfBuses
<= Srb
->PathId
)
2471 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2472 return STATUS_DEVICE_DOES_NOT_EXIST
;
2475 /* Get pointer to LunInfo */
2476 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Srb
->PathId
]->LunInfo
;
2478 /* Find matching LunInfo */
2481 if (LunInfo
->PathId
== Srb
->PathId
&&
2482 LunInfo
->TargetId
== Srb
->TargetId
&&
2483 LunInfo
->Lun
== Srb
->Lun
)
2488 LunInfo
= LunInfo
->Next
;
2491 /* If we couldn't find it - exit */
2492 if (LunInfo
== NULL
)
2493 return STATUS_DEVICE_DOES_NOT_EXIST
;
2497 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2499 /* Release, if asked */
2500 if (Srb
->Function
== SRB_FUNCTION_RELEASE_DEVICE
)
2502 LunInfo
->DeviceClaimed
= FALSE
;
2503 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2504 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2506 return STATUS_SUCCESS
;
2509 /* Attach, if not already claimed */
2510 if (LunInfo
->DeviceClaimed
)
2512 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2513 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
2515 return STATUS_DEVICE_BUSY
;
2518 /* Save the device object */
2519 DeviceObject
= LunInfo
->DeviceObject
;
2521 if (Srb
->Function
== SRB_FUNCTION_CLAIM_DEVICE
)
2522 LunInfo
->DeviceClaimed
= TRUE
;
2524 if (Srb
->Function
== SRB_FUNCTION_ATTACH_DEVICE
)
2525 LunInfo
->DeviceObject
= Srb
->DataBuffer
;
2527 Srb
->DataBuffer
= DeviceObject
;
2529 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2530 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2532 return STATUS_SUCCESS
;
2536 /**********************************************************************
2538 * ScsiPortDispatchScsi
2541 * Answer requests for SCSI calls
2547 * Standard dispatch arguments
2553 static NTSTATUS NTAPI
2554 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
2557 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2558 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2559 PIO_STACK_LOCATION Stack
;
2560 PSCSI_REQUEST_BLOCK Srb
;
2562 NTSTATUS Status
= STATUS_SUCCESS
;
2563 PIRP NextIrp
, IrpList
;
2564 PKDEVICE_QUEUE_ENTRY Entry
;
2566 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2569 DeviceExtension
= DeviceObject
->DeviceExtension
;
2570 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2572 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2575 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2576 Status
= STATUS_UNSUCCESSFUL
;
2578 Irp
->IoStatus
.Status
= Status
;
2579 Irp
->IoStatus
.Information
= 0;
2581 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2586 DPRINT("Srb: %p\n", Srb
);
2587 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
2588 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
2590 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2594 if (LunExtension
== NULL
)
2596 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2597 Status
= STATUS_NO_SUCH_DEVICE
;
2599 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2600 Irp
->IoStatus
.Status
= Status
;
2601 Irp
->IoStatus
.Information
= 0;
2603 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2608 switch (Srb
->Function
)
2610 case SRB_FUNCTION_SHUTDOWN
:
2611 case SRB_FUNCTION_FLUSH
:
2612 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2613 if (DeviceExtension
->CachesData
== FALSE
)
2615 /* All success here */
2616 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2617 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2618 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2619 return STATUS_SUCCESS
;
2621 /* Fall through to a usual execute operation */
2623 case SRB_FUNCTION_EXECUTE_SCSI
:
2624 case SRB_FUNCTION_IO_CONTROL
:
2625 DPRINT(" SRB_FUNCTION_EXECUTE_SCSI or SRB_FUNCTION_IO_CONTROL\n");
2626 /* Mark IRP as pending in all cases */
2627 IoMarkIrpPending(Irp
);
2629 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2631 /* Start IO directly */
2632 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2638 /* We need to be at DISPATCH_LEVEL */
2639 KeRaiseIrql (DISPATCH_LEVEL
, &oldIrql
);
2641 /* Insert IRP into the queue */
2642 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
2643 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
2646 /* It means the queue is empty, and we just start this request */
2647 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2650 /* Back to the old IRQL */
2651 KeLowerIrql (oldIrql
);
2653 return STATUS_PENDING
;
2655 case SRB_FUNCTION_CLAIM_DEVICE
:
2656 case SRB_FUNCTION_ATTACH_DEVICE
:
2657 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2659 /* Reference device object and keep the device object */
2660 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2663 case SRB_FUNCTION_RELEASE_DEVICE
:
2664 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2666 /* Dereference device object and clear the device object */
2667 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2670 case SRB_FUNCTION_RELEASE_QUEUE
:
2671 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2673 /* Guard with the spinlock */
2674 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2676 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2678 DPRINT("Queue is not frozen really\n");
2680 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2681 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2682 Status
= STATUS_SUCCESS
;
2687 /* Unfreeze the queue */
2688 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2690 if (LunExtension
->SrbInfo
.Srb
== NULL
)
2692 /* Get next logical unit request */
2693 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
2695 /* SpiGetNextRequestFromLun() releases the spinlock */
2700 DPRINT("The queue has active request\n");
2701 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2705 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2706 Status
= STATUS_SUCCESS
;
2709 case SRB_FUNCTION_FLUSH_QUEUE
:
2710 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2712 /* Guard with the spinlock */
2713 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2715 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2717 DPRINT("Queue is not frozen really\n");
2719 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2720 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2724 /* Make sure there is no active request */
2725 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
2727 /* Compile a list from the device queue */
2729 while ((Entry
= KeRemoveDeviceQueue(&LunExtension
->DeviceQueue
)) != NULL
)
2731 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
2734 Stack
= IoGetCurrentIrpStackLocation(NextIrp
);
2735 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2738 Srb
->SrbStatus
= SRB_STATUS_REQUEST_FLUSHED
;
2739 NextIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2741 /* Add then to the list */
2742 NextIrp
->Tail
.Overlay
.ListEntry
.Flink
= (PLIST_ENTRY
)IrpList
;
2746 /* Unfreeze the queue */
2747 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2749 /* Release the spinlock */
2750 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2752 /* Complete those requests */
2756 IrpList
= (PIRP
)NextIrp
->Tail
.Overlay
.ListEntry
.Flink
;
2758 IoCompleteRequest(NextIrp
, 0);
2761 Status
= STATUS_SUCCESS
;
2765 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
2766 Status
= STATUS_NOT_IMPLEMENTED
;
2770 Irp
->IoStatus
.Status
= Status
;
2772 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2778 /**********************************************************************
2780 * ScsiPortDeviceControl
2783 * Answer requests for device control calls
2789 * Standard dispatch arguments
2795 static NTSTATUS NTAPI
2796 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
2799 PIO_STACK_LOCATION Stack
;
2800 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2801 PDUMP_POINTERS DumpPointers
;
2804 DPRINT("ScsiPortDeviceControl()\n");
2806 Irp
->IoStatus
.Information
= 0;
2808 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2809 DeviceExtension
= DeviceObject
->DeviceExtension
;
2811 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
2813 case IOCTL_SCSI_GET_DUMP_POINTERS
:
2814 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2816 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DUMP_POINTERS
))
2818 Status
= STATUS_BUFFER_OVERFLOW
;
2819 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2823 DumpPointers
= Irp
->AssociatedIrp
.SystemBuffer
;
2824 DumpPointers
->DeviceObject
= DeviceObject
;
2827 Status
= STATUS_SUCCESS
;
2828 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2831 case IOCTL_SCSI_GET_CAPABILITIES
:
2832 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2833 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
== sizeof(PVOID
))
2835 *((PVOID
*)Irp
->AssociatedIrp
.SystemBuffer
) = &DeviceExtension
->PortCapabilities
;
2837 Irp
->IoStatus
.Information
= sizeof(PVOID
);
2838 Status
= STATUS_SUCCESS
;
2842 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(IO_SCSI_CAPABILITIES
))
2844 Status
= STATUS_BUFFER_TOO_SMALL
;
2848 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2849 &DeviceExtension
->PortCapabilities
,
2850 sizeof(IO_SCSI_CAPABILITIES
));
2852 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
2853 Status
= STATUS_SUCCESS
;
2856 case IOCTL_SCSI_GET_INQUIRY_DATA
:
2857 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2859 /* Copy inquiry data to the port device extension */
2860 Status
= SpiGetInquiryData(DeviceExtension
, Irp
);
2863 case IOCTL_SCSI_MINIPORT
:
2864 DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
2865 Status
= STATUS_NOT_IMPLEMENTED
;
2868 case IOCTL_SCSI_PASS_THROUGH
:
2869 DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
2870 Status
= STATUS_NOT_IMPLEMENTED
;
2874 if ('M' == (Stack
->Parameters
.DeviceIoControl
.IoControlCode
>> 16)) {
2875 DPRINT1(" got ioctl intended for the mount manager: 0x%lX\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2877 DPRINT1(" unknown ioctl code: 0x%lX\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2879 Status
= STATUS_NOT_IMPLEMENTED
;
2883 /* Complete the request with the given status */
2884 Irp
->IoStatus
.Status
= Status
;
2885 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2892 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
2895 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2896 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2897 PIO_STACK_LOCATION IrpStack
;
2898 PSCSI_REQUEST_BLOCK Srb
;
2899 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2903 DPRINT("ScsiPortStartIo() called!\n");
2905 DeviceExtension
= DeviceObject
->DeviceExtension
;
2906 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2908 DPRINT("DeviceExtension %p\n", DeviceExtension
);
2910 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2912 /* Apply "default" flags */
2913 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
2915 /* Get LUN extension */
2916 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2921 if (DeviceExtension
->NeedSrbDataAlloc
||
2922 DeviceExtension
->NeedSrbExtensionAlloc
)
2925 SrbInfo
= SpiAllocateSrbStructures(DeviceExtension
,
2929 /* Couldn't alloc one or both data structures, return */
2930 if (SrbInfo
== NULL
)
2932 /* We have to call IoStartNextPacket, because this request
2934 if (LunExtension
->Flags
& LUNEX_REQUEST_PENDING
)
2935 IoStartNextPacket(DeviceObject
, FALSE
);
2942 /* No allocations are needed */
2943 SrbInfo
= &LunExtension
->SrbInfo
;
2944 Srb
->SrbExtension
= NULL
;
2945 Srb
->QueueTag
= SP_UNTAGGED
;
2948 /* Increase sequence number of SRB */
2949 if (!SrbInfo
->SequenceNumber
)
2951 /* Increase global sequence number */
2952 DeviceExtension
->SequenceNumber
++;
2955 SrbInfo
->SequenceNumber
= DeviceExtension
->SequenceNumber
;
2958 /* Check some special SRBs */
2959 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2961 /* Some special handling */
2962 DPRINT1("Abort command! Unimplemented now\n");
2969 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
)
2971 // Store the MDL virtual address in SrbInfo structure
2972 SrbInfo
->DataOffset
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2974 if (DeviceExtension
->MapBuffers
)
2976 /* Calculate offset within DataBuffer */
2977 SrbInfo
->DataOffset
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
2978 Srb
->DataBuffer
= SrbInfo
->DataOffset
+
2979 (ULONG
)((PUCHAR
)Srb
->DataBuffer
-
2980 (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2983 if (DeviceExtension
->AdapterObject
)
2986 KeFlushIoBuffers(Irp
->MdlAddress
,
2987 Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? TRUE
: FALSE
,
2991 if (DeviceExtension
->MapRegisters
)
2993 /* Calculate number of needed map registers */
2994 SrbInfo
->NumberOfMapRegisters
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
2996 Srb
->DataTransferLength
);
2998 /* Allocate adapter channel */
2999 Status
= IoAllocateAdapterChannel(DeviceExtension
->AdapterObject
,
3000 DeviceExtension
->DeviceObject
,
3001 SrbInfo
->NumberOfMapRegisters
,
3005 if (!NT_SUCCESS(Status
))
3007 DPRINT1("IoAllocateAdapterChannel() failed!\n");
3009 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
3010 ScsiPortNotification(RequestComplete
,
3011 DeviceExtension
+ 1,
3014 ScsiPortNotification(NextRequest
,
3015 DeviceExtension
+ 1);
3017 /* Request DPC for that work */
3018 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3021 /* Control goes to SpiAdapterControl */
3026 /* Increase active request counter */
3027 CounterResult
= InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
3029 if (CounterResult
== 0 &&
3030 DeviceExtension
->AdapterObject
!= NULL
&&
3031 !DeviceExtension
->MapRegisters
)
3033 IoAllocateAdapterChannel(
3034 DeviceExtension
->AdapterObject
,
3036 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
,
3037 ScsiPortAllocateAdapterChannel
,
3044 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3046 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
3047 ScsiPortStartPacket
,
3050 DPRINT("Synchronization failed!\n");
3052 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3053 Irp
->IoStatus
.Information
= 0;
3054 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3056 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3060 /* Release the spinlock only */
3061 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3065 DPRINT("ScsiPortStartIo() done\n");
3069 static BOOLEAN NTAPI
3070 ScsiPortStartPacket(IN OUT PVOID Context
)
3072 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3073 PIO_STACK_LOCATION IrpStack
;
3074 PSCSI_REQUEST_BLOCK Srb
;
3075 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)Context
;
3076 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3077 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3081 DPRINT("ScsiPortStartPacket() called\n");
3083 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3085 IrpStack
= IoGetCurrentIrpStackLocation(DeviceObject
->CurrentIrp
);
3086 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
3088 /* Get LUN extension */
3089 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3094 /* Check if we are in a reset state */
3095 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
3097 /* Mark the we've got requests while being in the reset state */
3098 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET_REQUEST
;
3102 /* Set the time out value */
3103 DeviceExtension
->TimerCount
= Srb
->TimeOutValue
;
3106 DeviceExtension
->Flags
|= SCSI_PORT_DEVICE_BUSY
;
3108 if (LunExtension
->RequestTimeout
!= -1)
3110 /* Timer already active */
3115 /* It hasn't been initialized yet */
3116 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
3120 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
3122 /* Handle bypass-requests */
3124 /* Is this an abort request? */
3125 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
3127 /* Get pointer to SRB info structure */
3128 SrbInfo
= SpiGetSrbData(DeviceExtension
,
3134 /* Check if the request is still "active" */
3135 if (SrbInfo
== NULL
||
3136 SrbInfo
->Srb
== NULL
||
3137 !(SrbInfo
->Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
3139 /* It's not, mark it as active then */
3140 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
3143 LunExtension
->RequestTimeout
= -1;
3145 DPRINT("Request has been already completed, but abort request came\n");
3146 Srb
->SrbStatus
= SRB_STATUS_ABORT_FAILED
;
3148 /* Notify about request complete */
3149 ScsiPortNotification(RequestComplete
,
3150 DeviceExtension
->MiniPortDeviceExtension
,
3153 /* and about readiness for the next request */
3154 ScsiPortNotification(NextRequest
,
3155 DeviceExtension
->MiniPortDeviceExtension
);
3157 /* They might ask for some work, so queue the DPC for them */
3158 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3160 /* We're done in this branch */
3166 /* Add number of queued requests */
3167 LunExtension
->QueueCount
++;
3170 /* Bypass requests don't need request sense */
3171 LunExtension
->Flags
&= ~LUNEX_NEED_REQUEST_SENSE
;
3173 /* Is disconnect disabled for this request? */
3174 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3176 /* Set the corresponding flag */
3177 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3180 /* Transfer timeout value from Srb to Lun */
3181 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
3185 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3187 /* It's a disconnect, so no more requests can go */
3188 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3191 LunExtension
->Flags
|= SCSI_PORT_LU_ACTIVE
;
3193 /* Increment queue count */
3194 LunExtension
->QueueCount
++;
3196 /* If it's tagged - special thing */
3197 if (Srb
->QueueTag
!= SP_UNTAGGED
)
3199 SrbInfo
= &DeviceExtension
->SrbInfo
[Srb
->QueueTag
- 1];
3201 /* Chek for consistency */
3202 ASSERT(SrbInfo
->Requests
.Blink
== NULL
);
3204 /* Insert it into the list of requests */
3205 InsertTailList(&LunExtension
->SrbInfo
.Requests
, &SrbInfo
->Requests
);
3209 /* Mark this Srb active */
3210 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
3212 /* Call HwStartIo routine */
3213 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
3216 /* If notification is needed, then request a DPC */
3217 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
3218 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3223 IO_ALLOCATION_ACTION
3225 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
,
3227 PVOID MapRegisterBase
,
3230 PSCSI_REQUEST_BLOCK Srb
;
3231 PSCSI_SG_ADDRESS ScatterGatherList
;
3233 PIO_STACK_LOCATION IrpStack
;
3234 ULONG TotalLength
= 0;
3235 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3236 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3238 BOOLEAN WriteToDevice
;
3240 /* Get pointers to SrbInfo and DeviceExtension */
3241 SrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)Context
;
3242 DeviceExtension
= DeviceObject
->DeviceExtension
;
3244 /* Get pointer to SRB */
3245 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3246 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
3248 /* Depending on the map registers number, we allocate
3249 either from NonPagedPool, or from our static list */
3250 if (SrbInfo
->NumberOfMapRegisters
> MAX_SG_LIST
)
3252 SrbInfo
->ScatterGather
= ExAllocatePoolWithTag(
3253 NonPagedPool
, SrbInfo
->NumberOfMapRegisters
* sizeof(SCSI_SG_ADDRESS
), TAG_SCSIPORT
);
3255 if (SrbInfo
->ScatterGather
== NULL
)
3258 Srb
->SrbFlags
|= SRB_FLAGS_SGLIST_FROM_POOL
;
3262 SrbInfo
->ScatterGather
= SrbInfo
->ScatterGatherList
;
3265 /* Use chosen SG list source */
3266 ScatterGatherList
= SrbInfo
->ScatterGather
;
3268 /* Save map registers base */
3269 SrbInfo
->BaseOfMapRegister
= MapRegisterBase
;
3271 /* Determine WriteToDevice flag */
3272 WriteToDevice
= Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
? TRUE
: FALSE
;
3274 /* Get virtual address of the data buffer */
3275 DataVA
= (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
3276 ((PCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
3278 /* Build the actual SG list */
3279 while (TotalLength
< Srb
->DataTransferLength
)
3281 if (!ScatterGatherList
)
3284 ScatterGatherList
->Length
= Srb
->DataTransferLength
- TotalLength
;
3285 ScatterGatherList
->PhysicalAddress
= IoMapTransfer(NULL
,
3288 DataVA
+ TotalLength
,
3289 &ScatterGatherList
->Length
,
3292 TotalLength
+= ScatterGatherList
->Length
;
3293 ScatterGatherList
++;
3296 /* Schedule an active request */
3297 InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
3298 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &CurrentIrql
);
3299 KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
3300 ScsiPortStartPacket
,
3302 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, CurrentIrql
);
3304 return DeallocateObjectKeepRegisters
;
3307 static PSCSI_PORT_LUN_EXTENSION
3308 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3310 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3311 ULONG LunExtensionSize
;
3313 DPRINT("SpiAllocateLunExtension (%p)\n",
3316 /* Round LunExtensionSize first to the sizeof LONGLONG */
3317 LunExtensionSize
= (DeviceExtension
->LunExtensionSize
+
3318 sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
3320 LunExtensionSize
+= sizeof(SCSI_PORT_LUN_EXTENSION
);
3321 DPRINT("LunExtensionSize %lu\n", LunExtensionSize
);
3323 LunExtension
= ExAllocatePoolWithTag(NonPagedPool
, LunExtensionSize
, TAG_SCSIPORT
);
3324 if (LunExtension
== NULL
)
3326 DPRINT1("Out of resources!\n");
3330 /* Zero everything */
3331 RtlZeroMemory(LunExtension
, LunExtensionSize
);
3333 /* Initialize a list of requests */
3334 InitializeListHead(&LunExtension
->SrbInfo
.Requests
);
3336 /* Initialize timeout counter */
3337 LunExtension
->RequestTimeout
= -1;
3339 /* Set maximum queue size */
3340 LunExtension
->MaxQueueCount
= 256;
3342 /* Initialize request queue */
3343 KeInitializeDeviceQueue (&LunExtension
->DeviceQueue
);
3345 return LunExtension
;
3348 static PSCSI_PORT_LUN_EXTENSION
3349 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3354 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3356 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3357 DeviceExtension
, PathId
, TargetId
, Lun
);
3359 /* Get appropriate list */
3360 LunExtension
= DeviceExtension
->LunExtensionList
[(TargetId
+ Lun
) % LUS_NUMBER
];
3362 /* Iterate it until we find what we need */
3363 while (LunExtension
)
3365 if (LunExtension
->TargetId
== TargetId
&&
3366 LunExtension
->Lun
== Lun
&&
3367 LunExtension
->PathId
== PathId
)
3369 /* All matches, return */
3370 return LunExtension
;
3373 /* Advance to the next item */
3374 LunExtension
= LunExtension
->Next
;
3377 /* We did not find anything */
3378 DPRINT("Nothing found\n");
3382 static PSCSI_REQUEST_BLOCK_INFO
3383 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3384 PSCSI_PORT_LUN_EXTENSION LunExtension
,
3385 PSCSI_REQUEST_BLOCK Srb
)
3388 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3390 /* Spinlock must be held while this function executes */
3391 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3393 /* Allocate SRB data structure */
3394 if (DeviceExtension
->NeedSrbDataAlloc
)
3396 /* Treat the abort request in a special way */
3397 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
3399 SrbInfo
= SpiGetSrbData(DeviceExtension
,
3405 else if (Srb
->SrbFlags
&
3406 (SRB_FLAGS_QUEUE_ACTION_ENABLE
| SRB_FLAGS_NO_QUEUE_FREEZE
) &&
3407 !(Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3410 /* Do not process tagged commands if need request sense is set */
3411 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
3413 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3415 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3416 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3418 /* Relese the spinlock and return */
3419 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3423 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
3424 SrbInfo
= DeviceExtension
->FreeSrbInfo
;
3426 if (SrbInfo
== NULL
)
3428 /* No SRB structures left in the list. We have to leave
3429 and wait while we are called again */
3431 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3432 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3436 DeviceExtension
->FreeSrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)SrbInfo
->Requests
.Flink
;
3438 /* QueueTag must never be 0, so +1 to it */
3439 Srb
->QueueTag
= (UCHAR
)(SrbInfo
- DeviceExtension
->SrbInfo
) + 1;
3443 /* Usual untagged command */
3445 (!IsListEmpty(&LunExtension
->SrbInfo
.Requests
) ||
3446 LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
) &&
3447 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
3450 /* Mark it as pending and leave */
3451 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3452 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3453 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3455 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3459 Srb
->QueueTag
= SP_UNTAGGED
;
3460 SrbInfo
= &LunExtension
->SrbInfo
;
3465 Srb
->QueueTag
= SP_UNTAGGED
;
3466 SrbInfo
= &LunExtension
->SrbInfo
;
3469 /* Allocate SRB extension structure */
3470 if (DeviceExtension
->NeedSrbExtensionAlloc
)
3472 /* Check the list of free extensions */
3473 SrbExtension
= DeviceExtension
->FreeSrbExtensions
;
3475 /* If no free extensions... */
3476 if (SrbExtension
== NULL
)
3479 if (Srb
->Function
!= SRB_FUNCTION_ABORT_COMMAND
&&
3480 Srb
->QueueTag
!= SP_UNTAGGED
)
3482 SrbInfo
->Requests
.Blink
= NULL
;
3483 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
3484 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
3487 /* Return, in order to be called again later */
3488 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3489 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3493 /* Remove that free SRB extension from the list (since
3494 we're going to use it) */
3495 DeviceExtension
->FreeSrbExtensions
= *((PVOID
*)SrbExtension
);
3497 /* Spinlock can be released now */
3498 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3500 Srb
->SrbExtension
= SrbExtension
;
3502 if (Srb
->SenseInfoBuffer
!= NULL
&&
3503 DeviceExtension
->SupportsAutoSense
)
3505 /* Store pointer to the SenseInfo buffer */
3506 SrbInfo
->SaveSenseRequest
= Srb
->SenseInfoBuffer
;
3508 /* Does data fit the buffer? */
3509 if (Srb
->SenseInfoBufferLength
> sizeof(SENSE_DATA
))
3511 /* No, disabling autosense at all */
3512 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_AUTOSENSE
;
3516 /* Yes, update the buffer pointer */
3517 Srb
->SenseInfoBuffer
= SrbExtension
+ DeviceExtension
->SrbExtensionSize
;
3524 Srb
->SrbExtension
= NULL
;
3525 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3533 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
3534 IN PSCSI_LUN_INFO LunInfo
)
3536 IO_STATUS_BLOCK IoStatusBlock
;
3537 PIO_STACK_LOCATION IrpStack
;
3542 PINQUIRYDATA InquiryBuffer
;
3543 PSENSE_DATA SenseBuffer
;
3544 BOOLEAN KeepTrying
= TRUE
;
3545 ULONG RetryCount
= 0;
3546 SCSI_REQUEST_BLOCK Srb
;
3548 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3549 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3551 DPRINT ("SpiSendInquiry() called\n");
3553 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3555 InquiryBuffer
= ExAllocatePoolWithTag (NonPagedPool
, INQUIRYDATABUFFERSIZE
, TAG_SCSIPORT
);
3556 if (InquiryBuffer
== NULL
)
3557 return STATUS_INSUFFICIENT_RESOURCES
;
3559 SenseBuffer
= ExAllocatePoolWithTag (NonPagedPool
, SENSE_BUFFER_SIZE
, TAG_SCSIPORT
);
3560 if (SenseBuffer
== NULL
)
3562 ExFreePool(InquiryBuffer
);
3563 return STATUS_INSUFFICIENT_RESOURCES
;
3568 /* Initialize event for waiting */
3569 KeInitializeEvent(&Event
,
3574 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN
,
3579 INQUIRYDATABUFFERSIZE
,
3585 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3586 return STATUS_INSUFFICIENT_RESOURCES
;
3590 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3592 Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
3593 Srb
.OriginalRequest
= Irp
;
3594 Srb
.PathId
= LunInfo
->PathId
;
3595 Srb
.TargetId
= LunInfo
->TargetId
;
3596 Srb
.Lun
= LunInfo
->Lun
;
3597 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3598 Srb
.SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3599 Srb
.TimeOutValue
= 4;
3602 Srb
.SenseInfoBuffer
= SenseBuffer
;
3603 Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3605 Srb
.DataBuffer
= InquiryBuffer
;
3606 Srb
.DataTransferLength
= INQUIRYDATABUFFERSIZE
;
3608 /* Attach Srb to the Irp */
3609 IrpStack
= IoGetNextIrpStackLocation (Irp
);
3610 IrpStack
->Parameters
.Scsi
.Srb
= &Srb
;
3613 Cdb
= (PCDB
)Srb
.Cdb
;
3614 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_INQUIRY
;
3615 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= LunInfo
->Lun
;
3616 Cdb
->CDB6INQUIRY
.AllocationLength
= INQUIRYDATABUFFERSIZE
;
3618 /* Call the driver */
3619 Status
= IoCallDriver(DeviceObject
, Irp
);
3621 /* Wait for it to complete */
3622 if (Status
== STATUS_PENDING
)
3624 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3625 KeWaitForSingleObject(&Event
,
3630 Status
= IoStatusBlock
.Status
;
3633 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status
);
3635 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_SUCCESS
)
3637 /* All fine, copy data over */
3638 RtlCopyMemory(LunInfo
->InquiryData
,
3640 INQUIRYDATABUFFERSIZE
);
3642 Status
= STATUS_SUCCESS
;
3647 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb
.SrbStatus
);
3648 /* Check if the queue is frozen */
3649 if (Srb
.SrbStatus
& SRB_STATUS_QUEUE_FROZEN
)
3651 /* Something weird happened, deal with it (unfreeze the queue) */
3654 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb
.TargetId
);
3656 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3661 /* Clear frozen flag */
3662 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
3664 /* Acquire the spinlock */
3665 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
3667 /* Process the request */
3668 SpiGetNextRequestFromLun(DeviceObject
->DeviceExtension
, LunExtension
);
3670 /* SpiGetNextRequestFromLun() releases the spinlock,
3671 so we just lower irql back to what it was before */
3675 /* Check if data overrun happened */
3676 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
3678 DPRINT("Data overrun at TargetId %d\n", LunInfo
->TargetId
);
3679 /* Nothing dramatic, just copy data, but limiting the size */
3680 RtlCopyMemory(LunInfo
->InquiryData
,
3682 (Srb
.DataTransferLength
> INQUIRYDATABUFFERSIZE
) ?
3683 INQUIRYDATABUFFERSIZE
: Srb
.DataTransferLength
);
3685 Status
= STATUS_SUCCESS
;
3688 else if ((Srb
.SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3689 SenseBuffer
->SenseKey
== SCSI_SENSE_ILLEGAL_REQUEST
)
3691 /* LUN is not valid, but some device responds there.
3692 Mark it as invalid anyway */
3694 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3699 /* Retry a couple of times if no timeout happened */
3700 if ((RetryCount
< 2) &&
3701 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_NO_DEVICE
) &&
3702 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_SELECTION_TIMEOUT
))
3709 /* That's all, go to exit */
3712 /* Set status according to SRB status */
3713 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_FUNCTION
||
3714 SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH
)
3716 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3720 Status
= STATUS_IO_DEVICE_ERROR
;
3728 ExFreePool(InquiryBuffer
);
3729 ExFreePool(SenseBuffer
);
3731 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status
);
3737 /* Scans all SCSI buses */
3739 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3741 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3745 PSCSI_BUS_SCAN_INFO BusScanInfo
;
3746 PSCSI_LUN_INFO LastLunInfo
, LunInfo
, LunInfoExists
;
3747 BOOLEAN DeviceExists
;
3752 DPRINT("SpiScanAdapter() called\n");
3754 /* Scan all buses */
3755 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
3757 DPRINT(" Scanning bus %d\n", Bus
);
3760 /* Get pointer to the scan information */
3761 BusScanInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
];
3765 /* Find the last LUN info in the list */
3766 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3767 LastLunInfo
= LunInfo
;
3769 while (LunInfo
!= NULL
)
3771 LastLunInfo
= LunInfo
;
3772 LunInfo
= LunInfo
->Next
;
3777 /* We need to allocate this buffer */
3778 BusScanInfo
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_BUS_SCAN_INFO
), TAG_SCSIPORT
);
3782 DPRINT1("Out of resources!\n");
3786 /* Store the pointer in the BusScanInfo array */
3787 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
] = BusScanInfo
;
3789 /* Fill this struct (length and bus ids for now) */
3790 BusScanInfo
->Length
= sizeof(SCSI_BUS_SCAN_INFO
);
3791 BusScanInfo
->LogicalUnitsCount
= 0;
3792 BusScanInfo
->BusIdentifier
= DeviceExtension
->PortConfig
->InitiatorBusId
[Bus
];
3793 BusScanInfo
->LunInfo
= NULL
;
3795 /* Set pointer to the last LUN info to NULL */
3799 /* Create LUN information structure */
3800 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3802 if (LunInfo
== NULL
)
3804 DPRINT1("Out of resources!\n");
3808 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3810 /* Create LunExtension */
3811 LunExtension
= SpiAllocateLunExtension (DeviceExtension
);
3813 /* And send INQUIRY to every target */
3814 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
3816 /* TODO: Support scan bottom-up */
3818 /* Skip if it's the same address */
3819 if (Target
== BusScanInfo
->BusIdentifier
)
3822 /* Try to find an existing device here */
3823 DeviceExists
= FALSE
;
3824 LunInfoExists
= BusScanInfo
->LunInfo
;
3826 /* Find matching address on this bus */
3827 while (LunInfoExists
)
3829 if (LunInfoExists
->TargetId
== Target
)
3831 DeviceExists
= TRUE
;
3835 /* Advance to the next one */
3836 LunInfoExists
= LunInfoExists
->Next
;
3839 /* No need to bother rescanning, since we already did that before */
3843 /* Scan all logical units */
3844 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
3846 if ((!LunExtension
) || (!LunInfo
))
3849 /* Add extension to the list */
3850 Hint
= (Target
+ Lun
) % LUS_NUMBER
;
3851 LunExtension
->Next
= DeviceExtension
->LunExtensionList
[Hint
];
3852 DeviceExtension
->LunExtensionList
[Hint
] = LunExtension
;
3854 /* Fill Path, Target, Lun fields */
3855 LunExtension
->PathId
= LunInfo
->PathId
= (UCHAR
)Bus
;
3856 LunExtension
->TargetId
= LunInfo
->TargetId
= (UCHAR
) Target
;
3857 LunExtension
->Lun
= LunInfo
->Lun
= (UCHAR
)Lun
;
3859 /* Set flag to prevent race conditions */
3860 LunExtension
->Flags
|= SCSI_PORT_SCAN_IN_PROGRESS
;
3862 /* Zero LU extension contents */
3863 if (DeviceExtension
->LunExtensionSize
)
3865 RtlZeroMemory(LunExtension
+ 1,
3866 DeviceExtension
->LunExtensionSize
);
3869 /* Finally send the inquiry command */
3870 Status
= SpiSendInquiry(DeviceExtension
->DeviceObject
, LunInfo
);
3872 if (NT_SUCCESS(Status
))
3874 /* Let's see if we really found a device */
3875 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3877 /* Check if this device is unsupported */
3878 if (InquiryData
->DeviceTypeQualifier
== DEVICE_QUALIFIER_NOT_SUPPORTED
)
3880 DeviceExtension
->LunExtensionList
[Hint
] =
3881 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3886 /* Clear the "in scan" flag */
3887 LunExtension
->Flags
&= ~SCSI_PORT_SCAN_IN_PROGRESS
;
3889 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3890 InquiryData
->DeviceType
, Bus
, Target
, Lun
);
3892 /* Add this info to the linked list */
3893 LunInfo
->Next
= NULL
;
3895 LastLunInfo
->Next
= LunInfo
;
3897 BusScanInfo
->LunInfo
= LunInfo
;
3899 /* Store the last LUN info */
3900 LastLunInfo
= LunInfo
;
3902 /* Store DeviceObject */
3903 LunInfo
->DeviceObject
= DeviceExtension
->DeviceObject
;
3905 /* Allocate another buffer */
3906 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3910 DPRINT1("Out of resources!\n");
3914 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3916 /* Create a new LU extension */
3917 LunExtension
= SpiAllocateLunExtension(DeviceExtension
);
3923 /* Remove this LUN from the list */
3924 DeviceExtension
->LunExtensionList
[Hint
] =
3925 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3927 /* Decide whether we are continuing or not */
3928 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
3936 /* Free allocated buffers */
3938 ExFreePool(LunExtension
);
3941 ExFreePool(LunInfo
);
3943 /* Sum what we found */
3944 BusScanInfo
->LogicalUnitsCount
+= (UCHAR
) DevicesFound
;
3945 DPRINT(" Found %d devices on bus %d\n", DevicesFound
, Bus
);
3948 DPRINT ("SpiScanAdapter() done\n");
3953 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3956 ULONG InquiryDataSize
;
3957 PSCSI_LUN_INFO LunInfo
;
3958 ULONG BusCount
, LunCount
, Length
;
3959 PIO_STACK_LOCATION IrpStack
;
3960 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
3961 PSCSI_INQUIRY_DATA InquiryData
;
3962 PSCSI_BUS_DATA BusData
;
3966 DPRINT("SpiGetInquiryData() called\n");
3968 /* Get pointer to the buffer */
3969 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3970 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3972 /* Initialize bus and LUN counters */
3973 BusCount
= DeviceExtension
->BusesConfig
->NumberOfBuses
;
3976 /* Calculate total number of LUNs */
3977 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3978 LunCount
+= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3980 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
3982 ((sizeof(SCSI_INQUIRY_DATA
) - 1 + INQUIRYDATABUFFERSIZE
+
3983 sizeof(ULONG
) - 1) & ~(sizeof(ULONG
) - 1));
3985 /* Calculate data size */
3986 Length
= sizeof(SCSI_ADAPTER_BUS_INFO
) + (BusCount
- 1) *
3987 sizeof(SCSI_BUS_DATA
);
3989 Length
+= InquiryDataSize
* LunCount
;
3991 /* Check, if all data is going to fit into provided buffer */
3992 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< Length
)
3994 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3995 return STATUS_BUFFER_TOO_SMALL
;
3998 /* Store data size in the IRP */
3999 Irp
->IoStatus
.Information
= Length
;
4001 DPRINT("Data size: %lu\n", Length
);
4003 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
4005 AdapterBusInfo
->NumberOfBuses
= (UCHAR
)BusCount
;
4007 /* Point InquiryData to the corresponding place inside Buffer */
4008 InquiryData
= (PSCSI_INQUIRY_DATA
)(Buffer
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
4009 (BusCount
- 1) * sizeof(SCSI_BUS_DATA
));
4012 for (Bus
= 0; Bus
< BusCount
; Bus
++)
4014 BusData
= &AdapterBusInfo
->BusData
[Bus
];
4016 /* Calculate and save an offset of the inquiry data */
4017 BusData
->InquiryDataOffset
= (ULONG
)((PUCHAR
)InquiryData
- Buffer
);
4019 /* Get a pointer to the LUN information structure */
4020 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
4022 /* Store Initiator Bus Id */
4023 BusData
->InitiatorBusId
=
4024 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->BusIdentifier
;
4026 /* Store LUN count */
4027 BusData
->NumberOfLogicalUnits
=
4028 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
4031 while (LunInfo
!= NULL
)
4033 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
4034 Bus
, LunInfo
->TargetId
, LunInfo
->Lun
);
4036 /* Fill InquiryData with values */
4037 InquiryData
->PathId
= LunInfo
->PathId
;
4038 InquiryData
->TargetId
= LunInfo
->TargetId
;
4039 InquiryData
->Lun
= LunInfo
->Lun
;
4040 InquiryData
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
4041 InquiryData
->DeviceClaimed
= LunInfo
->DeviceClaimed
;
4042 InquiryData
->NextInquiryDataOffset
=
4043 (ULONG
)((PUCHAR
)InquiryData
+ InquiryDataSize
- Buffer
);
4045 /* Copy data in it */
4046 RtlCopyMemory(InquiryData
->InquiryData
,
4047 LunInfo
->InquiryData
,
4048 INQUIRYDATABUFFERSIZE
);
4050 /* Move to the next LUN */
4051 LunInfo
= LunInfo
->Next
;
4052 InquiryData
= (PSCSI_INQUIRY_DATA
) ((PCHAR
)InquiryData
+ InquiryDataSize
);
4055 /* Either mark the end, or set offset to 0 */
4056 if (BusData
->NumberOfLogicalUnits
!= 0)
4057 ((PSCSI_INQUIRY_DATA
) ((PCHAR
) InquiryData
- InquiryDataSize
))->NextInquiryDataOffset
= 0;
4059 BusData
->InquiryDataOffset
= 0;
4062 /* Finish with success */
4063 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4064 return STATUS_SUCCESS
;
4067 static PSCSI_REQUEST_BLOCK_INFO
4068 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4074 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4076 if (QueueTag
== SP_UNTAGGED
)
4078 /* Untagged request, get LU and return pointer to SrbInfo */
4079 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4084 /* Return NULL in case of error */
4088 /* Return the pointer to SrbInfo */
4089 return &LunExtension
->SrbInfo
;
4093 /* Make sure the tag is valid, if it is - return the data */
4094 if (QueueTag
> DeviceExtension
->SrbDataCount
|| QueueTag
< 1)
4097 return &DeviceExtension
->SrbInfo
[QueueTag
-1];
4102 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4103 IN PSCSI_REQUEST_BLOCK InitialSrb
)
4105 PSCSI_REQUEST_BLOCK Srb
;
4108 PIO_STACK_LOCATION IrpStack
;
4109 LARGE_INTEGER LargeInt
;
4112 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb
);
4115 Srb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
) + sizeof(PVOID
), TAG_SCSIPORT
);
4116 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
4119 LargeInt
.QuadPart
= (LONGLONG
) 1;
4120 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_READ
,
4121 DeviceExtension
->DeviceObject
,
4122 InitialSrb
->SenseInfoBuffer
,
4123 InitialSrb
->SenseInfoBufferLength
,
4127 IoSetCompletionRoutine(Irp
,
4128 (PIO_COMPLETION_ROUTINE
)SpiCompletionRoutine
,
4136 DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb
);
4140 IrpStack
= IoGetNextIrpStackLocation(Irp
);
4141 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
4143 /* Put Srb address into Irp... */
4144 IrpStack
->Parameters
.Others
.Argument1
= (PVOID
)Srb
;
4146 /* ...and vice versa */
4147 Srb
->OriginalRequest
= Irp
;
4150 Ptr
= (PVOID
*)(Srb
+1);
4153 /* Build CDB for REQUEST SENSE */
4155 Cdb
= (PCDB
)Srb
->Cdb
;
4157 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
4158 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= 0;
4159 Cdb
->CDB6INQUIRY
.Reserved1
= 0;
4160 Cdb
->CDB6INQUIRY
.PageCode
= 0;
4161 Cdb
->CDB6INQUIRY
.IReserved
= 0;
4162 Cdb
->CDB6INQUIRY
.AllocationLength
= (UCHAR
)InitialSrb
->SenseInfoBufferLength
;
4163 Cdb
->CDB6INQUIRY
.Control
= 0;
4166 Srb
->TargetId
= InitialSrb
->TargetId
;
4167 Srb
->Lun
= InitialSrb
->Lun
;
4168 Srb
->PathId
= InitialSrb
->PathId
;
4170 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4171 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
4173 /* Timeout will be 2 seconds */
4174 Srb
->TimeOutValue
= 2;
4176 /* No auto request sense */
4177 Srb
->SenseInfoBufferLength
= 0;
4178 Srb
->SenseInfoBuffer
= NULL
;
4180 /* Set necessary flags */
4181 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_BYPASS_FROZEN_QUEUE
|
4182 SRB_FLAGS_DISABLE_DISCONNECT
;
4184 /* Transfer disable synch transfer flag */
4185 if (InitialSrb
->SrbFlags
& SRB_FLAGS_DISABLE_SYNCH_TRANSFER
)
4186 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4188 Srb
->DataBuffer
= InitialSrb
->SenseInfoBuffer
;
4190 /* Fill the transfer length */
4191 Srb
->DataTransferLength
= InitialSrb
->SenseInfoBufferLength
;
4193 /* Clear statuses */
4194 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
4197 /* Call the driver */
4198 (VOID
)IoCallDriver(DeviceExtension
->DeviceObject
, Irp
);
4200 DPRINT("SpiSendRequestSense() done\n");
4207 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4208 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
4209 OUT PBOOLEAN NeedToCallStartIo
)
4211 PSCSI_REQUEST_BLOCK Srb
;
4212 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4215 //ULONG SequenceNumber;
4218 Irp
= Srb
->OriginalRequest
;
4220 /* Get Lun extension */
4221 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4226 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
&&
4227 DeviceExtension
->MapBuffers
&&
4230 /* MDL is shared if transfer is broken into smaller parts */
4231 Srb
->DataBuffer
= (PCCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
4232 ((PCCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
4234 /* In case of data going in, flush the buffers */
4235 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
4237 KeFlushIoBuffers(Irp
->MdlAddress
,
4243 /* Flush adapter if needed */
4244 if (SrbInfo
->BaseOfMapRegister
)
4246 /* TODO: Implement */
4250 /* Clear the request */
4251 SrbInfo
->Srb
= NULL
;
4253 /* If disconnect is disabled... */
4254 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
4256 /* Acquire the spinlock since we mess with flags */
4257 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4259 /* Set corresponding flag */
4260 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
4262 /* Clear the timer if needed */
4263 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
))
4264 DeviceExtension
->TimerCount
= -1;
4266 /* Spinlock is not needed anymore */
4267 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4269 if (!(DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
) &&
4270 !(DeviceExtension
->Flags
& SCSI_PORT_DEVICE_BUSY
) &&
4271 !(*NeedToCallStartIo
))
4273 /* We're not busy, but we have a request pending */
4274 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4278 /* Scatter/gather */
4279 if (Srb
->SrbFlags
& SRB_FLAGS_SGLIST_FROM_POOL
)
4281 /* TODO: Implement */
4285 /* Acquire spinlock (we're freeing SrbExtension) */
4286 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4288 /* Free it (if needed) */
4289 if (Srb
->SrbExtension
)
4291 if (Srb
->SenseInfoBuffer
!= NULL
&& DeviceExtension
->SupportsAutoSense
)
4293 ASSERT(Srb
->SenseInfoBuffer
== NULL
|| SrbInfo
->SaveSenseRequest
!= NULL
);
4295 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)
4297 /* Copy sense data to the buffer */
4298 RtlCopyMemory(SrbInfo
->SaveSenseRequest
,
4299 Srb
->SenseInfoBuffer
,
4300 Srb
->SenseInfoBufferLength
);
4303 /* And restore the pointer */
4304 Srb
->SenseInfoBuffer
= SrbInfo
->SaveSenseRequest
;
4307 /* Put it into the free srb extensions list */
4308 *((PVOID
*)Srb
->SrbExtension
) = DeviceExtension
->FreeSrbExtensions
;
4309 DeviceExtension
->FreeSrbExtensions
= Srb
->SrbExtension
;
4312 /* Save transfer length in the IRP */
4313 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
4315 //SequenceNumber = SrbInfo->SequenceNumber;
4316 SrbInfo
->SequenceNumber
= 0;
4318 /* Decrement the queue count */
4319 LunExtension
->QueueCount
--;
4321 /* Free Srb, if needed*/
4322 if (Srb
->QueueTag
!= SP_UNTAGGED
)
4324 /* Put it into the free list */
4325 SrbInfo
->Requests
.Blink
= NULL
;
4326 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
4327 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
4330 /* SrbInfo is not used anymore */
4333 if (DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
)
4335 /* Clear the flag */
4336 DeviceExtension
->Flags
&= ~SCSI_PORT_REQUEST_PENDING
;
4338 /* Note the caller about StartIo */
4339 *NeedToCallStartIo
= TRUE
;
4342 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
4344 /* Start the packet */
4345 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4347 if (!(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
) &&
4348 LunExtension
->RequestTimeout
== -1)
4350 /* Start the next packet */
4351 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4355 /* Release the spinlock */
4356 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4359 DPRINT("IoCompleting request IRP 0x%p\n", Irp
);
4361 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4363 /* Decrement number of active requests, and analyze the result */
4364 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4367 !DeviceExtension
->MapRegisters
&&
4368 DeviceExtension
->AdapterObject
!= NULL
)
4370 /* Nullify map registers */
4371 DeviceExtension
->MapRegisterBase
= NULL
;
4372 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4375 /* Exit, we're done */
4379 /* Decrement number of active requests, and analyze the result */
4380 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4383 !DeviceExtension
->MapRegisters
&&
4384 DeviceExtension
->AdapterObject
!= NULL
)
4386 /* Result is negative, so this is a slave, free map registers */
4387 DeviceExtension
->MapRegisterBase
= NULL
;
4388 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4391 /* Convert status */
4392 Irp
->IoStatus
.Status
= SpiStatusSrbToNt(Srb
->SrbStatus
);
4394 /* It's not a bypass, it's busy or the queue is full? */
4395 if ((Srb
->ScsiStatus
== SCSISTAT_BUSY
||
4396 Srb
->SrbStatus
== SRB_STATUS_BUSY
||
4397 Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
) &&
4398 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
))
4401 DPRINT("Busy SRB status %x\n", Srb
->SrbStatus
);
4403 /* Requeu, if needed */
4404 if (LunExtension
->Flags
& (LUNEX_FROZEN_QUEUE
| LUNEX_BUSY
))
4406 DPRINT("it's being requeued\n");
4408 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4409 Srb
->ScsiStatus
= 0;
4411 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4412 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
4415 /* It's a big f.ck up if we got here */
4416 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
4417 Srb
->ScsiStatus
= SCSISTAT_BUSY
;
4423 /* Release the spinlock */
4424 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4427 else if (LunExtension
->AttemptCount
++ < 20)
4429 /* LUN is still busy */
4430 Srb
->ScsiStatus
= 0;
4431 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4433 LunExtension
->BusyRequest
= Irp
;
4434 LunExtension
->Flags
|= LUNEX_BUSY
;
4436 /* Release the spinlock */
4437 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4442 /* Freeze the queue*/
4443 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4444 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4446 /* "Unfull" the queue */
4447 LunExtension
->Flags
&= ~LUNEX_FULL_QUEUE
;
4449 /* Release the spinlock */
4450 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4452 /* Return status that the device is not ready */
4453 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
4454 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4460 /* Start the next request, if LUN is idle, and this is sense request */
4461 if (((Srb
->ScsiStatus
!= SCSISTAT_CHECK_CONDITION
) ||
4462 (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) ||
4463 !Srb
->SenseInfoBuffer
|| !Srb
->SenseInfoBufferLength
)
4464 && (Srb
->SrbFlags
& SRB_FLAGS_NO_QUEUE_FREEZE
))
4466 if (LunExtension
->RequestTimeout
== -1)
4467 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4469 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4473 /* Freeze the queue */
4474 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4475 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4477 /* Do we need a request sense? */
4478 if (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4479 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
4480 Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
)
4482 /* If LUN is busy, we have to requeue it in order to allow request sense */
4483 if (LunExtension
->Flags
& LUNEX_BUSY
)
4485 DPRINT("Requeueing busy request to allow request sense\n");
4487 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4488 &LunExtension
->BusyRequest
->Tail
.Overlay
.DeviceQueueEntry
,
4491 /* We should never get here */
4494 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4495 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4500 /* Clear busy flags */
4501 LunExtension
->Flags
&= ~(LUNEX_FULL_QUEUE
| LUNEX_BUSY
);
4504 /* Release the spinlock */
4505 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4507 /* Send RequestSense */
4508 SpiSendRequestSense(DeviceExtension
, Srb
);
4514 /* Release the spinlock */
4515 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4518 /* Complete the request */
4519 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4524 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
4528 PSCSI_REQUEST_BLOCK Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
4529 PSCSI_REQUEST_BLOCK InitialSrb
;
4532 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp
);
4534 if ((Srb
->Function
== SRB_FUNCTION_RESET_BUS
) ||
4535 (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
))
4537 /* Deallocate SRB and IRP and exit */
4541 return STATUS_MORE_PROCESSING_REQUIRED
;
4544 /* Get a pointer to the SRB and IRP which were initially sent */
4545 InitialSrb
= *((PVOID
*)(Srb
+1));
4546 InitialIrp
= InitialSrb
->OriginalRequest
;
4548 if ((SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
) ||
4549 (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_DATA_OVERRUN
))
4551 /* Sense data is OK */
4552 InitialSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
4554 /* Set length to be the same */
4555 InitialSrb
->SenseInfoBufferLength
= (UCHAR
)Srb
->DataTransferLength
;
4558 /* Make sure initial SRB's queue is frozen */
4559 ASSERT(InitialSrb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
);
4561 /* Complete this request */
4562 IoCompleteRequest(InitialIrp
, IO_DISK_INCREMENT
);
4564 /* Deallocate everything (internal) */
4567 if (Irp
->MdlAddress
!= NULL
)
4569 MmUnlockPages(Irp
->MdlAddress
);
4570 IoFreeMdl(Irp
->MdlAddress
);
4571 Irp
->MdlAddress
= NULL
;
4575 return STATUS_MORE_PROCESSING_REQUIRED
;
4578 static BOOLEAN NTAPI
4579 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
4580 IN PVOID ServiceContext
)
4582 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4584 DPRINT("ScsiPortIsr() called!\n");
4586 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
4588 /* If interrupts are disabled - we don't expect any */
4589 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_DISABLE_INTERRUPTS
)
4592 /* Call miniport's HwInterrupt routine */
4593 if (DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
) == FALSE
)
4595 /* This interrupt doesn't belong to us */
4599 /* If flag of notification is set - queue a DPC */
4600 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4602 IoRequestDpc(DeviceExtension
->DeviceObject
,
4603 DeviceExtension
->CurrentIrp
,
4612 SpiSaveInterruptData(IN PVOID Context
)
4614 PSCSI_PORT_SAVE_INTERRUPT InterruptContext
= Context
;
4615 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4616 PSCSI_REQUEST_BLOCK Srb
;
4617 PSCSI_REQUEST_BLOCK_INFO SrbInfo
, NextSrbInfo
;
4618 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4621 /* Get pointer to the device extension */
4622 DeviceExtension
= InterruptContext
->DeviceExtension
;
4624 /* If we don't have anything pending - return */
4625 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
))
4628 /* Actually save the interrupt data */
4629 *InterruptContext
->InterruptData
= DeviceExtension
->InterruptData
;
4631 /* Clear the data stored in the device extension */
4632 DeviceExtension
->InterruptData
.Flags
&=
4633 (SCSI_PORT_RESET
| SCSI_PORT_RESET_REQUEST
| SCSI_PORT_DISABLE_INTERRUPTS
);
4634 DeviceExtension
->InterruptData
.CompletedAbort
= NULL
;
4635 DeviceExtension
->InterruptData
.ReadyLun
= NULL
;
4636 DeviceExtension
->InterruptData
.CompletedRequests
= NULL
;
4638 /* Loop through the list of completed requests */
4639 SrbInfo
= InterruptContext
->InterruptData
->CompletedRequests
;
4643 /* Make sure we have SRV */
4644 ASSERT(SrbInfo
->Srb
);
4646 /* Get SRB and LunExtension */
4649 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4654 /* We have to check special cases if request is unsuccessfull*/
4655 if (Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
)
4657 /* Check if we need request sense by a few conditions */
4658 if (Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
&&
4659 Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4660 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
))
4662 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
4664 /* It means: we tried to send REQUEST SENSE, but failed */
4666 Srb
->ScsiStatus
= 0;
4667 Srb
->SrbStatus
= SRB_STATUS_REQUEST_SENSE_FAILED
;
4671 /* Set the corresponding flag, so that REQUEST SENSE
4673 LunExtension
->Flags
|= LUNEX_NEED_REQUEST_SENSE
;
4678 /* Check for a full queue */
4679 if (Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
)
4681 /* TODO: Implement when it's encountered */
4686 /* Let's decide if we need to watch timeout or not */
4687 if (Srb
->QueueTag
== SP_UNTAGGED
)
4693 if (LunExtension
->SrbInfo
.Requests
.Flink
== &SrbInfo
->Requests
)
4698 /* Remove it from the queue */
4699 RemoveEntryList(&SrbInfo
->Requests
);
4704 /* We have to maintain timeout counter */
4705 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
))
4707 LunExtension
->RequestTimeout
= -1;
4711 NextSrbInfo
= CONTAINING_RECORD(LunExtension
->SrbInfo
.Requests
.Flink
,
4712 SCSI_REQUEST_BLOCK_INFO
,
4715 Srb
= NextSrbInfo
->Srb
;
4717 /* Update timeout counter */
4718 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
4722 SrbInfo
= SrbInfo
->CompletedRequests
;
4730 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4731 IN PSCSI_PORT_LUN_EXTENSION LunExtension
)
4733 PIO_STACK_LOCATION IrpStack
;
4735 PKDEVICE_QUEUE_ENTRY Entry
;
4736 PSCSI_REQUEST_BLOCK Srb
;
4739 /* If LUN is not active or queue is more than maximum allowed */
4740 if (LunExtension
->QueueCount
>= LunExtension
->MaxQueueCount
||
4741 !(LunExtension
->Flags
& SCSI_PORT_LU_ACTIVE
))
4743 /* Release the spinlock and exit */
4744 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4748 /* Check if we can get a next request */
4749 if (LunExtension
->Flags
&
4750 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_BUSY
|
4751 LUNEX_FULL_QUEUE
| LUNEX_FROZEN_QUEUE
| LUNEX_REQUEST_PENDING
))
4753 /* Pending requests can only be started if the queue is empty */
4754 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
) &&
4755 !(LunExtension
->Flags
&
4756 (LUNEX_BUSY
| LUNEX_FROZEN_QUEUE
| LUNEX_FULL_QUEUE
| LUNEX_NEED_REQUEST_SENSE
)))
4758 /* Make sure we have SRB */
4759 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
4761 /* Clear active and pending flags */
4762 LunExtension
->Flags
&= ~(LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
);
4764 /* Get next Irp, and clear pending requests list */
4765 NextIrp
= LunExtension
->PendingRequest
;
4766 LunExtension
->PendingRequest
= NULL
;
4768 /* Set attempt counter to zero */
4769 LunExtension
->AttemptCount
= 0;
4771 /* Release the spinlock */
4772 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4774 /* Start the next pending request */
4775 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4781 /* Release the spinlock, without clearing any flags and exit */
4782 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4788 /* Reset active flag */
4789 LunExtension
->Flags
&= ~SCSI_PORT_LU_ACTIVE
;
4791 /* Set attempt counter to zero */
4792 LunExtension
->AttemptCount
= 0;
4794 /* Remove packet from the device queue */
4795 Entry
= KeRemoveByKeyDeviceQueue(&LunExtension
->DeviceQueue
, LunExtension
->SortKey
);
4799 /* Get pointer to the next irp */
4800 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
4802 /* Get point to the SRB */
4803 IrpStack
= IoGetCurrentIrpStackLocation(NextIrp
);
4804 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
4807 LunExtension
->SortKey
= Srb
->QueueSortKey
;
4808 LunExtension
->SortKey
++;
4810 /* Release the spinlock */
4811 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4813 /* Start the next pending request */
4814 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4818 /* Release the spinlock */
4819 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4825 // ScsiPortDpcForIsr
4832 // IN PDEVICE_OBJECT DpcDeviceObject
4834 // IN PVOID DpcContext
4837 ScsiPortDpcForIsr(IN PKDPC Dpc
,
4838 IN PDEVICE_OBJECT DpcDeviceObject
,
4840 IN PVOID DpcContext
)
4842 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DpcDeviceObject
->DeviceExtension
;
4843 SCSI_PORT_INTERRUPT_DATA InterruptData
;
4844 SCSI_PORT_SAVE_INTERRUPT Context
;
4845 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4846 BOOLEAN NeedToStartIo
;
4847 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
4848 LARGE_INTEGER TimerValue
;
4850 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4851 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
4853 /* We need to acquire spinlock */
4854 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4856 RtlZeroMemory(&InterruptData
, sizeof(SCSI_PORT_INTERRUPT_DATA
));
4860 /* Interrupt structure must be snapshotted, and only then analyzed */
4861 Context
.InterruptData
= &InterruptData
;
4862 Context
.DeviceExtension
= DeviceExtension
;
4864 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
4865 SpiSaveInterruptData
,
4868 /* Nothing - just return (don't forget to release the spinlock */
4869 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4870 DPRINT("ScsiPortDpcForIsr() done\n");
4874 /* If flush of adapters is needed - do it */
4875 if (InterruptData
.Flags
& SCSI_PORT_FLUSH_ADAPTERS
)
4877 /* TODO: Implement */
4881 /* Check for IoMapTransfer */
4882 if (InterruptData
.Flags
& SCSI_PORT_MAP_TRANSFER
)
4884 /* TODO: Implement */
4888 /* Check if timer is needed */
4889 if (InterruptData
.Flags
& SCSI_PORT_TIMER_NEEDED
)
4891 /* Save the timer routine */
4892 DeviceExtension
->HwScsiTimer
= InterruptData
.HwScsiTimer
;
4894 if (InterruptData
.MiniportTimerValue
== 0)
4896 /* Cancel the timer */
4897 KeCancelTimer(&DeviceExtension
->MiniportTimer
);
4901 /* Convert timer value */
4902 TimerValue
.QuadPart
= Int32x32To64(InterruptData
.MiniportTimerValue
, -10);
4905 KeSetTimer(&DeviceExtension
->MiniportTimer
,
4907 &DeviceExtension
->MiniportTimerDpc
);
4911 /* If it's ready for the next request */
4912 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4914 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4915 if ((DeviceExtension
->Flags
&
4916 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
)) ==
4917 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
))
4919 /* Clear busy flag set by ScsiPortStartPacket() */
4920 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4922 if (!(InterruptData
.Flags
& SCSI_PORT_RESET
))
4924 /* Ready for next, and no reset is happening */
4925 DeviceExtension
->TimerCount
= -1;
4930 /* Not busy, but not ready for the next request */
4931 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4932 InterruptData
.Flags
&= ~SCSI_PORT_NEXT_REQUEST_READY
;
4937 if (InterruptData
.Flags
& SCSI_PORT_RESET_REPORTED
)
4939 /* Hold for a bit */
4940 DeviceExtension
->TimerCount
= 4;
4943 /* Any ready LUN? */
4944 if (InterruptData
.ReadyLun
!= NULL
)
4947 /* Process all LUNs from the list*/
4950 /* Remove it from the list first (as processed) */
4951 LunExtension
= InterruptData
.ReadyLun
;
4952 InterruptData
.ReadyLun
= LunExtension
->ReadyLun
;
4953 LunExtension
->ReadyLun
= NULL
;
4955 /* Get next request for this LUN */
4956 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4958 /* Still ready requests exist?
4959 If yes - get spinlock, if no - stop here */
4960 if (InterruptData
.ReadyLun
!= NULL
)
4961 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4968 /* Release the spinlock */
4969 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4972 /* If we ready for next packet, start it */
4973 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4974 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4976 NeedToStartIo
= FALSE
;
4978 /* Loop the completed request list */
4979 while (InterruptData
.CompletedRequests
)
4981 /* Remove the request */
4982 SrbInfo
= InterruptData
.CompletedRequests
;
4983 InterruptData
.CompletedRequests
= SrbInfo
->CompletedRequests
;
4984 SrbInfo
->CompletedRequests
= NULL
;
4987 SpiProcessCompletedRequest(DeviceExtension
,
4992 /* Loop abort request list */
4993 while (InterruptData
.CompletedAbort
)
4995 LunExtension
= InterruptData
.CompletedAbort
;
4997 /* Remove the request */
4998 InterruptData
.CompletedAbort
= LunExtension
->CompletedAbortRequests
;
5000 /* Get spinlock since we're going to change flags */
5001 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5003 /* TODO: Put SrbExtension to the list of free extensions */
5007 /* If we need - call StartIo routine */
5010 /* Make sure CurrentIrp is not null! */
5011 ASSERT(DpcDeviceObject
->CurrentIrp
!= NULL
);
5012 ScsiPortStartIo(DpcDeviceObject
, DpcDeviceObject
->CurrentIrp
);
5015 /* Everything has been done, check */
5016 if (InterruptData
.Flags
& SCSI_PORT_ENABLE_INT_REQUEST
)
5018 /* Synchronize using spinlock */
5019 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5021 /* Request an interrupt */
5022 DeviceExtension
->HwInterrupt(DeviceExtension
->MiniPortDeviceExtension
);
5024 ASSERT(DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
);
5026 /* Should interrupts be enabled again? */
5027 if (DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
)
5029 /* Clear this flag */
5030 DeviceExtension
->Flags
&= ~SCSI_PORT_DISABLE_INT_REQUESET
;
5032 /* Call a special routine to do this */
5035 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
5036 SpiEnableInterrupts
,
5041 /* If we need a notification again - loop */
5042 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5045 /* Release the spinlock */
5046 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5049 DPRINT("ScsiPortDpcForIsr() done\n");
5054 SpiProcessTimeout(PVOID ServiceContext
)
5056 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
5057 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
5060 DPRINT("SpiProcessTimeout() entered\n");
5062 DeviceExtension
->TimerCount
= -1;
5064 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
5066 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET
;
5068 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET_REQUEST
)
5070 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET_REQUEST
;
5071 ScsiPortStartPacket(ServiceContext
);
5078 DPRINT("Resetting the bus\n");
5080 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
5082 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
, Bus
);
5084 /* Reset flags and set reset timeout to 4 seconds */
5085 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
5086 DeviceExtension
->TimerCount
= 4;
5089 /* If miniport requested - request a dpc for it */
5090 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5091 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
5100 SpiResetBus(PVOID ServiceContext
)
5102 PRESETBUS_PARAMS ResetParams
= (PRESETBUS_PARAMS
)ServiceContext
;
5103 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5105 /* Perform the bus reset */
5106 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ResetParams
->DeviceExtension
;
5107 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
,
5108 ResetParams
->PathId
);
5110 /* Set flags and start the timer */
5111 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
5112 DeviceExtension
->TimerCount
= 4;
5114 /* If miniport requested - give him a DPC */
5115 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5116 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
5123 // This function handles timeouts and other time delayed processing
5128 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
5129 // IN PVOID Context the Controller extension for the
5130 // controller the device is on
5133 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
5136 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5137 PSCSI_PORT_LUN_EXTENSION LunExtension
;
5141 DPRINT("ScsiPortIoTimer()\n");
5143 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
5145 /* Protect with the spinlock */
5146 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5148 /* Check timeouts */
5149 if (DeviceExtension
->TimerCount
> 0)
5151 /* Decrease the timeout counter */
5152 DeviceExtension
->TimerCount
--;
5154 if (DeviceExtension
->TimerCount
== 0)
5156 /* Timeout, process it */
5157 if (KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
5159 DeviceExtension
->DeviceObject
))
5161 DPRINT("Error happened during processing timeout, but nothing critical\n");
5165 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5167 /* We should exit now, since timeout is processed */
5171 /* Per-Lun scanning of timeouts is needed... */
5172 for (Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
5174 LunExtension
= DeviceExtension
->LunExtensionList
[Lun
];
5176 while (LunExtension
)
5178 if (LunExtension
->Flags
& LUNEX_BUSY
)
5180 if (!(LunExtension
->Flags
&
5181 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_FROZEN_QUEUE
)))
5183 DPRINT("Retrying busy request\n");
5185 /* Clear flags, and retry busy request */
5186 LunExtension
->Flags
&= ~(LUNEX_BUSY
| LUNEX_FULL_QUEUE
);
5187 Irp
= LunExtension
->BusyRequest
;
5189 /* Clearing busy request */
5190 LunExtension
->BusyRequest
= NULL
;
5192 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5194 IoStartPacket(DeviceObject
, Irp
, (PULONG
)NULL
, NULL
);
5196 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5199 else if (LunExtension
->RequestTimeout
== 0)
5201 RESETBUS_PARAMS ResetParams
;
5203 LunExtension
->RequestTimeout
= -1;
5205 DPRINT("Request timed out, resetting bus\n");
5207 /* Pass params to the bus reset routine */
5208 ResetParams
.PathId
= LunExtension
->PathId
;
5209 ResetParams
.DeviceExtension
= DeviceExtension
;
5211 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
5215 DPRINT1("Reset failed\n");
5218 else if (LunExtension
->RequestTimeout
> 0)
5220 /* Decrement the timeout counter */
5221 LunExtension
->RequestTimeout
--;
5224 LunExtension
= LunExtension
->Next
;
5228 /* Release the spinlock */
5229 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5232 /**********************************************************************
5237 * Builds the registry device map of all device which are attached
5238 * to the given SCSI HBA port. The device map is located at:
5239 * \Registry\Machine\DeviceMap\Scsi
5249 * Name of registry driver service key.
5256 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5257 PUNICODE_STRING RegistryPath
)
5259 PSCSI_PORT_LUN_EXTENSION LunExtension
;
5260 OBJECT_ATTRIBUTES ObjectAttributes
;
5261 UNICODE_STRING KeyName
;
5262 UNICODE_STRING ValueName
;
5263 WCHAR NameBuffer
[64];
5266 HANDLE ScsiPortKey
= NULL
;
5267 HANDLE ScsiBusKey
= NULL
;
5268 HANDLE ScsiInitiatorKey
= NULL
;
5269 HANDLE ScsiTargetKey
= NULL
;
5270 HANDLE ScsiLunKey
= NULL
;
5273 ULONG CurrentTarget
;
5280 DPRINT("SpiBuildDeviceMap() called\n");
5282 if (DeviceExtension
== NULL
|| RegistryPath
== NULL
)
5284 DPRINT1("Invalid parameter\n");
5285 return(STATUS_INVALID_PARAMETER
);
5288 /* Open or create the 'Scsi' subkey */
5289 RtlInitUnicodeString(&KeyName
,
5290 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
5291 InitializeObjectAttributes(&ObjectAttributes
,
5293 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
5296 Status
= ZwCreateKey(&ScsiKey
,
5301 REG_OPTION_VOLATILE
,
5303 if (!NT_SUCCESS(Status
))
5305 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5309 /* Create new 'Scsi Port X' subkey */
5310 DPRINT("Scsi Port %lu\n",
5311 DeviceExtension
->PortNumber
);
5313 swprintf(NameBuffer
,
5315 DeviceExtension
->PortNumber
);
5316 RtlInitUnicodeString(&KeyName
,
5318 InitializeObjectAttributes(&ObjectAttributes
,
5323 Status
= ZwCreateKey(&ScsiPortKey
,
5328 REG_OPTION_VOLATILE
,
5331 if (!NT_SUCCESS(Status
))
5333 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5338 * Create port-specific values
5341 /* Set 'DMA Enabled' (REG_DWORD) value */
5342 UlongData
= (ULONG
)!DeviceExtension
->PortCapabilities
.AdapterUsesPio
;
5343 DPRINT(" DMA Enabled = %s\n", (UlongData
) ? "TRUE" : "FALSE");
5344 RtlInitUnicodeString(&ValueName
,
5346 Status
= ZwSetValueKey(ScsiPortKey
,
5352 if (!NT_SUCCESS(Status
))
5354 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status
);
5355 ZwClose(ScsiPortKey
);
5359 /* Set 'Driver' (REG_SZ) value */
5360 DriverName
= wcsrchr(RegistryPath
->Buffer
, L
'\\') + 1;
5361 RtlInitUnicodeString(&ValueName
,
5363 Status
= ZwSetValueKey(ScsiPortKey
,
5368 (ULONG
)((wcslen(DriverName
) + 1) * sizeof(WCHAR
)));
5369 if (!NT_SUCCESS(Status
))
5371 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status
);
5372 ZwClose(ScsiPortKey
);
5376 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
5377 UlongData
= (ULONG
)DeviceExtension
->PortConfig
->BusInterruptLevel
;
5378 DPRINT(" Interrupt = %lu\n", UlongData
);
5379 RtlInitUnicodeString(&ValueName
,
5381 Status
= ZwSetValueKey(ScsiPortKey
,
5387 if (!NT_SUCCESS(Status
))
5389 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status
);
5390 ZwClose(ScsiPortKey
);
5394 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
5395 UlongData
= ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension
->PortConfig
->AccessRanges
)[0].RangeStart
);
5396 DPRINT(" IOAddress = %lx\n", UlongData
);
5397 RtlInitUnicodeString(&ValueName
,
5399 Status
= ZwSetValueKey(ScsiPortKey
,
5405 if (!NT_SUCCESS(Status
))
5407 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status
);
5408 ZwClose(ScsiPortKey
);
5412 /* Enumerate buses */
5413 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
->NumberOfBuses
; BusNumber
++)
5415 /* Create 'Scsi Bus X' key */
5416 DPRINT(" Scsi Bus %lu\n", BusNumber
);
5417 swprintf(NameBuffer
,
5420 RtlInitUnicodeString(&KeyName
,
5422 InitializeObjectAttributes(&ObjectAttributes
,
5427 Status
= ZwCreateKey(&ScsiBusKey
,
5432 REG_OPTION_VOLATILE
,
5434 if (!NT_SUCCESS(Status
))
5436 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5440 /* Create 'Initiator Id X' key */
5441 DPRINT(" Initiator Id %u\n",
5442 DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5443 swprintf(NameBuffer
,
5445 (unsigned int)(UCHAR
)DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5446 RtlInitUnicodeString(&KeyName
,
5448 InitializeObjectAttributes(&ObjectAttributes
,
5453 Status
= ZwCreateKey(&ScsiInitiatorKey
,
5458 REG_OPTION_VOLATILE
,
5460 if (!NT_SUCCESS(Status
))
5462 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5466 /* FIXME: Are there any initiator values (??) */
5468 ZwClose(ScsiInitiatorKey
);
5469 ScsiInitiatorKey
= NULL
;
5472 /* Enumerate targets */
5473 CurrentTarget
= (ULONG
)-1;
5474 ScsiTargetKey
= NULL
;
5475 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
5477 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
5479 LunExtension
= SpiGetLunExtension(DeviceExtension
,
5483 if (LunExtension
!= NULL
)
5485 if (Target
!= CurrentTarget
)
5487 /* Close old target key */
5488 if (ScsiTargetKey
!= NULL
)
5490 ZwClose(ScsiTargetKey
);
5491 ScsiTargetKey
= NULL
;
5494 /* Create 'Target Id X' key */
5495 DPRINT(" Target Id %lu\n", Target
);
5496 swprintf(NameBuffer
,
5499 RtlInitUnicodeString(&KeyName
,
5501 InitializeObjectAttributes(&ObjectAttributes
,
5506 Status
= ZwCreateKey(&ScsiTargetKey
,
5511 REG_OPTION_VOLATILE
,
5513 if (!NT_SUCCESS(Status
))
5515 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5519 CurrentTarget
= Target
;
5522 /* Create 'Logical Unit Id X' key */
5523 DPRINT(" Logical Unit Id %lu\n", Lun
);
5524 swprintf(NameBuffer
,
5525 L
"Logical Unit Id %lu",
5527 RtlInitUnicodeString(&KeyName
,
5529 InitializeObjectAttributes(&ObjectAttributes
,
5534 Status
= ZwCreateKey(&ScsiLunKey
,
5539 REG_OPTION_VOLATILE
,
5541 if (!NT_SUCCESS(Status
))
5543 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5547 /* Set 'Identifier' (REG_SZ) value */
5548 swprintf(NameBuffer
,
5550 LunExtension
->InquiryData
.VendorId
,
5551 LunExtension
->InquiryData
.ProductId
,
5552 LunExtension
->InquiryData
.ProductRevisionLevel
);
5553 DPRINT(" Identifier = '%S'\n", NameBuffer
);
5554 RtlInitUnicodeString(&ValueName
,
5556 Status
= ZwSetValueKey(ScsiLunKey
,
5561 (ULONG
)((wcslen(NameBuffer
) + 1) * sizeof(WCHAR
)));
5562 if (!NT_SUCCESS(Status
))
5564 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status
);
5568 /* Set 'Type' (REG_SZ) value */
5569 switch (LunExtension
->InquiryData
.DeviceType
)
5572 TypeName
= L
"DiskPeripheral";
5575 TypeName
= L
"TapePeripheral";
5578 TypeName
= L
"PrinterPeripheral";
5581 TypeName
= L
"WormPeripheral";
5584 TypeName
= L
"CdRomPeripheral";
5587 TypeName
= L
"ScannerPeripheral";
5590 TypeName
= L
"OpticalDiskPeripheral";
5593 TypeName
= L
"MediumChangerPeripheral";
5596 TypeName
= L
"CommunicationPeripheral";
5599 TypeName
= L
"OtherPeripheral";
5602 DPRINT(" Type = '%S'\n", TypeName
);
5603 RtlInitUnicodeString(&ValueName
,
5605 Status
= ZwSetValueKey(ScsiLunKey
,
5610 (ULONG
)((wcslen(TypeName
) + 1) * sizeof(WCHAR
)));
5611 if (!NT_SUCCESS(Status
))
5613 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status
);
5617 ZwClose(ScsiLunKey
);
5622 /* Close old target key */
5623 if (ScsiTargetKey
!= NULL
)
5625 ZwClose(ScsiTargetKey
);
5626 ScsiTargetKey
= NULL
;
5630 ZwClose(ScsiBusKey
);
5635 if (ScsiLunKey
!= NULL
)
5636 ZwClose (ScsiLunKey
);
5638 if (ScsiInitiatorKey
!= NULL
)
5639 ZwClose (ScsiInitiatorKey
);
5641 if (ScsiTargetKey
!= NULL
)
5642 ZwClose (ScsiTargetKey
);
5644 if (ScsiBusKey
!= NULL
)
5645 ZwClose (ScsiBusKey
);
5647 if (ScsiPortKey
!= NULL
)
5648 ZwClose (ScsiPortKey
);
5650 DPRINT("SpiBuildDeviceMap() done\n");
5657 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
5658 IN PVOID DeviceObject
,
5659 IN PVOID SystemArgument1
,
5660 IN PVOID SystemArgument2
)
5662 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5664 DPRINT("Miniport timer DPC\n");
5666 DeviceExtension
= ((PDEVICE_OBJECT
)DeviceObject
)->DeviceExtension
;
5668 /* Acquire the spinlock */
5669 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5671 /* Call the timer routine */
5672 if (DeviceExtension
->HwScsiTimer
!= NULL
)
5674 DeviceExtension
->HwScsiTimer(&DeviceExtension
->MiniPortDeviceExtension
);
5677 /* Release the spinlock */
5678 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5680 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5682 ScsiPortDpcForIsr(NULL
,
5683 DeviceExtension
->DeviceObject
,
5690 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5691 PHW_INITIALIZATION_DATA HwInitData
,
5692 PCONFIGURATION_INFO InternalConfigInfo
,
5693 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5696 UNICODE_STRING UnicodeString
;
5697 OBJECT_ATTRIBUTES ObjectAttributes
;
5698 PCONFIGURATION_INFORMATION DdkConfigInformation
;
5699 HANDLE RootKey
, Key
;
5701 WCHAR DeviceBuffer
[16];
5702 WCHAR StrBuffer
[512];
5706 /* Zero out the struct if told so */
5709 /* First zero the portconfig */
5710 RtlZeroMemory(ConfigInfo
, sizeof(PORT_CONFIGURATION_INFORMATION
));
5712 /* Then access ranges */
5713 RtlZeroMemory(InternalConfigInfo
->AccessRanges
,
5714 HwInitData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
5716 /* Initialize the struct */
5717 ConfigInfo
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
5718 ConfigInfo
->AdapterInterfaceType
= HwInitData
->AdapterInterfaceType
;
5719 ConfigInfo
->InterruptMode
= Latched
;
5720 ConfigInfo
->DmaChannel
= SP_UNINITIALIZED_VALUE
;
5721 ConfigInfo
->DmaPort
= SP_UNINITIALIZED_VALUE
;
5722 ConfigInfo
->DmaChannel2
= SP_UNINITIALIZED_VALUE
;
5723 ConfigInfo
->DmaPort2
= SP_UNINITIALIZED_VALUE
;
5724 ConfigInfo
->MaximumTransferLength
= SP_UNINITIALIZED_VALUE
;
5725 ConfigInfo
->NumberOfAccessRanges
= HwInitData
->NumberOfAccessRanges
;
5726 ConfigInfo
->MaximumNumberOfTargets
= 8;
5728 /* Store parameters */
5729 ConfigInfo
->NeedPhysicalAddresses
= HwInitData
->NeedPhysicalAddresses
;
5730 ConfigInfo
->MapBuffers
= HwInitData
->MapBuffers
;
5731 ConfigInfo
->AutoRequestSense
= HwInitData
->AutoRequestSense
;
5732 ConfigInfo
->ReceiveEvent
= HwInitData
->ReceiveEvent
;
5733 ConfigInfo
->TaggedQueuing
= HwInitData
->TaggedQueuing
;
5734 ConfigInfo
->MultipleRequestPerLu
= HwInitData
->MultipleRequestPerLu
;
5736 /* Get the disk usage */
5737 DdkConfigInformation
= IoGetConfigurationInformation();
5738 ConfigInfo
->AtdiskPrimaryClaimed
= DdkConfigInformation
->AtDiskPrimaryAddressClaimed
;
5739 ConfigInfo
->AtdiskSecondaryClaimed
= DdkConfigInformation
->AtDiskSecondaryAddressClaimed
;
5741 /* Initiator bus id is not set */
5742 for (Bus
= 0; Bus
< 8; Bus
++)
5743 ConfigInfo
->InitiatorBusId
[Bus
] = (CCHAR
)SP_UNINITIALIZED_VALUE
;
5746 ConfigInfo
->NumberOfPhysicalBreaks
= 17;
5748 /* Clear this information */
5749 InternalConfigInfo
->DisableTaggedQueueing
= FALSE
;
5750 InternalConfigInfo
->DisableMultipleLun
= FALSE
;
5752 /* Store Bus Number */
5753 ConfigInfo
->SystemIoBusNumber
= InternalConfigInfo
->BusNumber
;
5757 if (ConfigInfo
->AdapterInterfaceType
== Internal
)
5759 /* Open registry key for HW database */
5760 InitializeObjectAttributes(&ObjectAttributes
,
5761 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
5762 OBJ_CASE_INSENSITIVE
,
5766 Status
= ZwOpenKey(&RootKey
,
5770 if (NT_SUCCESS(Status
))
5772 /* Create name for it */
5773 swprintf(StrBuffer
, L
"ScsiAdapter\\%lu",
5774 InternalConfigInfo
->AdapterNumber
);
5776 RtlInitUnicodeString(&UnicodeString
, StrBuffer
);
5778 /* Open device key */
5779 InitializeObjectAttributes(&ObjectAttributes
,
5781 OBJ_CASE_INSENSITIVE
,
5785 Status
= ZwOpenKey(&Key
,
5791 if (NT_SUCCESS(Status
))
5793 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5795 DPRINT("Hardware info found at %S\n", StrBuffer
);
5798 SpiParseDeviceInfo(DeviceExtension
,
5804 InternalConfigInfo
->BusNumber
= 0;
5808 /* Try the next adapter */
5809 InternalConfigInfo
->AdapterNumber
++;
5815 /* Info was not found, exit */
5816 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status
);
5817 return STATUS_DEVICE_DOES_NOT_EXIST
;
5822 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status
);
5826 /* Look at device params */
5828 if (InternalConfigInfo
->Parameter
)
5830 ExFreePool(InternalConfigInfo
->Parameter
);
5831 InternalConfigInfo
->Parameter
= NULL
;
5834 if (InternalConfigInfo
->ServiceKey
!= NULL
)
5836 swprintf(DeviceBuffer
, L
"Device%lu", InternalConfigInfo
->AdapterNumber
);
5837 RtlInitUnicodeString(&UnicodeString
, DeviceBuffer
);
5839 /* Open the service key */
5840 InitializeObjectAttributes(&ObjectAttributes
,
5842 OBJ_CASE_INSENSITIVE
,
5843 InternalConfigInfo
->ServiceKey
,
5846 Status
= ZwOpenKey(&Key
,
5851 /* Parse device key */
5852 if (InternalConfigInfo
->DeviceKey
!= NULL
)
5854 SpiParseDeviceInfo(DeviceExtension
,
5855 InternalConfigInfo
->DeviceKey
,
5861 /* Then parse hw info */
5864 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5866 SpiParseDeviceInfo(DeviceExtension
,
5877 /* Adapter not found, go try the next one */
5878 InternalConfigInfo
->AdapterNumber
++;
5887 /* Update the last adapter number */
5888 InternalConfigInfo
->LastAdapterNumber
= InternalConfigInfo
->AdapterNumber
;
5890 /* Do we have this kind of bus at all? */
5892 Status
= IoQueryDeviceDescription(&HwInitData
->AdapterInterfaceType
,
5893 &InternalConfigInfo
->BusNumber
,
5898 SpQueryDeviceCallout
,
5901 /* This bus was not found */
5904 INTERFACE_TYPE InterfaceType
= Eisa
;
5906 /* Check for EISA */
5907 if (HwInitData
->AdapterInterfaceType
== Isa
)
5909 Status
= IoQueryDeviceDescription(&InterfaceType
,
5910 &InternalConfigInfo
->BusNumber
,
5915 SpQueryDeviceCallout
,
5918 /* Return respectively */
5920 return STATUS_SUCCESS
;
5922 return STATUS_DEVICE_DOES_NOT_EXIST
;
5926 return STATUS_DEVICE_DOES_NOT_EXIST
;
5931 return STATUS_SUCCESS
;
5936 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5938 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5939 IN PCONFIGURATION_INFO InternalConfigInfo
,
5942 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
5943 PCM_FULL_RESOURCE_DESCRIPTOR FullResource
;
5944 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
5945 PCM_SCSI_DEVICE_DATA ScsiDeviceData
;
5946 ULONG Length
, Count
, Dma
= 0, Interrupt
= 0;
5947 ULONG Index
= 0, RangeCount
= 0;
5948 UNICODE_STRING UnicodeString
;
5949 ANSI_STRING AnsiString
;
5950 NTSTATUS Status
= STATUS_SUCCESS
;
5953 KeyValueInformation
= (PKEY_VALUE_FULL_INFORMATION
) Buffer
;
5955 /* Loop through all values in the device node */
5958 Status
= ZwEnumerateValueKey(Key
,
5960 KeyValueFullInformation
,
5965 if (!NT_SUCCESS(Status
))
5970 /* Length for DWORD is ok? */
5971 if (KeyValueInformation
->Type
== REG_DWORD
&&
5972 KeyValueInformation
->DataLength
!= sizeof(ULONG
))
5977 /* Get MaximumLogicalUnit */
5978 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumLogicalUnit",
5979 KeyValueInformation
->NameLength
/2) == 0)
5982 if (KeyValueInformation
->Type
!= REG_DWORD
)
5984 DPRINT("Bad data type for MaximumLogicalUnit\n");
5988 DeviceExtension
->MaxLunCount
= *((PUCHAR
)
5989 (Buffer
+ KeyValueInformation
->DataOffset
));
5991 /* Check / reset if needed */
5992 if (DeviceExtension
->MaxLunCount
> SCSI_MAXIMUM_LOGICAL_UNITS
)
5993 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
5995 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension
->MaxLunCount
);
5998 /* Get InitiatorTargetId */
5999 if (_wcsnicmp(KeyValueInformation
->Name
, L
"InitiatorTargetId",
6000 KeyValueInformation
->NameLength
/ 2) == 0)
6003 if (KeyValueInformation
->Type
!= REG_DWORD
)
6005 DPRINT("Bad data type for InitiatorTargetId\n");
6009 ConfigInfo
->InitiatorBusId
[0] = *((PUCHAR
)
6010 (Buffer
+ KeyValueInformation
->DataOffset
));
6012 /* Check / reset if needed */
6013 if (ConfigInfo
->InitiatorBusId
[0] > ConfigInfo
->MaximumNumberOfTargets
- 1)
6014 ConfigInfo
->InitiatorBusId
[0] = (CCHAR
)-1;
6016 DPRINT("InitiatorTargetId = %d\n", ConfigInfo
->InitiatorBusId
[0]);
6020 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ScsiDebug",
6021 KeyValueInformation
->NameLength
/2) == 0)
6023 DPRINT("ScsiDebug key not supported\n");
6026 /* Check for a breakpoint */
6027 if (_wcsnicmp(KeyValueInformation
->Name
, L
"BreakPointOnEntry",
6028 KeyValueInformation
->NameLength
/2) == 0)
6030 DPRINT1("Breakpoint on entry requested!\n");
6034 /* Get DisableSynchronousTransfers */
6035 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableSynchronousTransfers",
6036 KeyValueInformation
->NameLength
/2) == 0)
6038 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6039 DPRINT("Synch transfers disabled\n");
6042 /* Get DisableDisconnects */
6043 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableDisconnects",
6044 KeyValueInformation
->NameLength
/2) == 0)
6046 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
6047 DPRINT("Disconnects disabled\n");
6050 /* Get DisableTaggedQueuing */
6051 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableTaggedQueuing",
6052 KeyValueInformation
->NameLength
/2) == 0)
6054 InternalConfigInfo
->DisableTaggedQueueing
= TRUE
;
6055 DPRINT("Tagged queueing disabled\n");
6058 /* Get DisableMultipleRequests */
6059 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableMultipleRequests",
6060 KeyValueInformation
->NameLength
/2) == 0)
6062 InternalConfigInfo
->DisableMultipleLun
= TRUE
;
6063 DPRINT("Multiple requests disabled\n");
6066 /* Get DriverParameters */
6067 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DriverParameters",
6068 KeyValueInformation
->NameLength
/2) == 0)
6070 /* Skip if nothing */
6071 if (KeyValueInformation
->DataLength
== 0)
6074 /* If there was something previously allocated - free it */
6075 if (InternalConfigInfo
->Parameter
!= NULL
)
6076 ExFreePool(InternalConfigInfo
->Parameter
);
6079 InternalConfigInfo
->Parameter
= ExAllocatePoolWithTag(NonPagedPool
,
6080 KeyValueInformation
->DataLength
, TAG_SCSIPORT
);
6082 if (InternalConfigInfo
->Parameter
!= NULL
)
6084 if (KeyValueInformation
->Type
!= REG_SZ
)
6088 InternalConfigInfo
->Parameter
,
6089 (PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
,
6090 KeyValueInformation
->DataLength
);
6094 /* If it's a unicode string, convert it to ansi */
6095 UnicodeString
.Length
= (USHORT
)KeyValueInformation
->DataLength
;
6096 UnicodeString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
6097 UnicodeString
.Buffer
=
6098 (PWSTR
)((PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
6100 AnsiString
.Length
= 0;
6101 AnsiString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
6102 AnsiString
.Buffer
= (PCHAR
)InternalConfigInfo
->Parameter
;
6104 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
6108 /* In case of error, free the allocated space */
6109 if (!NT_SUCCESS(Status
))
6111 ExFreePool(InternalConfigInfo
->Parameter
);
6112 InternalConfigInfo
->Parameter
= NULL
;
6118 DPRINT("Found driver parameter\n");
6121 /* Get MaximumSGList */
6122 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumSGList",
6123 KeyValueInformation
->NameLength
/2) == 0)
6125 if (KeyValueInformation
->Type
!= REG_DWORD
)
6127 DPRINT("Bad data type for MaximumSGList\n");
6131 ConfigInfo
->NumberOfPhysicalBreaks
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
6134 if (ConfigInfo
->NumberOfPhysicalBreaks
> SCSI_MAXIMUM_PHYSICAL_BREAKS
)
6136 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MAXIMUM_PHYSICAL_BREAKS
;
6138 else if (ConfigInfo
->NumberOfPhysicalBreaks
< SCSI_MINIMUM_PHYSICAL_BREAKS
)
6140 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MINIMUM_PHYSICAL_BREAKS
;
6143 DPRINT("MaximumSGList = %d\n", ConfigInfo
->NumberOfPhysicalBreaks
);
6146 /* Get NumberOfRequests */
6147 if (_wcsnicmp(KeyValueInformation
->Name
, L
"NumberOfRequests",
6148 KeyValueInformation
->NameLength
/2) == 0)
6150 if (KeyValueInformation
->Type
!= REG_DWORD
)
6152 DPRINT("NumberOfRequests has wrong data type\n");
6156 DeviceExtension
->RequestsNumber
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
6159 if (DeviceExtension
->RequestsNumber
< 16)
6161 DeviceExtension
->RequestsNumber
= 16;
6163 else if (DeviceExtension
->RequestsNumber
> 512)
6165 DeviceExtension
->RequestsNumber
= 512;
6168 DPRINT("Number Of Requests = %d\n", DeviceExtension
->RequestsNumber
);
6171 /* Get resource list */
6172 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ResourceList",
6173 KeyValueInformation
->NameLength
/2) == 0 ||
6174 _wcsnicmp(KeyValueInformation
->Name
, L
"Configuration Data",
6175 KeyValueInformation
->NameLength
/2) == 0 )
6177 if (KeyValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
||
6178 KeyValueInformation
->DataLength
< sizeof(REG_FULL_RESOURCE_DESCRIPTOR
))
6180 DPRINT("Bad data type for ResourceList\n");
6185 DPRINT("Found ResourceList\n");
6188 FullResource
= (PCM_FULL_RESOURCE_DESCRIPTOR
)(Buffer
+ KeyValueInformation
->DataOffset
);
6190 /* Copy some info from it */
6191 InternalConfigInfo
->BusNumber
= FullResource
->BusNumber
;
6192 ConfigInfo
->SystemIoBusNumber
= FullResource
->BusNumber
;
6194 /* Loop through it */
6195 for (Count
= 0; Count
< FullResource
->PartialResourceList
.Count
; Count
++)
6197 /* Get partial descriptor */
6199 &FullResource
->PartialResourceList
.PartialDescriptors
[Count
];
6201 /* Check datalength */
6202 if ((ULONG
)((PCHAR
)(PartialDescriptor
+ 1) -
6203 (PCHAR
)FullResource
) > KeyValueInformation
->DataLength
)
6205 DPRINT("Resource data is of incorrect size\n");
6209 switch (PartialDescriptor
->Type
)
6211 case CmResourceTypePort
:
6212 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
6214 DPRINT("Too many access ranges\n");
6218 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= FALSE
;
6219 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Port
.Start
;
6220 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Port
.Length
;
6225 case CmResourceTypeMemory
:
6226 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
6228 DPRINT("Too many access ranges\n");
6232 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= TRUE
;
6233 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Memory
.Start
;
6234 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Memory
.Length
;
6239 case CmResourceTypeInterrupt
:
6243 ConfigInfo
->BusInterruptLevel
=
6244 PartialDescriptor
->u
.Interrupt
.Level
;
6246 ConfigInfo
->BusInterruptVector
=
6247 PartialDescriptor
->u
.Interrupt
.Vector
;
6249 ConfigInfo
->InterruptMode
= (PartialDescriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
) ? Latched
: LevelSensitive
;
6251 else if (Interrupt
== 1)
6253 ConfigInfo
->BusInterruptLevel2
=
6254 PartialDescriptor
->u
.Interrupt
.Level
;
6256 ConfigInfo
->BusInterruptVector2
=
6257 PartialDescriptor
->u
.Interrupt
.Vector
;
6259 ConfigInfo
->InterruptMode2
= (PartialDescriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
) ? Latched
: LevelSensitive
;
6265 case CmResourceTypeDma
:
6269 ConfigInfo
->DmaChannel
= PartialDescriptor
->u
.Dma
.Channel
;
6270 ConfigInfo
->DmaPort
= PartialDescriptor
->u
.Dma
.Port
;
6272 if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8
)
6273 ConfigInfo
->DmaWidth
= Width8Bits
;
6274 else if ((PartialDescriptor
->Flags
& CM_RESOURCE_DMA_16
) ||
6275 (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
6276 ConfigInfo
->DmaWidth
= Width16Bits
;
6277 else if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_32
)
6278 ConfigInfo
->DmaWidth
= Width32Bits
;
6282 ConfigInfo
->DmaChannel2
= PartialDescriptor
->u
.Dma
.Channel
;
6283 ConfigInfo
->DmaPort2
= PartialDescriptor
->u
.Dma
.Port
;
6285 if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8
)
6286 ConfigInfo
->DmaWidth2
= Width8Bits
;
6287 else if ((PartialDescriptor
->Flags
& CM_RESOURCE_DMA_16
) ||
6288 (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
6289 ConfigInfo
->DmaWidth2
= Width16Bits
;
6290 else if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_32
)
6291 ConfigInfo
->DmaWidth2
= Width32Bits
;
6297 case CmResourceTypeDeviceSpecific
:
6298 if (PartialDescriptor
->u
.DeviceSpecificData
.DataSize
<
6299 sizeof(CM_SCSI_DEVICE_DATA
) ||
6300 (PCHAR
) (PartialDescriptor
+ 1) - (PCHAR
)FullResource
+
6301 PartialDescriptor
->u
.DeviceSpecificData
.DataSize
>
6302 KeyValueInformation
->DataLength
)
6304 DPRINT("Resource data length is incorrect");
6308 /* Set only one field from it */
6309 ScsiDeviceData
= (PCM_SCSI_DEVICE_DATA
) (PartialDescriptor
+1);
6310 ConfigInfo
->InitiatorBusId
[0] = ScsiDeviceData
->HostIdentifier
;
6320 SpQueryDeviceCallout(IN PVOID Context
,
6321 IN PUNICODE_STRING PathName
,
6322 IN INTERFACE_TYPE BusType
,
6324 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
6325 IN CONFIGURATION_TYPE ControllerType
,
6326 IN ULONG ControllerNumber
,
6327 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
6328 IN CONFIGURATION_TYPE PeripheralType
,
6329 IN ULONG PeripheralNumber
,
6330 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
6332 PBOOLEAN Found
= (PBOOLEAN
)Context
;
6333 /* We just set our Found variable to TRUE */
6336 return STATUS_SUCCESS
;
6339 IO_ALLOCATION_ACTION
6341 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject
,
6343 IN PVOID MapRegisterBase
,
6347 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
6349 /* Guard access with the spinlock */
6350 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
6352 /* Save MapRegisterBase we've got here */
6353 DeviceExtension
->MapRegisterBase
= MapRegisterBase
;
6355 /* Start pending request */
6356 KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
6357 ScsiPortStartPacket
, DeviceObject
);
6359 /* Release spinlock we took */
6360 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
6367 SpiStatusSrbToNt(UCHAR SrbStatus
)
6369 switch (SRB_STATUS(SrbStatus
))
6371 case SRB_STATUS_TIMEOUT
:
6372 case SRB_STATUS_COMMAND_TIMEOUT
:
6373 return STATUS_IO_TIMEOUT
;
6375 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH
:
6376 case SRB_STATUS_BAD_FUNCTION
:
6377 return STATUS_INVALID_DEVICE_REQUEST
;
6379 case SRB_STATUS_NO_DEVICE
:
6380 case SRB_STATUS_INVALID_LUN
:
6381 case SRB_STATUS_INVALID_TARGET_ID
:
6382 case SRB_STATUS_NO_HBA
:
6383 return STATUS_DEVICE_DOES_NOT_EXIST
;
6385 case SRB_STATUS_DATA_OVERRUN
:
6386 return STATUS_BUFFER_OVERFLOW
;
6388 case SRB_STATUS_SELECTION_TIMEOUT
:
6389 return STATUS_DEVICE_NOT_CONNECTED
;
6392 return STATUS_IO_DEVICE_ERROR
;
6395 return STATUS_IO_DEVICE_ERROR
;
6399 #undef ScsiPortConvertPhysicalAddressToUlong
6404 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
6406 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
6407 return(Address
.u
.LowPart
);