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 *****************************************************************/
42 #include "scsiport_int.h"
44 ULONG InternalDebugLevel
= 0x00;
46 #undef ScsiPortMoveMemory
48 /* GLOBALS *******************************************************************/
51 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
52 IN PDEVICE_OBJECT DeviceObject
,
53 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
54 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
55 IN PUNICODE_STRING RegistryPath
,
57 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
);
60 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
63 static DRIVER_DISPATCH ScsiPortDispatchScsi
;
65 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
69 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
72 static DRIVER_STARTIO ScsiPortStartIo
;
74 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
78 ScsiPortStartPacket(IN OUT PVOID Context
);
82 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
83 PVOID MapRegisterBase
, PVOID Context
);
85 static PSCSI_PORT_LUN_EXTENSION
86 SpiAllocateLunExtension(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
88 static PSCSI_PORT_LUN_EXTENSION
89 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
94 static PSCSI_REQUEST_BLOCK_INFO
95 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
96 PSCSI_PORT_LUN_EXTENSION LunExtension
,
97 PSCSI_REQUEST_BLOCK Srb
);
100 SpiSendInquiry(IN PDEVICE_OBJECT DeviceObject
,
101 IN OUT PSCSI_LUN_INFO LunInfo
);
104 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
107 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
110 static PSCSI_REQUEST_BLOCK_INFO
111 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
118 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
119 IN PVOID ServiceContext
);
122 ScsiPortDpcForIsr(IN PKDPC Dpc
,
123 IN PDEVICE_OBJECT DpcDeviceObject
,
125 IN PVOID DpcContext
);
128 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
133 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject
,
135 IN PVOID MapRegisterBase
,
139 SpiBuildDeviceMap(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
140 IN PUNICODE_STRING RegistryPath
);
143 SpiStatusSrbToNt(UCHAR SrbStatus
);
146 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
147 IN PSCSI_REQUEST_BLOCK Srb
);
149 static IO_COMPLETION_ROUTINE SpiCompletionRoutine
;
151 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
157 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
158 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
159 OUT PBOOLEAN NeedToCallStartIo
);
162 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
163 IN PSCSI_PORT_LUN_EXTENSION LunExtension
);
166 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
167 IN PVOID DeviceObject
,
168 IN PVOID SystemArgument1
,
169 IN PVOID SystemArgument2
);
172 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
173 PHW_INITIALIZATION_DATA HwInitData
,
174 PCONFIGURATION_INFO InternalConfigInfo
,
175 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
179 SpQueryDeviceCallout(IN PVOID Context
,
180 IN PUNICODE_STRING PathName
,
181 IN INTERFACE_TYPE BusType
,
183 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
184 IN CONFIGURATION_TYPE ControllerType
,
185 IN ULONG ControllerNumber
,
186 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
187 IN CONFIGURATION_TYPE PeripheralType
,
188 IN ULONG PeripheralNumber
,
189 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
);
192 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
194 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
195 IN PCONFIGURATION_INFO InternalConfigInfo
,
199 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
200 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
201 IN PPORT_CONFIGURATION_INFORMATION PortConfig
);
203 static PCM_RESOURCE_LIST
204 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
205 PPORT_CONFIGURATION_INFORMATION PortConfig
);
208 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
211 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
215 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
);
217 NTHALAPI ULONG NTAPI
HalGetBusData(BUS_DATA_TYPE
, ULONG
, ULONG
, PVOID
, ULONG
);
218 NTHALAPI ULONG NTAPI
HalGetInterruptVector(INTERFACE_TYPE
, ULONG
, ULONG
, ULONG
, PKIRQL
, PKAFFINITY
);
219 NTHALAPI NTSTATUS NTAPI
HalAssignSlotResources(PUNICODE_STRING
, PUNICODE_STRING
, PDRIVER_OBJECT
, PDEVICE_OBJECT
, INTERFACE_TYPE
, ULONG
, ULONG
, PCM_RESOURCE_LIST
*);
221 /* FUNCTIONS *****************************************************************/
223 /**********************************************************************
228 * This function initializes the driver.
235 * System allocated Driver Object for this driver.
238 * Name of registry driver service key.
245 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
246 IN PUNICODE_STRING RegistryPath
)
248 DPRINT("ScsiPort Driver %s\n", VERSION
);
249 return(STATUS_SUCCESS
);
253 /**********************************************************************
258 * Prints debugging messages.
265 * Debug level of the given message.
268 * Pointer to printf()-compatible format string.
271 Additional output data (see printf()).
280 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
281 IN PCHAR DebugMessage
,
287 if (DebugPrintLevel
> InternalDebugLevel
)
290 va_start(ap
, DebugMessage
);
291 vsprintf(Buffer
, DebugMessage
, ap
);
297 /* An internal helper function for ScsiPortCompleteRequest */
300 SpiCompleteRequest(IN PVOID HwDeviceExtension
,
301 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
304 PSCSI_REQUEST_BLOCK Srb
;
306 /* Get current SRB */
309 /* Return if there is no SRB or it is not active */
310 if (!Srb
|| !(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
)) return;
313 Srb
->SrbStatus
= SrbStatus
;
315 /* Set data transfered to 0 */
316 Srb
->DataTransferLength
= 0;
319 ScsiPortNotification(RequestComplete
,
328 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
334 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
335 PSCSI_PORT_LUN_EXTENSION LunExtension
;
336 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
337 PLIST_ENTRY ListEntry
;
341 DPRINT("ScsiPortCompleteRequest() called\n");
343 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
344 SCSI_PORT_DEVICE_EXTENSION
,
345 MiniPortDeviceExtension
);
347 /* Go through all buses */
348 for (BusNumber
= 0; BusNumber
< 8; BusNumber
++)
350 /* Go through all targets */
351 for (Target
= 0; Target
< DeviceExtension
->MaxTargedIds
; Target
++)
353 /* Get logical unit list head */
354 LunExtension
= DeviceExtension
->LunExtensionList
[Target
% 8];
356 /* Go through all logical units */
359 /* Now match what caller asked with what we are at now */
360 if ((PathId
== SP_UNTAGGED
|| PathId
== LunExtension
->PathId
) &&
361 (TargetId
== SP_UNTAGGED
|| TargetId
== LunExtension
->TargetId
) &&
362 (Lun
== SP_UNTAGGED
|| Lun
== LunExtension
->Lun
))
364 /* Yes, that's what caller asked for. Complete abort requests */
365 if (LunExtension
->CompletedAbortRequests
)
367 /* TODO: Save SrbStatus in this request */
368 DPRINT1("Completing abort request without setting SrbStatus!\n");
370 /* Issue a notification request */
371 ScsiPortNotification(RequestComplete
,
373 LunExtension
->CompletedAbortRequests
);
376 /* Complete the request using our helper */
377 SpiCompleteRequest(HwDeviceExtension
,
378 &LunExtension
->SrbInfo
,
381 /* Go through the queue and complete everything there too */
382 ListEntry
= LunExtension
->SrbInfo
.Requests
.Flink
;
383 while (ListEntry
!= &LunExtension
->SrbInfo
.Requests
)
385 /* Get the actual SRB info entry */
386 SrbInfo
= CONTAINING_RECORD(ListEntry
,
387 SCSI_REQUEST_BLOCK_INFO
,
391 SpiCompleteRequest(HwDeviceExtension
,
395 /* Advance to the next request in queue */
396 ListEntry
= SrbInfo
->Requests
.Flink
;
400 /* Advance to the next one */
401 LunExtension
= LunExtension
->Next
;
411 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
413 DPRINT("ScsiPortFlushDma()\n");
422 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
423 IN PVOID MappedAddress
)
425 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
426 PMAPPED_ADDRESS NextMa
, LastMa
;
428 //DPRINT("ScsiPortFreeDeviceBase() called\n");
430 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
431 SCSI_PORT_DEVICE_EXTENSION
,
432 MiniPortDeviceExtension
);
434 /* Initialize our pointers */
435 NextMa
= DeviceExtension
->MappedAddressList
;
440 if (NextMa
->MappedAddress
== MappedAddress
)
443 MmUnmapIoSpace(MappedAddress
, NextMa
->NumberOfBytes
);
445 /* Remove it from the list */
446 if (NextMa
== DeviceExtension
->MappedAddressList
)
448 /* Remove the first entry */
449 DeviceExtension
->MappedAddressList
= NextMa
->NextMappedAddress
;
453 LastMa
->NextMappedAddress
= NextMa
->NextMappedAddress
;
456 /* Free the resources and quit */
464 NextMa
= NextMa
->NextMappedAddress
;
474 ScsiPortGetBusData(IN PVOID DeviceExtension
,
475 IN ULONG BusDataType
,
476 IN ULONG SystemIoBusNumber
,
481 DPRINT("ScsiPortGetBusData()\n");
485 /* If Length is non-zero, just forward the call to
486 HalGetBusData() function */
487 return HalGetBusData(BusDataType
,
494 /* We have a more complex case here */
503 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
504 IN ULONG BusDataType
,
505 IN ULONG SystemIoBusNumber
,
511 DPRINT("ScsiPortSetBusDataByOffset()\n");
512 return HalSetBusDataByOffset(BusDataType
,
524 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
525 IN INTERFACE_TYPE BusType
,
526 IN ULONG SystemIoBusNumber
,
527 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
528 IN ULONG NumberOfBytes
,
529 IN BOOLEAN InIoSpace
)
531 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
532 PHYSICAL_ADDRESS TranslatedAddress
;
533 PMAPPED_ADDRESS DeviceBase
;
537 //DPRINT ("ScsiPortGetDeviceBase() called\n");
539 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
540 SCSI_PORT_DEVICE_EXTENSION
,
541 MiniPortDeviceExtension
);
543 AddressSpace
= (ULONG
)InIoSpace
;
544 if (HalTranslateBusAddress(BusType
,
548 &TranslatedAddress
) == FALSE
)
554 if (AddressSpace
!= 0)
555 return((PVOID
)(ULONG_PTR
)TranslatedAddress
.QuadPart
);
557 MappedAddress
= MmMapIoSpace(TranslatedAddress
,
561 DeviceBase
= ExAllocatePoolWithTag(NonPagedPool
,
562 sizeof(MAPPED_ADDRESS
), TAG_SCSIPORT
);
564 if (DeviceBase
== NULL
)
565 return MappedAddress
;
567 DeviceBase
->MappedAddress
= MappedAddress
;
568 DeviceBase
->NumberOfBytes
= NumberOfBytes
;
569 DeviceBase
->IoAddress
= IoAddress
;
570 DeviceBase
->BusNumber
= SystemIoBusNumber
;
572 /* Link it to the Device Extension list */
573 DeviceBase
->NextMappedAddress
= DeviceExtension
->MappedAddressList
;
574 DeviceExtension
->MappedAddressList
= DeviceBase
;
576 return MappedAddress
;
583 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
588 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
589 PSCSI_PORT_LUN_EXTENSION LunExtension
;
591 DPRINT("ScsiPortGetLogicalUnit() called\n");
593 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
594 SCSI_PORT_DEVICE_EXTENSION
,
595 MiniPortDeviceExtension
);
597 /* Check the extension size */
598 if (!DeviceExtension
->LunExtensionSize
)
600 /* They didn't want one */
604 LunExtension
= SpiGetLunExtension(DeviceExtension
,
608 /* Check that the logical unit exists */
611 /* Nope, return NULL */
615 /* Return the logical unit miniport extension */
616 return (LunExtension
+ 1);
623 SCSI_PHYSICAL_ADDRESS NTAPI
624 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
625 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
626 IN PVOID VirtualAddress
,
629 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
630 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
631 SIZE_T BufferLength
= 0;
633 PSCSI_SG_ADDRESS SGList
;
634 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
636 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
637 HwDeviceExtension
, Srb
, VirtualAddress
, Length
);
639 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
640 SCSI_PORT_DEVICE_EXTENSION
,
641 MiniPortDeviceExtension
);
643 if (Srb
== NULL
|| Srb
->SenseInfoBuffer
== VirtualAddress
)
645 /* Simply look it up in the allocated common buffer */
646 Offset
= (PUCHAR
)VirtualAddress
- (PUCHAR
)DeviceExtension
->SrbExtensionBuffer
;
648 BufferLength
= DeviceExtension
->CommonBufferLength
- Offset
;
649 PhysicalAddress
.QuadPart
= DeviceExtension
->PhysicalAddress
.QuadPart
+ Offset
;
651 else if (DeviceExtension
->MapRegisters
)
653 /* Scatter-gather list must be used */
654 SrbInfo
= SpiGetSrbData(DeviceExtension
,
660 SGList
= SrbInfo
->ScatterGather
;
662 /* Find needed item in the SG list */
663 Offset
= (PCHAR
)VirtualAddress
- (PCHAR
)Srb
->DataBuffer
;
664 while (Offset
>= SGList
->Length
)
666 Offset
-= SGList
->Length
;
670 /* We're done, store length and physical address */
671 BufferLength
= SGList
->Length
- Offset
;
672 PhysicalAddress
.QuadPart
= SGList
->PhysicalAddress
.QuadPart
+ Offset
;
677 PhysicalAddress
.QuadPart
= (LONGLONG
)(SP_UNINITIALIZED_VALUE
);
680 *Length
= (ULONG
)BufferLength
;
681 return PhysicalAddress
;
688 PSCSI_REQUEST_BLOCK NTAPI
689 ScsiPortGetSrb(IN PVOID DeviceExtension
,
695 DPRINT1("ScsiPortGetSrb() unimplemented\n");
705 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
706 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
707 IN ULONG NumberOfBytes
)
709 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
710 DEVICE_DESCRIPTION DeviceDescription
;
711 ULONG MapRegistersCount
;
714 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
715 HwDeviceExtension
, ConfigInfo
, NumberOfBytes
);
717 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
718 SCSI_PORT_DEVICE_EXTENSION
,
719 MiniPortDeviceExtension
);
721 /* Check for allocated common DMA buffer */
722 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
)
724 DPRINT1("The HBA has already got a common DMA buffer!\n");
728 /* Check for DMA adapter object */
729 if (DeviceExtension
->AdapterObject
== NULL
)
731 /* Initialize DMA adapter description */
732 RtlZeroMemory(&DeviceDescription
, sizeof(DEVICE_DESCRIPTION
));
734 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
735 DeviceDescription
.Master
= ConfigInfo
->Master
;
736 DeviceDescription
.ScatterGather
= ConfigInfo
->ScatterGather
;
737 DeviceDescription
.DemandMode
= ConfigInfo
->DemandMode
;
738 DeviceDescription
.Dma32BitAddresses
= ConfigInfo
->Dma32BitAddresses
;
739 DeviceDescription
.BusNumber
= ConfigInfo
->SystemIoBusNumber
;
740 DeviceDescription
.DmaChannel
= ConfigInfo
->DmaChannel
;
741 DeviceDescription
.InterfaceType
= ConfigInfo
->AdapterInterfaceType
;
742 DeviceDescription
.DmaWidth
= ConfigInfo
->DmaWidth
;
743 DeviceDescription
.DmaSpeed
= ConfigInfo
->DmaSpeed
;
744 DeviceDescription
.MaximumLength
= ConfigInfo
->MaximumTransferLength
;
745 DeviceDescription
.DmaPort
= ConfigInfo
->DmaPort
;
747 /* Get a DMA adapter object */
748 DeviceExtension
->AdapterObject
=
749 HalGetAdapter(&DeviceDescription
, &MapRegistersCount
);
751 /* Fail in case of error */
752 if (DeviceExtension
->AdapterObject
== NULL
)
754 DPRINT1("HalGetAdapter() failed\n");
758 /* Set number of physical breaks */
759 if (ConfigInfo
->NumberOfPhysicalBreaks
!= 0 &&
760 MapRegistersCount
> ConfigInfo
->NumberOfPhysicalBreaks
)
762 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
=
763 ConfigInfo
->NumberOfPhysicalBreaks
;
767 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
= MapRegistersCount
;
771 /* Update auto request sense feature */
772 DeviceExtension
->SupportsAutoSense
= ConfigInfo
->AutoRequestSense
;
774 /* Update Srb extension size */
775 if (DeviceExtension
->SrbExtensionSize
!= ConfigInfo
->SrbExtensionSize
)
776 DeviceExtension
->SrbExtensionSize
= ConfigInfo
->SrbExtensionSize
;
778 /* Update Srb extension alloc flag */
779 if (ConfigInfo
->AutoRequestSense
|| DeviceExtension
->SrbExtensionSize
)
780 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
782 /* Allocate a common DMA buffer */
783 Status
= SpiAllocateCommonBuffer(DeviceExtension
, NumberOfBytes
);
785 if (!NT_SUCCESS(Status
))
787 DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status
);
791 return DeviceExtension
->NonCachedExtension
;
795 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
)
797 PVOID
*SrbExtension
, CommonBuffer
;
798 ULONG CommonBufferLength
, BufSize
;
800 /* If size is 0, set it to 16 */
801 if (!DeviceExtension
->SrbExtensionSize
)
802 DeviceExtension
->SrbExtensionSize
= 16;
805 BufSize
= DeviceExtension
->SrbExtensionSize
;
807 /* Add autosense data size if needed */
808 if (DeviceExtension
->SupportsAutoSense
)
809 BufSize
+= sizeof(SENSE_DATA
);
813 BufSize
= (BufSize
+ sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
815 /* Sum up into the total common buffer length, and round it to page size */
817 ROUND_TO_PAGES(NonCachedSize
+ BufSize
* DeviceExtension
->RequestsNumber
);
820 if (!DeviceExtension
->AdapterObject
)
822 /* From nonpaged pool if there is no DMA */
823 CommonBuffer
= ExAllocatePoolWithTag(NonPagedPool
, CommonBufferLength
, TAG_SCSIPORT
);
827 /* Perform a full request since we have a DMA adapter*/
828 CommonBuffer
= HalAllocateCommonBuffer(DeviceExtension
->AdapterObject
,
830 &DeviceExtension
->PhysicalAddress
,
834 /* Fail in case of error */
836 return STATUS_INSUFFICIENT_RESOURCES
;
839 RtlZeroMemory(CommonBuffer
, CommonBufferLength
);
841 /* Store its size in Device Extension */
842 DeviceExtension
->CommonBufferLength
= CommonBufferLength
;
844 /* SrbExtension buffer is located at the beginning of the buffer */
845 DeviceExtension
->SrbExtensionBuffer
= CommonBuffer
;
847 /* Non-cached extension buffer is located at the end of
851 CommonBufferLength
-= NonCachedSize
;
852 DeviceExtension
->NonCachedExtension
= (PUCHAR
)CommonBuffer
+ CommonBufferLength
;
856 DeviceExtension
->NonCachedExtension
= NULL
;
859 if (DeviceExtension
->NeedSrbExtensionAlloc
)
861 /* Look up how many SRB data structures we need */
862 DeviceExtension
->SrbDataCount
= CommonBufferLength
/ BufSize
;
864 /* Initialize the free SRB extensions list */
865 SrbExtension
= (PVOID
*)CommonBuffer
;
866 DeviceExtension
->FreeSrbExtensions
= SrbExtension
;
868 /* Fill the remaining pointers (if we have more than 1 SRB) */
869 while (CommonBufferLength
>= 2 * BufSize
)
871 *SrbExtension
= (PVOID
*)((PCHAR
)SrbExtension
+ BufSize
);
872 SrbExtension
= *SrbExtension
;
874 CommonBufferLength
-= BufSize
;
878 return STATUS_SUCCESS
;
887 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
888 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
890 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
893 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
894 HwDeviceExtension
, PhysicalAddress
.QuadPart
);
896 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
897 SCSI_PORT_DEVICE_EXTENSION
,
898 MiniPortDeviceExtension
);
900 if (DeviceExtension
->PhysicalAddress
.QuadPart
> PhysicalAddress
.QuadPart
)
903 Offset
= (ULONG
)(PhysicalAddress
.QuadPart
- DeviceExtension
->PhysicalAddress
.QuadPart
);
905 if (Offset
>= DeviceExtension
->CommonBufferLength
)
908 return (PVOID
)((ULONG_PTR
)DeviceExtension
->SrbExtensionBuffer
+ Offset
);
912 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo
, PUNICODE_STRING RegistryPath
)
914 OBJECT_ATTRIBUTES ObjectAttributes
;
915 UNICODE_STRING KeyName
;
918 /* Open the service key */
919 InitializeObjectAttributes(&ObjectAttributes
,
921 OBJ_CASE_INSENSITIVE
,
925 Status
= ZwOpenKey(&ConfigInfo
->ServiceKey
,
929 if (!NT_SUCCESS(Status
))
931 DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath
, Status
);
932 ConfigInfo
->ServiceKey
= NULL
;
935 /* If we could open driver's service key, then proceed to the Parameters key */
936 if (ConfigInfo
->ServiceKey
!= NULL
)
938 RtlInitUnicodeString(&KeyName
, L
"Parameters");
939 InitializeObjectAttributes(&ObjectAttributes
,
941 OBJ_CASE_INSENSITIVE
,
942 ConfigInfo
->ServiceKey
,
943 (PSECURITY_DESCRIPTOR
) NULL
);
946 Status
= ZwOpenKey(&ConfigInfo
->DeviceKey
,
950 if (NT_SUCCESS(Status
))
952 /* Yes, Parameters key exist, and it must be used instead of
954 ZwClose(ConfigInfo
->ServiceKey
);
955 ConfigInfo
->ServiceKey
= ConfigInfo
->DeviceKey
;
956 ConfigInfo
->DeviceKey
= NULL
;
960 if (ConfigInfo
->ServiceKey
!= NULL
)
962 /* Open the Device key */
963 RtlInitUnicodeString(&KeyName
, L
"Device");
964 InitializeObjectAttributes(&ObjectAttributes
,
966 OBJ_CASE_INSENSITIVE
,
967 ConfigInfo
->ServiceKey
,
970 /* We don't check for failure here - not needed */
971 ZwOpenKey(&ConfigInfo
->DeviceKey
,
978 /**********************************************************************
983 * Initializes SCSI port driver specific data.
990 * Pointer to the miniport driver's driver object.
993 * Pointer to the miniport driver's registry path.
995 * HwInitializationData
996 * Pointer to port driver specific configuration data.
999 Miniport driver specific context.
1008 ScsiPortInitialize(IN PVOID Argument1
,
1010 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
1013 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
1014 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
1015 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
1016 PCONFIGURATION_INFORMATION SystemConfig
;
1017 PPORT_CONFIGURATION_INFORMATION PortConfig
;
1018 PORT_CONFIGURATION_INFORMATION InitialPortConfig
;
1019 CONFIGURATION_INFO ConfigInfo
;
1020 ULONG DeviceExtensionSize
;
1021 ULONG PortConfigSize
;
1023 BOOLEAN DeviceFound
= FALSE
;
1024 BOOLEAN FirstConfigCall
= TRUE
;
1028 PCI_SLOT_NUMBER SlotNumber
;
1030 PDEVICE_OBJECT PortDeviceObject
;
1031 WCHAR NameBuffer
[80];
1032 UNICODE_STRING DeviceName
;
1033 WCHAR DosNameBuffer
[80];
1034 UNICODE_STRING DosDeviceName
;
1035 PIO_SCSI_CAPABILITIES PortCapabilities
;
1038 PCM_RESOURCE_LIST ResourceList
;
1040 SIZE_T BusConfigSize
;
1043 DPRINT ("ScsiPortInitialize() called!\n");
1045 /* Check params for validity */
1046 if ((HwInitializationData
->HwInitialize
== NULL
) ||
1047 (HwInitializationData
->HwStartIo
== NULL
) ||
1048 (HwInitializationData
->HwInterrupt
== NULL
) ||
1049 (HwInitializationData
->HwFindAdapter
== NULL
) ||
1050 (HwInitializationData
->HwResetBus
== NULL
))
1052 return STATUS_INVALID_PARAMETER
;
1056 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
1057 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
1058 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
1059 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
1060 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
1062 /* Obtain configuration information */
1063 SystemConfig
= IoGetConfigurationInformation();
1065 /* Zero the internal configuration info structure */
1066 RtlZeroMemory(&ConfigInfo
, sizeof(CONFIGURATION_INFO
));
1068 /* Zero starting slot number */
1069 SlotNumber
.u
.AsULONG
= 0;
1071 /* Allocate space for access ranges */
1072 if (HwInitializationData
->NumberOfAccessRanges
)
1074 ConfigInfo
.AccessRanges
=
1075 ExAllocatePoolWithTag(PagedPool
,
1076 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
), TAG_SCSIPORT
);
1078 /* Fail if failed */
1079 if (ConfigInfo
.AccessRanges
== NULL
)
1080 return STATUS_INSUFFICIENT_RESOURCES
;
1083 /* Open registry keys */
1084 SpiInitOpenKeys(&ConfigInfo
, (PUNICODE_STRING
)Argument2
);
1086 /* Last adapter number = not known */
1087 ConfigInfo
.LastAdapterNumber
= SP_UNINITIALIZED_VALUE
;
1089 /* Calculate sizes of DeviceExtension and PortConfig */
1090 DeviceExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
1091 HwInitializationData
->DeviceExtensionSize
;
1093 MaxBus
= (HwInitializationData
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
1094 DPRINT("MaxBus: %lu\n", MaxBus
);
1098 /* Create a unicode device name */
1099 swprintf(NameBuffer
,
1100 L
"\\Device\\ScsiPort%lu",
1101 SystemConfig
->ScsiPortCount
);
1102 RtlInitUnicodeString(&DeviceName
, NameBuffer
);
1104 DPRINT("Creating device: %wZ\n", &DeviceName
);
1106 /* Create the port device */
1107 Status
= IoCreateDevice(DriverObject
,
1108 DeviceExtensionSize
,
1110 FILE_DEVICE_CONTROLLER
,
1115 if (!NT_SUCCESS(Status
))
1117 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
1118 PortDeviceObject
= NULL
;
1122 DPRINT ("Created device: %wZ (%p)\n", &DeviceName
, PortDeviceObject
);
1124 /* Set the buffering strategy here... */
1125 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1126 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
; /* FIXME: Is this really needed? */
1128 /* Fill Device Extension */
1129 DeviceExtension
= PortDeviceObject
->DeviceExtension
;
1130 RtlZeroMemory(DeviceExtension
, DeviceExtensionSize
);
1131 DeviceExtension
->Length
= DeviceExtensionSize
;
1132 DeviceExtension
->DeviceObject
= PortDeviceObject
;
1133 DeviceExtension
->PortNumber
= SystemConfig
->ScsiPortCount
;
1135 /* Driver's routines... */
1136 DeviceExtension
->HwInitialize
= HwInitializationData
->HwInitialize
;
1137 DeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
1138 DeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
1139 DeviceExtension
->HwResetBus
= HwInitializationData
->HwResetBus
;
1140 DeviceExtension
->HwDmaStarted
= HwInitializationData
->HwDmaStarted
;
1142 /* Extensions sizes */
1143 DeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
1144 DeviceExtension
->LunExtensionSize
= HwInitializationData
->SpecificLuExtensionSize
;
1145 DeviceExtension
->SrbExtensionSize
= HwInitializationData
->SrbExtensionSize
;
1147 /* Round Srb extension size to the quadword */
1148 DeviceExtension
->SrbExtensionSize
=
1149 ~(sizeof(LONGLONG
) - 1) & (DeviceExtension
->SrbExtensionSize
+
1150 sizeof(LONGLONG
) - 1);
1152 /* Fill some numbers (bus count, lun count, etc) */
1153 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
1154 DeviceExtension
->RequestsNumber
= 16;
1156 /* Initialize the spin lock in the controller extension */
1157 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1158 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
1160 /* Initialize the DPC object */
1161 IoInitializeDpcRequest(PortDeviceObject
,
1164 /* Initialize the device timer */
1165 DeviceExtension
->TimerCount
= -1;
1166 IoInitializeTimer(PortDeviceObject
,
1170 /* Initialize miniport timer */
1171 KeInitializeTimer(&DeviceExtension
->MiniportTimer
);
1172 KeInitializeDpc(&DeviceExtension
->MiniportTimerDpc
,
1173 SpiMiniportTimerDpc
,
1178 Status
= SpiCreatePortConfig(DeviceExtension
,
1179 HwInitializationData
,
1184 if (!NT_SUCCESS(Status
))
1186 DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status
);
1190 /* Allocate and initialize port configuration info */
1191 PortConfigSize
= (sizeof(PORT_CONFIGURATION_INFORMATION
) +
1192 HwInitializationData
->NumberOfAccessRanges
*
1193 sizeof(ACCESS_RANGE
) + 7) & ~7;
1194 DeviceExtension
->PortConfig
= ExAllocatePoolWithTag(NonPagedPool
, PortConfigSize
, TAG_SCSIPORT
);
1196 /* Fail if failed */
1197 if (DeviceExtension
->PortConfig
== NULL
)
1199 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1203 PortConfig
= DeviceExtension
->PortConfig
;
1205 /* Copy information here */
1206 RtlCopyMemory(PortConfig
,
1208 sizeof(PORT_CONFIGURATION_INFORMATION
));
1211 /* Copy extension sizes into the PortConfig */
1212 PortConfig
->SpecificLuExtensionSize
= DeviceExtension
->LunExtensionSize
;
1213 PortConfig
->SrbExtensionSize
= DeviceExtension
->SrbExtensionSize
;
1215 /* Initialize Access ranges */
1216 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1218 PortConfig
->AccessRanges
= (PVOID
)(PortConfig
+1);
1220 /* Align to LONGLONG */
1221 PortConfig
->AccessRanges
= (PVOID
)((ULONG_PTR
)(PortConfig
->AccessRanges
) + 7);
1222 PortConfig
->AccessRanges
= (PVOID
)((ULONG_PTR
)(PortConfig
->AccessRanges
) & ~7);
1225 RtlCopyMemory(PortConfig
->AccessRanges
,
1226 ConfigInfo
.AccessRanges
,
1227 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
1230 /* Search for matching PCI device */
1231 if ((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1232 (HwInitializationData
->VendorIdLength
> 0) &&
1233 (HwInitializationData
->VendorId
!= NULL
) &&
1234 (HwInitializationData
->DeviceIdLength
> 0) &&
1235 (HwInitializationData
->DeviceId
!= NULL
))
1237 PortConfig
->BusInterruptLevel
= 0;
1239 /* Get PCI device data */
1240 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1241 HwInitializationData
->VendorIdLength
,
1242 HwInitializationData
->VendorId
,
1243 HwInitializationData
->DeviceIdLength
,
1244 HwInitializationData
->DeviceId
);
1246 if (!SpiGetPciConfigData(DriverObject
,
1248 HwInitializationData
,
1251 ConfigInfo
.BusNumber
,
1254 /* Continue to the next bus, nothing here */
1255 ConfigInfo
.BusNumber
++;
1256 DeviceExtension
->PortConfig
= NULL
;
1257 ExFreePool(PortConfig
);
1259 goto CreatePortConfig
;
1262 if (!PortConfig
->BusInterruptLevel
)
1264 /* Bypass this slot, because no interrupt was assigned */
1265 DeviceExtension
->PortConfig
= NULL
;
1266 ExFreePool(PortConfig
);
1267 goto CreatePortConfig
;
1272 DPRINT("Non-pci bus\n");
1275 /* Note: HwFindAdapter is called once for each bus */
1277 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
1278 Result
= (HwInitializationData
->HwFindAdapter
)(&DeviceExtension
->MiniPortDeviceExtension
,
1280 0, /* BusInformation */
1281 ConfigInfo
.Parameter
, /* ArgumentString */
1285 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1286 Result
, (Again
) ? "True" : "False");
1288 /* Free MapRegisterBase, it's not needed anymore */
1289 if (DeviceExtension
->MapRegisterBase
!= NULL
)
1291 ExFreePool(DeviceExtension
->MapRegisterBase
);
1292 DeviceExtension
->MapRegisterBase
= NULL
;
1295 /* If result is nothing good... */
1296 if (Result
!= SP_RETURN_FOUND
)
1298 DPRINT("HwFindAdapter() Result: %lu\n", Result
);
1300 if (Result
== SP_RETURN_NOT_FOUND
)
1302 /* We can continue on the next bus */
1303 ConfigInfo
.BusNumber
++;
1306 DeviceExtension
->PortConfig
= NULL
;
1307 ExFreePool(PortConfig
);
1308 goto CreatePortConfig
;
1311 /* Otherwise, break */
1312 Status
= STATUS_INTERNAL_ERROR
;
1316 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1317 PortConfig
->BusInterruptVector
, PortConfig
->InitiatorBusId
[0]);
1319 /* If the SRB extension size was updated */
1320 if (!DeviceExtension
->NonCachedExtension
&&
1321 (PortConfig
->SrbExtensionSize
!= DeviceExtension
->SrbExtensionSize
))
1323 /* Set it (rounding to LONGLONG again) */
1324 DeviceExtension
->SrbExtensionSize
=
1325 (PortConfig
->SrbExtensionSize
+
1326 sizeof(LONGLONG
)) & ~(sizeof(LONGLONG
) - 1);
1329 /* The same with LUN extension size */
1330 if (PortConfig
->SpecificLuExtensionSize
!= DeviceExtension
->LunExtensionSize
)
1331 DeviceExtension
->LunExtensionSize
= PortConfig
->SpecificLuExtensionSize
;
1334 if (!((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1335 (HwInitializationData
->VendorIdLength
> 0) &&
1336 (HwInitializationData
->VendorId
!= NULL
) &&
1337 (HwInitializationData
->DeviceIdLength
> 0) &&
1338 (HwInitializationData
->DeviceId
!= NULL
)))
1340 /* Construct a resource list */
1341 ResourceList
= SpiConfigToResource(DeviceExtension
,
1346 UNICODE_STRING UnicodeString
;
1347 RtlInitUnicodeString(&UnicodeString
, L
"ScsiAdapter");
1348 DPRINT("Reporting resources\n");
1349 Status
= IoReportResourceUsage(&UnicodeString
,
1355 FIELD_OFFSET(CM_RESOURCE_LIST
,
1356 List
[0].PartialResourceList
.PartialDescriptors
) +
1357 ResourceList
->List
[0].PartialResourceList
.Count
1358 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
1361 ExFreePool(ResourceList
);
1363 /* In case of a failure or a conflict, break */
1364 if (Conflict
|| (!NT_SUCCESS(Status
)))
1367 Status
= STATUS_CONFLICTING_ADDRESSES
;
1373 /* Reset the Conflict var */
1376 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1377 if (PortConfig
->MaximumNumberOfTargets
> SCSI_MAXIMUM_TARGETS_PER_BUS
)
1378 DeviceExtension
->MaxTargedIds
= SCSI_MAXIMUM_TARGETS_PER_BUS
;
1380 DeviceExtension
->MaxTargedIds
= PortConfig
->MaximumNumberOfTargets
;
1382 DeviceExtension
->BusNum
= PortConfig
->NumberOfBuses
;
1383 DeviceExtension
->CachesData
= PortConfig
->CachesData
;
1384 DeviceExtension
->ReceiveEvent
= PortConfig
->ReceiveEvent
;
1385 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->TaggedQueuing
;
1386 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
;
1388 /* If something was disabled via registry - apply it */
1389 if (ConfigInfo
.DisableMultipleLun
)
1390 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1392 if (ConfigInfo
.DisableTaggedQueueing
)
1393 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1395 /* Check if we need to alloc SRB data */
1396 if (DeviceExtension
->SupportsTaggedQueuing
||
1397 DeviceExtension
->MultipleReqsPerLun
)
1399 DeviceExtension
->NeedSrbDataAlloc
= TRUE
;
1403 DeviceExtension
->NeedSrbDataAlloc
= FALSE
;
1406 /* Get a pointer to the port capabilities */
1407 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1409 /* Copy one field there */
1410 DeviceExtension
->MapBuffers
= PortConfig
->MapBuffers
;
1411 PortCapabilities
->AdapterUsesPio
= PortConfig
->MapBuffers
;
1413 if (DeviceExtension
->AdapterObject
== NULL
&&
1414 (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
|| PortConfig
->Master
))
1416 DPRINT1("DMA is not supported yet\n");
1420 if (DeviceExtension
->SrbExtensionBuffer
== NULL
&&
1421 (DeviceExtension
->SrbExtensionSize
!= 0 ||
1422 PortConfig
->AutoRequestSense
))
1424 DeviceExtension
->SupportsAutoSense
= PortConfig
->AutoRequestSense
;
1425 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
1427 /* Allocate common buffer */
1428 Status
= SpiAllocateCommonBuffer(DeviceExtension
, 0);
1430 /* Check for failure */
1431 if (!NT_SUCCESS(Status
))
1435 /* Allocate SrbData, if needed */
1436 if (DeviceExtension
->NeedSrbDataAlloc
)
1439 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1441 if (DeviceExtension
->SrbDataCount
!= 0)
1442 Count
= DeviceExtension
->SrbDataCount
;
1444 Count
= DeviceExtension
->RequestsNumber
* 2;
1446 /* Allocate the data */
1447 SrbData
= ExAllocatePoolWithTag(NonPagedPool
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
), TAG_SCSIPORT
);
1448 if (SrbData
== NULL
)
1449 return STATUS_INSUFFICIENT_RESOURCES
;
1451 RtlZeroMemory(SrbData
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
));
1453 DeviceExtension
->SrbInfo
= SrbData
;
1454 DeviceExtension
->FreeSrbInfo
= SrbData
;
1455 DeviceExtension
->SrbDataCount
= Count
;
1457 /* Link it to the list */
1460 SrbData
->Requests
.Flink
= (PLIST_ENTRY
)(SrbData
+ 1);
1465 /* Mark the last entry of the list */
1467 SrbData
->Requests
.Flink
= NULL
;
1470 /* Initialize port capabilities */
1471 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1472 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1473 PortCapabilities
->MaximumTransferLength
= PortConfig
->MaximumTransferLength
;
1475 if (PortConfig
->ReceiveEvent
)
1476 PortCapabilities
->SupportedAsynchronousEvents
|= SRBEV_SCSI_ASYNC_NOTIFICATION
;
1478 PortCapabilities
->TaggedQueuing
= DeviceExtension
->SupportsTaggedQueuing
;
1479 PortCapabilities
->AdapterScansDown
= PortConfig
->AdapterScansDown
;
1481 if (PortConfig
->AlignmentMask
> PortDeviceObject
->AlignmentRequirement
)
1482 PortDeviceObject
->AlignmentRequirement
= PortConfig
->AlignmentMask
;
1484 PortCapabilities
->AlignmentMask
= PortDeviceObject
->AlignmentRequirement
;
1486 if (PortCapabilities
->MaximumPhysicalPages
== 0)
1488 PortCapabilities
->MaximumPhysicalPages
=
1489 BYTES_TO_PAGES(PortCapabilities
->MaximumTransferLength
);
1491 /* Apply miniport's limits */
1492 if (PortConfig
->NumberOfPhysicalBreaks
< PortCapabilities
->MaximumPhysicalPages
)
1494 PortCapabilities
->MaximumPhysicalPages
= PortConfig
->NumberOfPhysicalBreaks
;
1498 /* Deal with interrupts */
1499 if (DeviceExtension
->HwInterrupt
== NULL
||
1500 (PortConfig
->BusInterruptLevel
== 0 && PortConfig
->BusInterruptVector
== 0))
1503 DeviceExtension
->InterruptCount
= 0;
1505 DPRINT1("Interrupt Count: 0\n");
1509 /* This code path will ALWAYS crash so stop it now */
1514 BOOLEAN InterruptShareable
;
1515 KINTERRUPT_MODE InterruptMode
[2];
1516 ULONG InterruptVector
[2], i
, MappedIrq
[2];
1517 KIRQL Dirql
[2], MaxDirql
;
1518 KAFFINITY Affinity
[2];
1520 DeviceExtension
->InterruptLevel
[0] = PortConfig
->BusInterruptLevel
;
1521 DeviceExtension
->InterruptLevel
[1] = PortConfig
->BusInterruptLevel2
;
1523 InterruptVector
[0] = PortConfig
->BusInterruptVector
;
1524 InterruptVector
[1] = PortConfig
->BusInterruptVector2
;
1526 InterruptMode
[0] = PortConfig
->InterruptMode
;
1527 InterruptMode
[1] = PortConfig
->InterruptMode2
;
1529 DeviceExtension
->InterruptCount
= (PortConfig
->BusInterruptLevel2
!= 0 || PortConfig
->BusInterruptVector2
!= 0) ? 2 : 1;
1531 for (i
= 0; i
< DeviceExtension
->InterruptCount
; i
++)
1533 /* Register an interrupt handler for this device */
1534 MappedIrq
[i
] = HalGetInterruptVector(PortConfig
->AdapterInterfaceType
,
1535 PortConfig
->SystemIoBusNumber
,
1536 DeviceExtension
->InterruptLevel
[i
],
1542 if (DeviceExtension
->InterruptCount
== 1 || Dirql
[0] > Dirql
[1])
1543 MaxDirql
= Dirql
[0];
1545 MaxDirql
= Dirql
[1];
1547 for (i
= 0; i
< DeviceExtension
->InterruptCount
; i
++)
1549 /* Determine IRQ sharability as usual */
1550 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1551 InterruptMode
[i
] == LevelSensitive
)
1553 InterruptShareable
= TRUE
;
1557 InterruptShareable
= FALSE
;
1560 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
[i
],
1561 (PKSERVICE_ROUTINE
)ScsiPortIsr
,
1563 &DeviceExtension
->IrqLock
,
1572 if (!(NT_SUCCESS(Status
)))
1574 DPRINT1("Could not connect interrupt %d\n",
1575 InterruptVector
[i
]);
1576 DeviceExtension
->Interrupt
[i
] = NULL
;
1581 if (!NT_SUCCESS(Status
))
1585 /* Save IoAddress (from access ranges) */
1586 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1588 DeviceExtension
->IoAddress
=
1589 ((*(PortConfig
->AccessRanges
))[0]).RangeStart
.LowPart
;
1591 DPRINT("Io Address %x\n", DeviceExtension
->IoAddress
);
1594 /* Set flag that it's allowed to disconnect during this command */
1595 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
1597 /* Initialize counter of active requests (-1 means there are none) */
1598 DeviceExtension
->ActiveRequestCounter
= -1;
1600 /* Analyze what we have about DMA */
1601 if (DeviceExtension
->AdapterObject
!= NULL
&&
1602 PortConfig
->Master
&&
1603 PortConfig
->NeedPhysicalAddresses
)
1605 DeviceExtension
->MapRegisters
= TRUE
;
1609 DeviceExtension
->MapRegisters
= FALSE
;
1612 /* Call HwInitialize at DISPATCH_LEVEL */
1613 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1615 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
1616 DeviceExtension
->HwInitialize
,
1617 DeviceExtension
->MiniPortDeviceExtension
))
1619 DPRINT1("HwInitialize() failed!\n");
1620 KeLowerIrql(OldIrql
);
1621 Status
= STATUS_ADAPTER_HARDWARE_ERROR
;
1625 /* Check if a notification is needed */
1626 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
1628 /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1629 ScsiPortDpcForIsr(NULL
,
1630 DeviceExtension
->DeviceObject
,
1635 /* Lower irql back to what it was */
1636 KeLowerIrql(OldIrql
);
1638 /* Start our timer */
1639 IoStartTimer(PortDeviceObject
);
1641 /* Initialize bus scanning information */
1642 BusConfigSize
= FIELD_OFFSET(BUSES_CONFIGURATION_INFORMATION
,
1643 BusScanInfo
[DeviceExtension
->PortConfig
->NumberOfBuses
]);
1644 DeviceExtension
->BusesConfig
= ExAllocatePoolWithTag(PagedPool
,
1647 if (!DeviceExtension
->BusesConfig
)
1649 DPRINT1("Out of resources!\n");
1650 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1655 RtlZeroMemory(DeviceExtension
->BusesConfig
, BusConfigSize
);
1657 /* Store number of buses there */
1658 DeviceExtension
->BusesConfig
->NumberOfBuses
= (UCHAR
)DeviceExtension
->BusNum
;
1660 /* Scan the adapter for devices */
1661 SpiScanAdapter(DeviceExtension
);
1663 /* Build the registry device map */
1664 SpiBuildDeviceMap(DeviceExtension
,
1665 (PUNICODE_STRING
)Argument2
);
1667 /* Create the dos device link */
1668 swprintf(DosNameBuffer
,
1670 SystemConfig
->ScsiPortCount
);
1671 RtlInitUnicodeString(&DosDeviceName
, DosNameBuffer
);
1672 IoCreateSymbolicLink(&DosDeviceName
, &DeviceName
);
1674 /* Increase the port count */
1675 SystemConfig
->ScsiPortCount
++;
1676 FirstConfigCall
= FALSE
;
1678 /* Increase adapter number and bus number respectively */
1679 ConfigInfo
.AdapterNumber
++;
1682 ConfigInfo
.BusNumber
++;
1684 DPRINT("Bus: %lu MaxBus: %lu\n", ConfigInfo
.BusNumber
, MaxBus
);
1689 /* Clean up the mess */
1690 SpiCleanupAfterInit(DeviceExtension
);
1692 /* Close registry keys */
1693 if (ConfigInfo
.ServiceKey
!= NULL
)
1694 ZwClose(ConfigInfo
.ServiceKey
);
1696 if (ConfigInfo
.DeviceKey
!= NULL
)
1697 ZwClose(ConfigInfo
.DeviceKey
);
1699 if (ConfigInfo
.BusKey
!= NULL
)
1700 ZwClose(ConfigInfo
.BusKey
);
1702 if (ConfigInfo
.AccessRanges
!= NULL
)
1703 ExFreePool(ConfigInfo
.AccessRanges
);
1705 if (ConfigInfo
.Parameter
!= NULL
)
1706 ExFreePool(ConfigInfo
.Parameter
);
1708 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1709 Status
, DeviceFound
);
1711 return (DeviceFound
== FALSE
) ? Status
: STATUS_SUCCESS
;
1715 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1717 PSCSI_LUN_INFO LunInfo
;
1721 /* Check if we have something to clean up */
1722 if (DeviceExtension
== NULL
)
1725 /* Stop the timer */
1726 IoStopTimer(DeviceExtension
->DeviceObject
);
1728 /* Disconnect the interrupts */
1729 while (DeviceExtension
->InterruptCount
)
1731 if (DeviceExtension
->Interrupt
[--DeviceExtension
->InterruptCount
])
1732 IoDisconnectInterrupt(DeviceExtension
->Interrupt
[DeviceExtension
->InterruptCount
]);
1735 /* Delete ConfigInfo */
1736 if (DeviceExtension
->BusesConfig
)
1738 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
1740 if (!DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
])
1743 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
1747 /* Free current, but save pointer to the next one */
1748 Ptr
= LunInfo
->Next
;
1749 ExFreePool(LunInfo
);
1753 ExFreePool(DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]);
1756 ExFreePool(DeviceExtension
->BusesConfig
);
1759 /* Free PortConfig */
1760 if (DeviceExtension
->PortConfig
)
1761 ExFreePool(DeviceExtension
->PortConfig
);
1764 for(Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
1766 while (DeviceExtension
->LunExtensionList
[Lun
])
1768 Ptr
= DeviceExtension
->LunExtensionList
[Lun
];
1769 DeviceExtension
->LunExtensionList
[Lun
] = DeviceExtension
->LunExtensionList
[Lun
]->Next
;
1775 /* Free common buffer (if it exists) */
1776 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
&&
1777 DeviceExtension
->CommonBufferLength
!= 0)
1779 if (!DeviceExtension
->AdapterObject
)
1781 ExFreePool(DeviceExtension
->SrbExtensionBuffer
);
1785 HalFreeCommonBuffer(DeviceExtension
->AdapterObject
,
1786 DeviceExtension
->CommonBufferLength
,
1787 DeviceExtension
->PhysicalAddress
,
1788 DeviceExtension
->SrbExtensionBuffer
,
1794 if (DeviceExtension
->SrbInfo
!= NULL
)
1795 ExFreePool(DeviceExtension
->SrbInfo
);
1797 /* Unmap mapped addresses */
1798 while (DeviceExtension
->MappedAddressList
!= NULL
)
1800 MmUnmapIoSpace(DeviceExtension
->MappedAddressList
->MappedAddress
,
1801 DeviceExtension
->MappedAddressList
->NumberOfBytes
);
1803 Ptr
= DeviceExtension
->MappedAddressList
;
1804 DeviceExtension
->MappedAddressList
= DeviceExtension
->MappedAddressList
->NextMappedAddress
;
1809 /* Finally delete the device object */
1810 DPRINT("Deleting device %p\n", DeviceExtension
->DeviceObject
);
1811 IoDeleteDevice(DeviceExtension
->DeviceObject
);
1818 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
1819 IN PSCSI_REQUEST_BLOCK Srb
,
1820 IN PVOID LogicalAddress
,
1823 DPRINT1("ScsiPortIoMapTransfer()\n");
1831 ScsiPortLogError(IN PVOID HwDeviceExtension
,
1832 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
1839 //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1841 DPRINT1("ScsiPortLogError() called\n");
1842 DPRINT1("PathId: 0x%02x TargetId: 0x%02x Lun: 0x%02x ErrorCode: 0x%08lx UniqueId: 0x%08lx\n",
1843 PathId
, TargetId
, Lun
, ErrorCode
, UniqueId
);
1845 //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1848 DPRINT("ScsiPortLogError() done\n");
1855 ScsiPortMoveMemory(OUT PVOID Destination
,
1859 RtlMoveMemory(Destination
,
1869 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
1870 IN PVOID HwDeviceExtension
,
1873 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1876 DPRINT("ScsiPortNotification() called\n");
1878 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1879 SCSI_PORT_DEVICE_EXTENSION
,
1880 MiniPortDeviceExtension
);
1882 DPRINT("DeviceExtension %p\n", DeviceExtension
);
1884 va_start(ap
, HwDeviceExtension
);
1886 switch (NotificationType
)
1888 case RequestComplete
:
1890 PSCSI_REQUEST_BLOCK Srb
;
1891 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1893 Srb
= (PSCSI_REQUEST_BLOCK
) va_arg (ap
, PSCSI_REQUEST_BLOCK
);
1895 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb
);
1897 /* Make sure Srb is alright */
1898 ASSERT(Srb
->SrbStatus
!= SRB_STATUS_PENDING
);
1899 ASSERT(Srb
->Function
!= SRB_FUNCTION_EXECUTE_SCSI
|| Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
|| Srb
->ScsiStatus
== SCSISTAT_GOOD
);
1901 if (!(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
1903 /* It's been already completed */
1908 /* It's not active anymore */
1909 Srb
->SrbFlags
&= ~SRB_FLAGS_IS_ACTIVE
;
1911 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
1913 /* TODO: Treat it specially */
1918 /* Get the SRB data */
1919 SrbData
= SpiGetSrbData(DeviceExtension
,
1925 /* Make sure there are no CompletedRequests and there is a Srb */
1926 ASSERT(SrbData
->CompletedRequests
== NULL
&& SrbData
->Srb
!= NULL
);
1928 /* If it's a read/write request, make sure it has data inside it */
1929 if ((Srb
->SrbStatus
== SRB_STATUS_SUCCESS
) &&
1930 ((Srb
->Cdb
[0] == SCSIOP_READ
) || (Srb
->Cdb
[0] == SCSIOP_WRITE
)))
1932 ASSERT(Srb
->DataTransferLength
);
1935 SrbData
->CompletedRequests
= DeviceExtension
->InterruptData
.CompletedRequests
;
1936 DeviceExtension
->InterruptData
.CompletedRequests
= SrbData
;
1942 DPRINT("Notify: NextRequest\n");
1943 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1951 PSCSI_PORT_LUN_EXTENSION LunExtension
;
1953 PathId
= (UCHAR
) va_arg (ap
, int);
1954 TargetId
= (UCHAR
) va_arg (ap
, int);
1955 Lun
= (UCHAR
) va_arg (ap
, int);
1957 DPRINT("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1958 PathId
, TargetId
, Lun
);
1960 /* Mark it in the flags field */
1961 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1963 /* Get the LUN extension */
1964 LunExtension
= SpiGetLunExtension(DeviceExtension
,
1969 /* If returned LunExtension is NULL, break out */
1970 if (!LunExtension
) break;
1972 /* This request should not be processed if */
1973 if ((LunExtension
->ReadyLun
) ||
1974 (LunExtension
->SrbInfo
.Srb
))
1976 /* Nothing to do here */
1980 /* Add this LUN to the list */
1981 LunExtension
->ReadyLun
= DeviceExtension
->InterruptData
.ReadyLun
;
1982 DeviceExtension
->InterruptData
.ReadyLun
= LunExtension
;
1987 DPRINT("Notify: ResetDetected\n");
1988 /* Add RESET flags */
1989 DeviceExtension
->InterruptData
.Flags
|=
1990 SCSI_PORT_RESET
| SCSI_PORT_RESET_REPORTED
;
1993 case CallDisableInterrupts
:
1994 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
1997 case CallEnableInterrupts
:
1998 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
2001 case RequestTimerCall
:
2002 DPRINT("Notify: RequestTimerCall\n");
2003 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_TIMER_NEEDED
;
2004 DeviceExtension
->InterruptData
.HwScsiTimer
= (PHW_TIMER
)va_arg(ap
, PHW_TIMER
);
2005 DeviceExtension
->InterruptData
.MiniportTimerValue
= (ULONG
)va_arg(ap
, ULONG
);
2008 case BusChangeDetected
:
2009 DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
2013 DPRINT1 ("Unsupported notification from WMI: %lu\n", NotificationType
);
2019 /* Request a DPC after we're done with the interrupt */
2020 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NOTIFICATION_NEEDED
;
2027 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
2028 IN INTERFACE_TYPE BusType
,
2029 IN ULONG SystemIoBusNumber
,
2030 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
2031 IN ULONG NumberOfBytes
,
2032 IN BOOLEAN InIoSpace
)
2034 DPRINT("ScsiPortValidateRange()\n");
2039 /* INTERNAL FUNCTIONS ********************************************************/
2042 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
2043 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
2044 IN PPORT_CONFIGURATION_INFORMATION PortConfig
)
2046 PACCESS_RANGE AccessRange
;
2047 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData
;
2050 ULONG Interrupt
= 0;
2055 /* Loop through all entries */
2056 for (Index
= 0; Index
< ResourceDescriptor
->PartialResourceList
.Count
; Index
++)
2058 PartialData
= &ResourceDescriptor
->PartialResourceList
.PartialDescriptors
[Index
];
2060 switch (PartialData
->Type
)
2062 case CmResourceTypePort
:
2063 /* Copy access ranges */
2064 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
2066 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
2068 AccessRange
->RangeStart
= PartialData
->u
.Port
.Start
;
2069 AccessRange
->RangeLength
= PartialData
->u
.Port
.Length
;
2071 AccessRange
->RangeInMemory
= FALSE
;
2076 case CmResourceTypeMemory
:
2077 /* Copy access ranges */
2078 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
2080 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
2082 AccessRange
->RangeStart
= PartialData
->u
.Memory
.Start
;
2083 AccessRange
->RangeLength
= PartialData
->u
.Memory
.Length
;
2085 AccessRange
->RangeInMemory
= TRUE
;
2090 case CmResourceTypeInterrupt
:
2094 /* Copy interrupt data */
2095 PortConfig
->BusInterruptLevel
= PartialData
->u
.Interrupt
.Level
;
2096 PortConfig
->BusInterruptVector
= PartialData
->u
.Interrupt
.Vector
;
2098 /* Set interrupt mode accordingly to the resource */
2099 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
2101 PortConfig
->InterruptMode
= Latched
;
2103 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
2105 PortConfig
->InterruptMode
= LevelSensitive
;
2108 else if (Interrupt
== 1)
2110 /* Copy interrupt data */
2111 PortConfig
->BusInterruptLevel2
= PartialData
->u
.Interrupt
.Level
;
2112 PortConfig
->BusInterruptVector2
= PartialData
->u
.Interrupt
.Vector
;
2114 /* Set interrupt mode accordingly to the resource */
2115 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
2117 PortConfig
->InterruptMode2
= Latched
;
2119 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
2121 PortConfig
->InterruptMode2
= LevelSensitive
;
2128 case CmResourceTypeDma
:
2132 PortConfig
->DmaChannel
= PartialData
->u
.Dma
.Channel
;
2133 PortConfig
->DmaPort
= PartialData
->u
.Dma
.Port
;
2135 if (PartialData
->Flags
& CM_RESOURCE_DMA_8
)
2136 PortConfig
->DmaWidth
= Width8Bits
;
2137 else if ((PartialData
->Flags
& CM_RESOURCE_DMA_16
) ||
2138 (PartialData
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
2139 PortConfig
->DmaWidth
= Width16Bits
;
2140 else if (PartialData
->Flags
& CM_RESOURCE_DMA_32
)
2141 PortConfig
->DmaWidth
= Width32Bits
;
2145 PortConfig
->DmaChannel2
= PartialData
->u
.Dma
.Channel
;
2146 PortConfig
->DmaPort2
= PartialData
->u
.Dma
.Port
;
2148 if (PartialData
->Flags
& CM_RESOURCE_DMA_8
)
2149 PortConfig
->DmaWidth2
= Width8Bits
;
2150 else if ((PartialData
->Flags
& CM_RESOURCE_DMA_16
) ||
2151 (PartialData
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
2152 PortConfig
->DmaWidth2
= Width16Bits
;
2153 else if (PartialData
->Flags
& CM_RESOURCE_DMA_32
)
2154 PortConfig
->DmaWidth2
= Width32Bits
;
2161 static PCM_RESOURCE_LIST
2162 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2163 PPORT_CONFIGURATION_INFORMATION PortConfig
)
2165 PCONFIGURATION_INFORMATION ConfigInfo
;
2166 PCM_RESOURCE_LIST ResourceList
;
2167 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
2168 PACCESS_RANGE AccessRange
;
2169 ULONG ListLength
= 0, i
, FullSize
;
2170 ULONG Interrupt
, Dma
;
2172 /* Get current Atdisk usage from the system */
2173 ConfigInfo
= IoGetConfigurationInformation();
2175 if (PortConfig
->AtdiskPrimaryClaimed
)
2176 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
2178 if (PortConfig
->AtdiskSecondaryClaimed
)
2179 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
2181 /* Do we use DMA? */
2182 if (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
||
2183 PortConfig
->DmaPort
!= SP_UNINITIALIZED_VALUE
)
2187 if (PortConfig
->DmaChannel2
!= SP_UNINITIALIZED_VALUE
||
2188 PortConfig
->DmaPort2
!= SP_UNINITIALIZED_VALUE
)
2197 /* How many interrupts to we have? */
2198 Interrupt
= DeviceExtension
->InterruptCount
;
2199 ListLength
+= Interrupt
;
2201 /* How many access ranges do we use? */
2202 AccessRange
= &((*(PortConfig
->AccessRanges
))[0]);
2203 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2205 if (AccessRange
->RangeLength
!= 0)
2211 /* Allocate the resource list, since we know its size now */
2212 FullSize
= sizeof(CM_RESOURCE_LIST
) + (ListLength
- 1) *
2213 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
2215 ResourceList
= (PCM_RESOURCE_LIST
)ExAllocatePoolWithTag(PagedPool
, FullSize
, TAG_SCSIPORT
);
2221 RtlZeroMemory(ResourceList
, FullSize
);
2224 ResourceList
->Count
= 1;
2225 ResourceList
->List
[0].InterfaceType
= PortConfig
->AdapterInterfaceType
;
2226 ResourceList
->List
[0].BusNumber
= PortConfig
->SystemIoBusNumber
;
2227 ResourceList
->List
[0].PartialResourceList
.Count
= ListLength
;
2228 ResourceDescriptor
= ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
;
2230 /* Copy access ranges array over */
2231 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2233 AccessRange
= &((*(PortConfig
->AccessRanges
))[i
]);
2235 /* If the range is empty - skip it */
2236 if (AccessRange
->RangeLength
== 0)
2239 if (AccessRange
->RangeInMemory
)
2241 ResourceDescriptor
->Type
= CmResourceTypeMemory
;
2242 ResourceDescriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
;
2246 ResourceDescriptor
->Type
= CmResourceTypePort
;
2247 ResourceDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
2250 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2252 ResourceDescriptor
->u
.Memory
.Start
= AccessRange
->RangeStart
;
2253 ResourceDescriptor
->u
.Memory
.Length
= AccessRange
->RangeLength
;
2255 ResourceDescriptor
++;
2258 /* If we use interrupt(s), copy them */
2261 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2263 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2264 ((Interrupt
== 2) ? PortConfig
->InterruptMode2
: PortConfig
->InterruptMode
) == LevelSensitive
)
2266 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2267 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2271 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2272 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2275 ResourceDescriptor
->u
.Interrupt
.Level
= (Interrupt
== 2) ? PortConfig
->BusInterruptLevel2
: PortConfig
->BusInterruptLevel
;
2276 ResourceDescriptor
->u
.Interrupt
.Vector
= (Interrupt
== 2) ? PortConfig
->BusInterruptVector2
: PortConfig
->BusInterruptVector
;
2277 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2279 ResourceDescriptor
++;
2286 ResourceDescriptor
->Type
= CmResourceTypeDma
;
2287 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2288 ResourceDescriptor
->u
.Dma
.Channel
= (Dma
== 2) ? PortConfig
->DmaChannel2
: PortConfig
->DmaChannel
;
2289 ResourceDescriptor
->u
.Dma
.Port
= (Dma
== 2) ? PortConfig
->DmaPort2
: PortConfig
->DmaPort
;
2290 ResourceDescriptor
->Flags
= 0;
2292 if (((Dma
== 2) ? PortConfig
->DmaWidth2
: PortConfig
->DmaWidth
) == Width8Bits
)
2293 ResourceDescriptor
->Flags
|= CM_RESOURCE_DMA_8
;
2294 else if (((Dma
== 2) ? PortConfig
->DmaWidth2
: PortConfig
->DmaWidth
) == Width16Bits
)
2295 ResourceDescriptor
->Flags
|= CM_RESOURCE_DMA_16
;
2297 ResourceDescriptor
->Flags
|= CM_RESOURCE_DMA_32
;
2299 if (((Dma
== 2) ? PortConfig
->DmaChannel2
: PortConfig
->DmaChannel
) == SP_UNINITIALIZED_VALUE
)
2300 ResourceDescriptor
->u
.Dma
.Channel
= 0;
2302 if (((Dma
== 2) ? PortConfig
->DmaPort2
: PortConfig
->DmaPort
) == SP_UNINITIALIZED_VALUE
)
2303 ResourceDescriptor
->u
.Dma
.Port
= 0;
2305 ResourceDescriptor
++;
2309 return ResourceList
;
2314 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
2315 IN PDEVICE_OBJECT DeviceObject
,
2316 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
2317 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
2318 IN PUNICODE_STRING RegistryPath
,
2320 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
)
2322 PCI_COMMON_CONFIG PciConfig
;
2323 PCI_SLOT_NUMBER SlotNumber
;
2326 ULONG FunctionNumber
;
2327 CHAR VendorIdString
[8];
2328 CHAR DeviceIdString
[8];
2329 UNICODE_STRING UnicodeStr
;
2330 PCM_RESOURCE_LIST ResourceList
= NULL
;
2333 DPRINT ("SpiGetPciConfiguration() called\n");
2335 SlotNumber
.u
.AsULONG
= 0;
2337 /* Loop through all devices */
2338 for (DeviceNumber
= NextSlotNumber
->u
.bits
.DeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
2340 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
2342 /* Loop through all functions */
2343 for (FunctionNumber
= NextSlotNumber
->u
.bits
.FunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
2345 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
2347 /* Get PCI config bytes */
2348 DataSize
= HalGetBusData(PCIConfiguration
,
2350 SlotNumber
.u
.AsULONG
,
2354 /* If result of HalGetBusData is 0, then the bus is wrong */
2358 /* Check if result is PCI_INVALID_VENDORID or too small */
2359 if ((DataSize
< sizeof(ULONG
)) ||
2360 (PciConfig
.VendorID
== PCI_INVALID_VENDORID
))
2362 /* Continue to try the next function */
2366 sprintf (VendorIdString
, "%04hx", PciConfig
.VendorID
);
2367 sprintf (DeviceIdString
, "%04hx", PciConfig
.DeviceID
);
2369 if (_strnicmp(VendorIdString
, HwInitializationData
->VendorId
, HwInitializationData
->VendorIdLength
) ||
2370 _strnicmp(DeviceIdString
, HwInitializationData
->DeviceId
, HwInitializationData
->DeviceIdLength
))
2372 /* It is not our device */
2376 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2380 SlotNumber
.u
.bits
.DeviceNumber
,
2381 SlotNumber
.u
.bits
.FunctionNumber
);
2384 RtlInitUnicodeString(&UnicodeStr
, L
"ScsiAdapter");
2385 Status
= HalAssignSlotResources(RegistryPath
,
2391 SlotNumber
.u
.AsULONG
,
2394 if (!NT_SUCCESS(Status
))
2397 /* Create configuration information */
2398 SpiResourceToConfig(HwInitializationData
,
2402 /* Free the resource list */
2403 ExFreePool(ResourceList
);
2405 /* Set dev & fn numbers */
2406 NextSlotNumber
->u
.bits
.DeviceNumber
= DeviceNumber
;
2407 NextSlotNumber
->u
.bits
.FunctionNumber
= FunctionNumber
+ 1;
2409 /* Save the slot number */
2410 PortConfig
->SlotNumber
= SlotNumber
.u
.AsULONG
;
2414 NextSlotNumber
->u
.bits
.FunctionNumber
= 0;
2417 NextSlotNumber
->u
.bits
.DeviceNumber
= 0;
2418 DPRINT ("No device found\n");
2425 /**********************************************************************
2427 * ScsiPortCreateClose
2430 * Answer requests for Create/Close calls: a null operation.
2437 * Pointer to a device object.
2440 * Pointer to an IRP.
2446 static NTSTATUS NTAPI
2447 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
2450 DPRINT("ScsiPortCreateClose()\n");
2452 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2453 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2455 return STATUS_SUCCESS
;
2459 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2462 PSCSI_LUN_INFO LunInfo
;
2463 PIO_STACK_LOCATION IrpStack
;
2464 PDEVICE_OBJECT DeviceObject
;
2465 PSCSI_REQUEST_BLOCK Srb
;
2468 /* Get pointer to the SRB */
2469 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2470 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
2472 /* Check if PathId matches number of buses */
2473 if (DeviceExtension
->BusesConfig
== NULL
||
2474 DeviceExtension
->BusesConfig
->NumberOfBuses
<= Srb
->PathId
)
2476 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2477 return STATUS_DEVICE_DOES_NOT_EXIST
;
2480 /* Get pointer to LunInfo */
2481 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Srb
->PathId
]->LunInfo
;
2483 /* Find matching LunInfo */
2486 if (LunInfo
->PathId
== Srb
->PathId
&&
2487 LunInfo
->TargetId
== Srb
->TargetId
&&
2488 LunInfo
->Lun
== Srb
->Lun
)
2493 LunInfo
= LunInfo
->Next
;
2496 /* If we couldn't find it - exit */
2497 if (LunInfo
== NULL
)
2498 return STATUS_DEVICE_DOES_NOT_EXIST
;
2502 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2504 /* Release, if asked */
2505 if (Srb
->Function
== SRB_FUNCTION_RELEASE_DEVICE
)
2507 LunInfo
->DeviceClaimed
= FALSE
;
2508 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2509 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2511 return STATUS_SUCCESS
;
2514 /* Attach, if not already claimed */
2515 if (LunInfo
->DeviceClaimed
)
2517 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2518 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
2520 return STATUS_DEVICE_BUSY
;
2523 /* Save the device object */
2524 DeviceObject
= LunInfo
->DeviceObject
;
2526 if (Srb
->Function
== SRB_FUNCTION_CLAIM_DEVICE
)
2527 LunInfo
->DeviceClaimed
= TRUE
;
2529 if (Srb
->Function
== SRB_FUNCTION_ATTACH_DEVICE
)
2530 LunInfo
->DeviceObject
= Srb
->DataBuffer
;
2532 Srb
->DataBuffer
= DeviceObject
;
2534 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2535 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2537 return STATUS_SUCCESS
;
2541 /**********************************************************************
2543 * ScsiPortDispatchScsi
2546 * Answer requests for SCSI calls
2552 * Standard dispatch arguments
2558 static NTSTATUS NTAPI
2559 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
2562 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2563 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2564 PIO_STACK_LOCATION Stack
;
2565 PSCSI_REQUEST_BLOCK Srb
;
2567 NTSTATUS Status
= STATUS_SUCCESS
;
2568 PIRP NextIrp
, IrpList
;
2569 PKDEVICE_QUEUE_ENTRY Entry
;
2571 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2574 DeviceExtension
= DeviceObject
->DeviceExtension
;
2575 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2577 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2580 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2581 Status
= STATUS_UNSUCCESSFUL
;
2583 Irp
->IoStatus
.Status
= Status
;
2584 Irp
->IoStatus
.Information
= 0;
2586 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2591 DPRINT("Srb: %p\n", Srb
);
2592 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
2593 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
2595 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2599 if (LunExtension
== NULL
)
2601 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2602 Status
= STATUS_NO_SUCH_DEVICE
;
2604 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2605 Irp
->IoStatus
.Status
= Status
;
2606 Irp
->IoStatus
.Information
= 0;
2608 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2613 switch (Srb
->Function
)
2615 case SRB_FUNCTION_SHUTDOWN
:
2616 case SRB_FUNCTION_FLUSH
:
2617 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2618 if (DeviceExtension
->CachesData
== FALSE
)
2620 /* All success here */
2621 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2622 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2623 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2624 return STATUS_SUCCESS
;
2626 /* Fall through to a usual execute operation */
2628 case SRB_FUNCTION_EXECUTE_SCSI
:
2629 case SRB_FUNCTION_IO_CONTROL
:
2630 DPRINT(" SRB_FUNCTION_EXECUTE_SCSI or SRB_FUNCTION_IO_CONTROL\n");
2631 /* Mark IRP as pending in all cases */
2632 IoMarkIrpPending(Irp
);
2634 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2636 /* Start IO directly */
2637 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2643 /* We need to be at DISPATCH_LEVEL */
2644 KeRaiseIrql (DISPATCH_LEVEL
, &oldIrql
);
2646 /* Insert IRP into the queue */
2647 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
2648 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
2651 /* It means the queue is empty, and we just start this request */
2652 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2655 /* Back to the old IRQL */
2656 KeLowerIrql (oldIrql
);
2658 return STATUS_PENDING
;
2660 case SRB_FUNCTION_CLAIM_DEVICE
:
2661 case SRB_FUNCTION_ATTACH_DEVICE
:
2662 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2664 /* Reference device object and keep the device object */
2665 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2668 case SRB_FUNCTION_RELEASE_DEVICE
:
2669 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2671 /* Dereference device object and clear the device object */
2672 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2675 case SRB_FUNCTION_RELEASE_QUEUE
:
2676 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2678 /* Guard with the spinlock */
2679 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2681 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2683 DPRINT("Queue is not frozen really\n");
2685 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2686 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2687 Status
= STATUS_SUCCESS
;
2692 /* Unfreeze the queue */
2693 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2695 if (LunExtension
->SrbInfo
.Srb
== NULL
)
2697 /* Get next logical unit request */
2698 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
2700 /* SpiGetNextRequestFromLun() releases the spinlock */
2705 DPRINT("The queue has active request\n");
2706 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2710 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2711 Status
= STATUS_SUCCESS
;
2714 case SRB_FUNCTION_FLUSH_QUEUE
:
2715 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2717 /* Guard with the spinlock */
2718 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2720 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2722 DPRINT("Queue is not frozen really\n");
2724 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2725 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2729 /* Make sure there is no active request */
2730 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
2732 /* Compile a list from the device queue */
2734 while ((Entry
= KeRemoveDeviceQueue(&LunExtension
->DeviceQueue
)) != NULL
)
2736 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
2739 Stack
= IoGetCurrentIrpStackLocation(NextIrp
);
2740 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2743 Srb
->SrbStatus
= SRB_STATUS_REQUEST_FLUSHED
;
2744 NextIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2746 /* Add then to the list */
2747 NextIrp
->Tail
.Overlay
.ListEntry
.Flink
= (PLIST_ENTRY
)IrpList
;
2751 /* Unfreeze the queue */
2752 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2754 /* Release the spinlock */
2755 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2757 /* Complete those requests */
2761 IrpList
= (PIRP
)NextIrp
->Tail
.Overlay
.ListEntry
.Flink
;
2763 IoCompleteRequest(NextIrp
, 0);
2766 Status
= STATUS_SUCCESS
;
2770 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
2771 Status
= STATUS_NOT_IMPLEMENTED
;
2775 Irp
->IoStatus
.Status
= Status
;
2777 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2783 /**********************************************************************
2785 * ScsiPortDeviceControl
2788 * Answer requests for device control calls
2794 * Standard dispatch arguments
2800 static NTSTATUS NTAPI
2801 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
2804 PIO_STACK_LOCATION Stack
;
2805 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2806 PDUMP_POINTERS DumpPointers
;
2809 DPRINT("ScsiPortDeviceControl()\n");
2811 Irp
->IoStatus
.Information
= 0;
2813 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2814 DeviceExtension
= DeviceObject
->DeviceExtension
;
2816 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
2818 case IOCTL_SCSI_GET_DUMP_POINTERS
:
2819 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2821 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DUMP_POINTERS
))
2823 Status
= STATUS_BUFFER_OVERFLOW
;
2824 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2828 DumpPointers
= Irp
->AssociatedIrp
.SystemBuffer
;
2829 DumpPointers
->DeviceObject
= DeviceObject
;
2832 Status
= STATUS_SUCCESS
;
2833 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2836 case IOCTL_SCSI_GET_CAPABILITIES
:
2837 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2838 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
== sizeof(PVOID
))
2840 *((PVOID
*)Irp
->AssociatedIrp
.SystemBuffer
) = &DeviceExtension
->PortCapabilities
;
2842 Irp
->IoStatus
.Information
= sizeof(PVOID
);
2843 Status
= STATUS_SUCCESS
;
2847 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(IO_SCSI_CAPABILITIES
))
2849 Status
= STATUS_BUFFER_TOO_SMALL
;
2853 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2854 &DeviceExtension
->PortCapabilities
,
2855 sizeof(IO_SCSI_CAPABILITIES
));
2857 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
2858 Status
= STATUS_SUCCESS
;
2861 case IOCTL_SCSI_GET_INQUIRY_DATA
:
2862 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2864 /* Copy inquiry data to the port device extension */
2865 Status
= SpiGetInquiryData(DeviceExtension
, Irp
);
2868 case IOCTL_SCSI_MINIPORT
:
2869 DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
2870 Status
= STATUS_NOT_IMPLEMENTED
;
2873 case IOCTL_SCSI_PASS_THROUGH
:
2874 DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
2875 Status
= STATUS_NOT_IMPLEMENTED
;
2879 if (DEVICE_TYPE_FROM_CTL_CODE(Stack
->Parameters
.DeviceIoControl
.IoControlCode
) == MOUNTDEVCONTROLTYPE
)
2881 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
2883 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
:
2884 DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n");
2886 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
:
2887 DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_UNIQUE_ID\n");
2890 DPRINT1(" got ioctl intended for the mount manager: 0x%lX\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2894 DPRINT1(" unknown ioctl code: 0x%lX\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2896 Status
= STATUS_NOT_IMPLEMENTED
;
2900 /* Complete the request with the given status */
2901 Irp
->IoStatus
.Status
= Status
;
2902 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2909 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
2912 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2913 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2914 PIO_STACK_LOCATION IrpStack
;
2915 PSCSI_REQUEST_BLOCK Srb
;
2916 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2920 DPRINT("ScsiPortStartIo() called!\n");
2922 DeviceExtension
= DeviceObject
->DeviceExtension
;
2923 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2925 DPRINT("DeviceExtension %p\n", DeviceExtension
);
2927 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2929 /* Apply "default" flags */
2930 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
2932 /* Get LUN extension */
2933 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2938 if (DeviceExtension
->NeedSrbDataAlloc
||
2939 DeviceExtension
->NeedSrbExtensionAlloc
)
2942 SrbInfo
= SpiAllocateSrbStructures(DeviceExtension
,
2946 /* Couldn't alloc one or both data structures, return */
2947 if (SrbInfo
== NULL
)
2949 /* We have to call IoStartNextPacket, because this request
2951 if (LunExtension
->Flags
& LUNEX_REQUEST_PENDING
)
2952 IoStartNextPacket(DeviceObject
, FALSE
);
2959 /* No allocations are needed */
2960 SrbInfo
= &LunExtension
->SrbInfo
;
2961 Srb
->SrbExtension
= NULL
;
2962 Srb
->QueueTag
= SP_UNTAGGED
;
2965 /* Increase sequence number of SRB */
2966 if (!SrbInfo
->SequenceNumber
)
2968 /* Increase global sequence number */
2969 DeviceExtension
->SequenceNumber
++;
2972 SrbInfo
->SequenceNumber
= DeviceExtension
->SequenceNumber
;
2975 /* Check some special SRBs */
2976 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2978 /* Some special handling */
2979 DPRINT1("Abort command! Unimplemented now\n");
2986 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
)
2988 // Store the MDL virtual address in SrbInfo structure
2989 SrbInfo
->DataOffset
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2991 if (DeviceExtension
->MapBuffers
)
2993 /* Calculate offset within DataBuffer */
2994 SrbInfo
->DataOffset
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
2995 Srb
->DataBuffer
= SrbInfo
->DataOffset
+
2996 (ULONG
)((PUCHAR
)Srb
->DataBuffer
-
2997 (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3000 if (DeviceExtension
->AdapterObject
)
3003 KeFlushIoBuffers(Irp
->MdlAddress
,
3004 Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? TRUE
: FALSE
,
3008 if (DeviceExtension
->MapRegisters
)
3010 /* Calculate number of needed map registers */
3011 SrbInfo
->NumberOfMapRegisters
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
3013 Srb
->DataTransferLength
);
3015 /* Allocate adapter channel */
3016 Status
= IoAllocateAdapterChannel(DeviceExtension
->AdapterObject
,
3017 DeviceExtension
->DeviceObject
,
3018 SrbInfo
->NumberOfMapRegisters
,
3022 if (!NT_SUCCESS(Status
))
3024 DPRINT1("IoAllocateAdapterChannel() failed!\n");
3026 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
3027 ScsiPortNotification(RequestComplete
,
3028 DeviceExtension
+ 1,
3031 ScsiPortNotification(NextRequest
,
3032 DeviceExtension
+ 1);
3034 /* Request DPC for that work */
3035 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3038 /* Control goes to SpiAdapterControl */
3043 /* Increase active request counter */
3044 CounterResult
= InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
3046 if (CounterResult
== 0 &&
3047 DeviceExtension
->AdapterObject
!= NULL
&&
3048 !DeviceExtension
->MapRegisters
)
3050 IoAllocateAdapterChannel(
3051 DeviceExtension
->AdapterObject
,
3053 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
,
3054 ScsiPortAllocateAdapterChannel
,
3061 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3063 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
3064 ScsiPortStartPacket
,
3067 DPRINT("Synchronization failed!\n");
3069 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3070 Irp
->IoStatus
.Information
= 0;
3071 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3073 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3077 /* Release the spinlock only */
3078 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3082 DPRINT("ScsiPortStartIo() done\n");
3086 static BOOLEAN NTAPI
3087 ScsiPortStartPacket(IN OUT PVOID Context
)
3089 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3090 PIO_STACK_LOCATION IrpStack
;
3091 PSCSI_REQUEST_BLOCK Srb
;
3092 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)Context
;
3093 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3094 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3098 DPRINT("ScsiPortStartPacket() called\n");
3100 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3102 IrpStack
= IoGetCurrentIrpStackLocation(DeviceObject
->CurrentIrp
);
3103 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
3105 /* Get LUN extension */
3106 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3111 /* Check if we are in a reset state */
3112 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
3114 /* Mark the we've got requests while being in the reset state */
3115 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET_REQUEST
;
3119 /* Set the time out value */
3120 DeviceExtension
->TimerCount
= Srb
->TimeOutValue
;
3123 DeviceExtension
->Flags
|= SCSI_PORT_DEVICE_BUSY
;
3125 if (LunExtension
->RequestTimeout
!= -1)
3127 /* Timer already active */
3132 /* It hasn't been initialized yet */
3133 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
3137 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
3139 /* Handle bypass-requests */
3141 /* Is this an abort request? */
3142 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
3144 /* Get pointer to SRB info structure */
3145 SrbInfo
= SpiGetSrbData(DeviceExtension
,
3151 /* Check if the request is still "active" */
3152 if (SrbInfo
== NULL
||
3153 SrbInfo
->Srb
== NULL
||
3154 !(SrbInfo
->Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
3156 /* It's not, mark it as active then */
3157 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
3160 LunExtension
->RequestTimeout
= -1;
3162 DPRINT("Request has been already completed, but abort request came\n");
3163 Srb
->SrbStatus
= SRB_STATUS_ABORT_FAILED
;
3165 /* Notify about request complete */
3166 ScsiPortNotification(RequestComplete
,
3167 DeviceExtension
->MiniPortDeviceExtension
,
3170 /* and about readiness for the next request */
3171 ScsiPortNotification(NextRequest
,
3172 DeviceExtension
->MiniPortDeviceExtension
);
3174 /* They might ask for some work, so queue the DPC for them */
3175 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3177 /* We're done in this branch */
3183 /* Add number of queued requests */
3184 LunExtension
->QueueCount
++;
3187 /* Bypass requests don't need request sense */
3188 LunExtension
->Flags
&= ~LUNEX_NEED_REQUEST_SENSE
;
3190 /* Is disconnect disabled for this request? */
3191 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3193 /* Set the corresponding flag */
3194 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3197 /* Transfer timeout value from Srb to Lun */
3198 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
3202 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3204 /* It's a disconnect, so no more requests can go */
3205 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3208 LunExtension
->Flags
|= SCSI_PORT_LU_ACTIVE
;
3210 /* Increment queue count */
3211 LunExtension
->QueueCount
++;
3213 /* If it's tagged - special thing */
3214 if (Srb
->QueueTag
!= SP_UNTAGGED
)
3216 SrbInfo
= &DeviceExtension
->SrbInfo
[Srb
->QueueTag
- 1];
3218 /* Chek for consistency */
3219 ASSERT(SrbInfo
->Requests
.Blink
== NULL
);
3221 /* Insert it into the list of requests */
3222 InsertTailList(&LunExtension
->SrbInfo
.Requests
, &SrbInfo
->Requests
);
3226 /* Mark this Srb active */
3227 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
3229 /* Call HwStartIo routine */
3230 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
3233 /* If notification is needed, then request a DPC */
3234 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
3235 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3240 IO_ALLOCATION_ACTION
3242 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
,
3244 PVOID MapRegisterBase
,
3247 PSCSI_REQUEST_BLOCK Srb
;
3248 PSCSI_SG_ADDRESS ScatterGatherList
;
3250 PIO_STACK_LOCATION IrpStack
;
3251 ULONG TotalLength
= 0;
3252 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3253 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3255 BOOLEAN WriteToDevice
;
3257 /* Get pointers to SrbInfo and DeviceExtension */
3258 SrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)Context
;
3259 DeviceExtension
= DeviceObject
->DeviceExtension
;
3261 /* Get pointer to SRB */
3262 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3263 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
3265 /* Depending on the map registers number, we allocate
3266 either from NonPagedPool, or from our static list */
3267 if (SrbInfo
->NumberOfMapRegisters
> MAX_SG_LIST
)
3269 SrbInfo
->ScatterGather
= ExAllocatePoolWithTag(
3270 NonPagedPool
, SrbInfo
->NumberOfMapRegisters
* sizeof(SCSI_SG_ADDRESS
), TAG_SCSIPORT
);
3272 if (SrbInfo
->ScatterGather
== NULL
)
3275 Srb
->SrbFlags
|= SRB_FLAGS_SGLIST_FROM_POOL
;
3279 SrbInfo
->ScatterGather
= SrbInfo
->ScatterGatherList
;
3282 /* Use chosen SG list source */
3283 ScatterGatherList
= SrbInfo
->ScatterGather
;
3285 /* Save map registers base */
3286 SrbInfo
->BaseOfMapRegister
= MapRegisterBase
;
3288 /* Determine WriteToDevice flag */
3289 WriteToDevice
= Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
? TRUE
: FALSE
;
3291 /* Get virtual address of the data buffer */
3292 DataVA
= (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
3293 ((PCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
3295 /* Build the actual SG list */
3296 while (TotalLength
< Srb
->DataTransferLength
)
3298 if (!ScatterGatherList
)
3301 ScatterGatherList
->Length
= Srb
->DataTransferLength
- TotalLength
;
3302 ScatterGatherList
->PhysicalAddress
= IoMapTransfer(DeviceExtension
->AdapterObject
,
3305 DataVA
+ TotalLength
,
3306 &ScatterGatherList
->Length
,
3309 TotalLength
+= ScatterGatherList
->Length
;
3310 ScatterGatherList
++;
3313 /* Schedule an active request */
3314 InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
3315 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &CurrentIrql
);
3316 KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
3317 ScsiPortStartPacket
,
3319 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, CurrentIrql
);
3321 return DeallocateObjectKeepRegisters
;
3324 static PSCSI_PORT_LUN_EXTENSION
3325 SpiAllocateLunExtension(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3327 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3328 ULONG LunExtensionSize
;
3330 DPRINT("SpiAllocateLunExtension(%p)\n", DeviceExtension
);
3332 /* Round LunExtensionSize first to the sizeof LONGLONG */
3333 LunExtensionSize
= (DeviceExtension
->LunExtensionSize
+
3334 sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
3336 LunExtensionSize
+= sizeof(SCSI_PORT_LUN_EXTENSION
);
3337 DPRINT("LunExtensionSize %lu\n", LunExtensionSize
);
3339 LunExtension
= ExAllocatePoolWithTag(NonPagedPool
, LunExtensionSize
, TAG_SCSIPORT
);
3340 if (LunExtension
== NULL
)
3342 DPRINT1("Out of resources!\n");
3346 /* Zero everything */
3347 RtlZeroMemory(LunExtension
, LunExtensionSize
);
3349 /* Initialize a list of requests */
3350 InitializeListHead(&LunExtension
->SrbInfo
.Requests
);
3352 /* Initialize timeout counter */
3353 LunExtension
->RequestTimeout
= -1;
3355 /* Set maximum queue size */
3356 LunExtension
->MaxQueueCount
= 256;
3358 /* Initialize request queue */
3359 KeInitializeDeviceQueue(&LunExtension
->DeviceQueue
);
3361 return LunExtension
;
3364 static PSCSI_PORT_LUN_EXTENSION
3365 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3370 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3372 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3373 DeviceExtension
, PathId
, TargetId
, Lun
);
3375 /* Get appropriate list */
3376 LunExtension
= DeviceExtension
->LunExtensionList
[(TargetId
+ Lun
) % LUS_NUMBER
];
3378 /* Iterate it until we find what we need */
3379 while (LunExtension
)
3381 if (LunExtension
->TargetId
== TargetId
&&
3382 LunExtension
->Lun
== Lun
&&
3383 LunExtension
->PathId
== PathId
)
3385 /* All matches, return */
3386 return LunExtension
;
3389 /* Advance to the next item */
3390 LunExtension
= LunExtension
->Next
;
3393 /* We did not find anything */
3394 DPRINT("Nothing found\n");
3398 static PSCSI_REQUEST_BLOCK_INFO
3399 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3400 PSCSI_PORT_LUN_EXTENSION LunExtension
,
3401 PSCSI_REQUEST_BLOCK Srb
)
3404 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3406 /* Spinlock must be held while this function executes */
3407 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3409 /* Allocate SRB data structure */
3410 if (DeviceExtension
->NeedSrbDataAlloc
)
3412 /* Treat the abort request in a special way */
3413 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
3415 SrbInfo
= SpiGetSrbData(DeviceExtension
,
3421 else if (Srb
->SrbFlags
&
3422 (SRB_FLAGS_QUEUE_ACTION_ENABLE
| SRB_FLAGS_NO_QUEUE_FREEZE
) &&
3423 !(Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3426 /* Do not process tagged commands if need request sense is set */
3427 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
3429 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3431 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3432 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3434 /* Release the spinlock and return */
3435 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3439 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
3440 SrbInfo
= DeviceExtension
->FreeSrbInfo
;
3442 if (SrbInfo
== NULL
)
3444 /* No SRB structures left in the list. We have to leave
3445 and wait while we are called again */
3447 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3448 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3452 DeviceExtension
->FreeSrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)SrbInfo
->Requests
.Flink
;
3454 /* QueueTag must never be 0, so +1 to it */
3455 Srb
->QueueTag
= (UCHAR
)(SrbInfo
- DeviceExtension
->SrbInfo
) + 1;
3459 /* Usual untagged command */
3461 (!IsListEmpty(&LunExtension
->SrbInfo
.Requests
) ||
3462 LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
) &&
3463 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
3466 /* Mark it as pending and leave */
3467 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3468 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3469 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3471 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3475 Srb
->QueueTag
= SP_UNTAGGED
;
3476 SrbInfo
= &LunExtension
->SrbInfo
;
3481 Srb
->QueueTag
= SP_UNTAGGED
;
3482 SrbInfo
= &LunExtension
->SrbInfo
;
3485 /* Allocate SRB extension structure */
3486 if (DeviceExtension
->NeedSrbExtensionAlloc
)
3488 /* Check the list of free extensions */
3489 SrbExtension
= DeviceExtension
->FreeSrbExtensions
;
3491 /* If no free extensions... */
3492 if (SrbExtension
== NULL
)
3495 if (Srb
->Function
!= SRB_FUNCTION_ABORT_COMMAND
&&
3496 Srb
->QueueTag
!= SP_UNTAGGED
)
3498 SrbInfo
->Requests
.Blink
= NULL
;
3499 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
3500 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
3503 /* Return, in order to be called again later */
3504 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3505 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3509 /* Remove that free SRB extension from the list (since
3510 we're going to use it) */
3511 DeviceExtension
->FreeSrbExtensions
= *((PVOID
*)SrbExtension
);
3513 /* Spinlock can be released now */
3514 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3516 Srb
->SrbExtension
= SrbExtension
;
3518 if (Srb
->SenseInfoBuffer
!= NULL
&&
3519 DeviceExtension
->SupportsAutoSense
)
3521 /* Store pointer to the SenseInfo buffer */
3522 SrbInfo
->SaveSenseRequest
= Srb
->SenseInfoBuffer
;
3524 /* Does data fit the buffer? */
3525 if (Srb
->SenseInfoBufferLength
> sizeof(SENSE_DATA
))
3527 /* No, disabling autosense at all */
3528 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_AUTOSENSE
;
3532 /* Yes, update the buffer pointer */
3533 Srb
->SenseInfoBuffer
= SrbExtension
+ DeviceExtension
->SrbExtensionSize
;
3540 Srb
->SrbExtension
= NULL
;
3541 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3549 SpiSendInquiry(IN PDEVICE_OBJECT DeviceObject
,
3550 IN OUT PSCSI_LUN_INFO LunInfo
)
3552 IO_STATUS_BLOCK IoStatusBlock
;
3553 PIO_STACK_LOCATION IrpStack
;
3558 PINQUIRYDATA InquiryBuffer
;
3559 PSENSE_DATA SenseBuffer
;
3560 BOOLEAN KeepTrying
= TRUE
;
3561 ULONG RetryCount
= 0;
3562 SCSI_REQUEST_BLOCK Srb
;
3564 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3565 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3567 DPRINT("SpiSendInquiry() called\n");
3569 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3571 InquiryBuffer
= ExAllocatePoolWithTag(NonPagedPool
, INQUIRYDATABUFFERSIZE
, TAG_SCSIPORT
);
3572 if (InquiryBuffer
== NULL
)
3573 return STATUS_INSUFFICIENT_RESOURCES
;
3575 SenseBuffer
= ExAllocatePoolWithTag(NonPagedPool
, SENSE_BUFFER_SIZE
, TAG_SCSIPORT
);
3576 if (SenseBuffer
== NULL
)
3578 ExFreePoolWithTag(InquiryBuffer
, TAG_SCSIPORT
);
3579 return STATUS_INSUFFICIENT_RESOURCES
;
3584 /* Initialize event for waiting */
3585 KeInitializeEvent(&Event
,
3590 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN
,
3595 INQUIRYDATABUFFERSIZE
,
3601 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3604 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3610 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3612 Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
3613 Srb
.OriginalRequest
= Irp
;
3614 Srb
.PathId
= LunInfo
->PathId
;
3615 Srb
.TargetId
= LunInfo
->TargetId
;
3616 Srb
.Lun
= LunInfo
->Lun
;
3617 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3618 Srb
.SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3619 Srb
.TimeOutValue
= 4;
3622 Srb
.SenseInfoBuffer
= SenseBuffer
;
3623 Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3625 Srb
.DataBuffer
= InquiryBuffer
;
3626 Srb
.DataTransferLength
= INQUIRYDATABUFFERSIZE
;
3628 /* Attach Srb to the Irp */
3629 IrpStack
= IoGetNextIrpStackLocation (Irp
);
3630 IrpStack
->Parameters
.Scsi
.Srb
= &Srb
;
3633 Cdb
= (PCDB
)Srb
.Cdb
;
3634 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_INQUIRY
;
3635 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= LunInfo
->Lun
;
3636 Cdb
->CDB6INQUIRY
.AllocationLength
= INQUIRYDATABUFFERSIZE
;
3638 /* Call the driver */
3639 Status
= IoCallDriver(DeviceObject
, Irp
);
3641 /* Wait for it to complete */
3642 if (Status
== STATUS_PENDING
)
3644 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3645 KeWaitForSingleObject(&Event
,
3650 Status
= IoStatusBlock
.Status
;
3653 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status
);
3655 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_SUCCESS
)
3657 /* All fine, copy data over */
3658 RtlCopyMemory(LunInfo
->InquiryData
,
3660 INQUIRYDATABUFFERSIZE
);
3663 Status
= STATUS_SUCCESS
;
3668 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb
.SrbStatus
);
3670 /* Check if the queue is frozen */
3671 if (Srb
.SrbStatus
& SRB_STATUS_QUEUE_FROZEN
)
3673 /* Something weird happened, deal with it (unfreeze the queue) */
3676 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb
.TargetId
);
3678 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3683 /* Clear frozen flag */
3684 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
3686 /* Acquire the spinlock */
3687 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
3689 /* Process the request */
3690 SpiGetNextRequestFromLun(DeviceObject
->DeviceExtension
, LunExtension
);
3692 /* SpiGetNextRequestFromLun() releases the spinlock,
3693 so we just lower irql back to what it was before */
3697 /* Check if data overrun happened */
3698 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
3700 DPRINT("Data overrun at TargetId %d\n", LunInfo
->TargetId
);
3702 /* Nothing dramatic, just copy data, but limiting the size */
3703 RtlCopyMemory(LunInfo
->InquiryData
,
3705 (Srb
.DataTransferLength
> INQUIRYDATABUFFERSIZE
) ?
3706 INQUIRYDATABUFFERSIZE
: Srb
.DataTransferLength
);
3709 Status
= STATUS_SUCCESS
;
3712 else if ((Srb
.SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3713 SenseBuffer
->SenseKey
== SCSI_SENSE_ILLEGAL_REQUEST
)
3715 /* LUN is not valid, but some device responds there.
3716 Mark it as invalid anyway */
3719 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3724 /* Retry a couple of times if no timeout happened */
3725 if ((RetryCount
< 2) &&
3726 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_NO_DEVICE
) &&
3727 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_SELECTION_TIMEOUT
))
3734 /* That's all, quit the loop */
3737 /* Set status according to SRB status */
3738 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_FUNCTION
||
3739 SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH
)
3741 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3745 Status
= STATUS_IO_DEVICE_ERROR
;
3752 ExFreePoolWithTag(InquiryBuffer
, TAG_SCSIPORT
);
3753 ExFreePoolWithTag(SenseBuffer
, TAG_SCSIPORT
);
3755 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status
);
3761 /* Scans all SCSI buses */
3763 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3765 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3769 PSCSI_BUS_SCAN_INFO BusScanInfo
;
3770 PSCSI_LUN_INFO LastLunInfo
, LunInfo
, LunInfoExists
;
3771 BOOLEAN DeviceExists
;
3776 DPRINT("SpiScanAdapter() called\n");
3778 /* Scan all buses */
3779 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
3781 DPRINT(" Scanning bus %d\n", Bus
);
3784 /* Get pointer to the scan information */
3785 BusScanInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
];
3789 /* Find the last LUN info in the list */
3790 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3791 LastLunInfo
= LunInfo
;
3793 while (LunInfo
!= NULL
)
3795 LastLunInfo
= LunInfo
;
3796 LunInfo
= LunInfo
->Next
;
3801 /* We need to allocate this buffer */
3802 BusScanInfo
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_BUS_SCAN_INFO
), TAG_SCSIPORT
);
3805 DPRINT1("Out of resources!\n");
3809 /* Store the pointer in the BusScanInfo array */
3810 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
] = BusScanInfo
;
3812 /* Fill this struct (length and bus ids for now) */
3813 BusScanInfo
->Length
= sizeof(SCSI_BUS_SCAN_INFO
);
3814 BusScanInfo
->LogicalUnitsCount
= 0;
3815 BusScanInfo
->BusIdentifier
= DeviceExtension
->PortConfig
->InitiatorBusId
[Bus
];
3816 BusScanInfo
->LunInfo
= NULL
;
3818 /* Set pointer to the last LUN info to NULL */
3822 /* Create LUN information structure */
3823 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3826 DPRINT1("Out of resources!\n");
3830 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3832 /* Create LunExtension */
3833 LunExtension
= SpiAllocateLunExtension(DeviceExtension
);
3835 /* And send INQUIRY to every target */
3836 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
3838 /* TODO: Support scan bottom-up */
3840 /* Skip if it's the same address */
3841 if (Target
== BusScanInfo
->BusIdentifier
)
3844 /* Try to find an existing device here */
3845 DeviceExists
= FALSE
;
3846 LunInfoExists
= BusScanInfo
->LunInfo
;
3848 /* Find matching address on this bus */
3849 while (LunInfoExists
)
3851 if (LunInfoExists
->TargetId
== Target
)
3853 DeviceExists
= TRUE
;
3857 /* Advance to the next one */
3858 LunInfoExists
= LunInfoExists
->Next
;
3861 /* No need to bother rescanning, since we already did that before */
3865 /* Scan all logical units */
3866 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
3868 if ((!LunExtension
) || (!LunInfo
))
3871 /* Add extension to the list */
3872 Hint
= (Target
+ Lun
) % LUS_NUMBER
;
3873 LunExtension
->Next
= DeviceExtension
->LunExtensionList
[Hint
];
3874 DeviceExtension
->LunExtensionList
[Hint
] = LunExtension
;
3876 /* Fill Path, Target, Lun fields */
3877 LunExtension
->PathId
= LunInfo
->PathId
= (UCHAR
)Bus
;
3878 LunExtension
->TargetId
= LunInfo
->TargetId
= (UCHAR
)Target
;
3879 LunExtension
->Lun
= LunInfo
->Lun
= (UCHAR
)Lun
;
3881 /* Set flag to prevent race conditions */
3882 LunExtension
->Flags
|= SCSI_PORT_SCAN_IN_PROGRESS
;
3884 /* Zero LU extension contents */
3885 if (DeviceExtension
->LunExtensionSize
)
3887 RtlZeroMemory(LunExtension
+ 1,
3888 DeviceExtension
->LunExtensionSize
);
3891 /* Finally send the inquiry command */
3892 Status
= SpiSendInquiry(DeviceExtension
->DeviceObject
, LunInfo
);
3894 if (NT_SUCCESS(Status
))
3896 /* Let's see if we really found a device */
3897 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3899 /* Check if this device is unsupported */
3900 if (InquiryData
->DeviceTypeQualifier
== DEVICE_QUALIFIER_NOT_SUPPORTED
)
3902 DeviceExtension
->LunExtensionList
[Hint
] =
3903 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3908 /* Clear the "in scan" flag */
3909 LunExtension
->Flags
&= ~SCSI_PORT_SCAN_IN_PROGRESS
;
3911 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3912 InquiryData
->DeviceType
, Bus
, Target
, Lun
);
3915 * Cache the inquiry data into the LUN extension (or alternatively
3916 * we could save a pointer to LunInfo within the LunExtension?)
3918 RtlCopyMemory(&LunExtension
->InquiryData
,
3920 INQUIRYDATABUFFERSIZE
);
3922 /* Add this info to the linked list */
3923 LunInfo
->Next
= NULL
;
3925 LastLunInfo
->Next
= LunInfo
;
3927 BusScanInfo
->LunInfo
= LunInfo
;
3929 /* Store the last LUN info */
3930 LastLunInfo
= LunInfo
;
3932 /* Store DeviceObject */
3933 LunInfo
->DeviceObject
= DeviceExtension
->DeviceObject
;
3935 /* Allocate another buffer */
3936 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3939 DPRINT1("Out of resources!\n");
3943 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3945 /* Create a new LU extension */
3946 LunExtension
= SpiAllocateLunExtension(DeviceExtension
);
3952 /* Remove this LUN from the list */
3953 DeviceExtension
->LunExtensionList
[Hint
] =
3954 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3956 /* Decide whether we are continuing or not */
3957 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
3965 /* Free allocated buffers */
3967 ExFreePoolWithTag(LunExtension
, TAG_SCSIPORT
);
3970 ExFreePoolWithTag(LunInfo
, TAG_SCSIPORT
);
3972 /* Sum what we found */
3973 BusScanInfo
->LogicalUnitsCount
+= (UCHAR
)DevicesFound
;
3974 DPRINT(" Found %d devices on bus %d\n", DevicesFound
, Bus
);
3977 DPRINT("SpiScanAdapter() done\n");
3982 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3985 ULONG InquiryDataSize
;
3986 PSCSI_LUN_INFO LunInfo
;
3987 ULONG BusCount
, LunCount
, Length
;
3988 PIO_STACK_LOCATION IrpStack
;
3989 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
3990 PSCSI_INQUIRY_DATA InquiryData
;
3991 PSCSI_BUS_DATA BusData
;
3995 DPRINT("SpiGetInquiryData() called\n");
3997 /* Get pointer to the buffer */
3998 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3999 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
4001 /* Initialize bus and LUN counters */
4002 BusCount
= DeviceExtension
->BusesConfig
->NumberOfBuses
;
4005 /* Calculate total number of LUNs */
4006 for (Bus
= 0; Bus
< BusCount
; Bus
++)
4007 LunCount
+= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
4009 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
4011 ((sizeof(SCSI_INQUIRY_DATA
) - 1 + INQUIRYDATABUFFERSIZE
+
4012 sizeof(ULONG
) - 1) & ~(sizeof(ULONG
) - 1));
4014 /* Calculate data size */
4015 Length
= sizeof(SCSI_ADAPTER_BUS_INFO
) + (BusCount
- 1) * sizeof(SCSI_BUS_DATA
);
4017 Length
+= InquiryDataSize
* LunCount
;
4019 /* Check, if all data is going to fit into provided buffer */
4020 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< Length
)
4022 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4023 return STATUS_BUFFER_TOO_SMALL
;
4026 /* Store data size in the IRP */
4027 Irp
->IoStatus
.Information
= Length
;
4029 DPRINT("Data size: %lu\n", Length
);
4031 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
4033 AdapterBusInfo
->NumberOfBuses
= (UCHAR
)BusCount
;
4035 /* Point InquiryData to the corresponding place inside Buffer */
4036 InquiryData
= (PSCSI_INQUIRY_DATA
)(Buffer
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
4037 (BusCount
- 1) * sizeof(SCSI_BUS_DATA
));
4040 for (Bus
= 0; Bus
< BusCount
; Bus
++)
4042 BusData
= &AdapterBusInfo
->BusData
[Bus
];
4044 /* Calculate and save an offset of the inquiry data */
4045 BusData
->InquiryDataOffset
= (ULONG
)((PUCHAR
)InquiryData
- Buffer
);
4047 /* Get a pointer to the LUN information structure */
4048 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
4050 /* Store Initiator Bus Id */
4051 BusData
->InitiatorBusId
=
4052 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->BusIdentifier
;
4054 /* Store LUN count */
4055 BusData
->NumberOfLogicalUnits
=
4056 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
4059 while (LunInfo
!= NULL
)
4061 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
4062 Bus
, LunInfo
->TargetId
, LunInfo
->Lun
);
4064 /* Fill InquiryData with values */
4065 InquiryData
->PathId
= LunInfo
->PathId
;
4066 InquiryData
->TargetId
= LunInfo
->TargetId
;
4067 InquiryData
->Lun
= LunInfo
->Lun
;
4068 InquiryData
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
4069 InquiryData
->DeviceClaimed
= LunInfo
->DeviceClaimed
;
4070 InquiryData
->NextInquiryDataOffset
=
4071 (ULONG
)((PUCHAR
)InquiryData
+ InquiryDataSize
- Buffer
);
4073 /* Copy data in it */
4074 RtlCopyMemory(InquiryData
->InquiryData
,
4075 LunInfo
->InquiryData
,
4076 INQUIRYDATABUFFERSIZE
);
4078 /* Move to the next LUN */
4079 LunInfo
= LunInfo
->Next
;
4080 InquiryData
= (PSCSI_INQUIRY_DATA
) ((PCHAR
)InquiryData
+ InquiryDataSize
);
4083 /* Either mark the end, or set offset to 0 */
4084 if (BusData
->NumberOfLogicalUnits
!= 0)
4085 ((PSCSI_INQUIRY_DATA
) ((PCHAR
)InquiryData
- InquiryDataSize
))->NextInquiryDataOffset
= 0;
4087 BusData
->InquiryDataOffset
= 0;
4090 /* Finish with success */
4091 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4092 return STATUS_SUCCESS
;
4095 static PSCSI_REQUEST_BLOCK_INFO
4096 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4102 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4104 if (QueueTag
== SP_UNTAGGED
)
4106 /* Untagged request, get LU and return pointer to SrbInfo */
4107 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4112 /* Return NULL in case of error */
4116 /* Return the pointer to SrbInfo */
4117 return &LunExtension
->SrbInfo
;
4121 /* Make sure the tag is valid, if it is - return the data */
4122 if (QueueTag
> DeviceExtension
->SrbDataCount
|| QueueTag
< 1)
4125 return &DeviceExtension
->SrbInfo
[QueueTag
-1];
4130 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4131 IN PSCSI_REQUEST_BLOCK InitialSrb
)
4133 PSCSI_REQUEST_BLOCK Srb
;
4136 PIO_STACK_LOCATION IrpStack
;
4137 LARGE_INTEGER LargeInt
;
4140 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb
);
4143 Srb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
) + sizeof(PVOID
), TAG_SCSIPORT
);
4144 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
4147 LargeInt
.QuadPart
= (LONGLONG
) 1;
4148 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_READ
,
4149 DeviceExtension
->DeviceObject
,
4150 InitialSrb
->SenseInfoBuffer
,
4151 InitialSrb
->SenseInfoBufferLength
,
4155 IoSetCompletionRoutine(Irp
,
4156 (PIO_COMPLETION_ROUTINE
)SpiCompletionRoutine
,
4164 DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb
);
4168 IrpStack
= IoGetNextIrpStackLocation(Irp
);
4169 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
4171 /* Put Srb address into Irp... */
4172 IrpStack
->Parameters
.Others
.Argument1
= (PVOID
)Srb
;
4174 /* ...and vice versa */
4175 Srb
->OriginalRequest
= Irp
;
4178 Ptr
= (PVOID
*)(Srb
+1);
4181 /* Build CDB for REQUEST SENSE */
4183 Cdb
= (PCDB
)Srb
->Cdb
;
4185 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
4186 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= 0;
4187 Cdb
->CDB6INQUIRY
.Reserved1
= 0;
4188 Cdb
->CDB6INQUIRY
.PageCode
= 0;
4189 Cdb
->CDB6INQUIRY
.IReserved
= 0;
4190 Cdb
->CDB6INQUIRY
.AllocationLength
= (UCHAR
)InitialSrb
->SenseInfoBufferLength
;
4191 Cdb
->CDB6INQUIRY
.Control
= 0;
4194 Srb
->TargetId
= InitialSrb
->TargetId
;
4195 Srb
->Lun
= InitialSrb
->Lun
;
4196 Srb
->PathId
= InitialSrb
->PathId
;
4198 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4199 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
4201 /* Timeout will be 2 seconds */
4202 Srb
->TimeOutValue
= 2;
4204 /* No auto request sense */
4205 Srb
->SenseInfoBufferLength
= 0;
4206 Srb
->SenseInfoBuffer
= NULL
;
4208 /* Set necessary flags */
4209 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_BYPASS_FROZEN_QUEUE
|
4210 SRB_FLAGS_DISABLE_DISCONNECT
;
4212 /* Transfer disable synch transfer flag */
4213 if (InitialSrb
->SrbFlags
& SRB_FLAGS_DISABLE_SYNCH_TRANSFER
)
4214 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4216 Srb
->DataBuffer
= InitialSrb
->SenseInfoBuffer
;
4218 /* Fill the transfer length */
4219 Srb
->DataTransferLength
= InitialSrb
->SenseInfoBufferLength
;
4221 /* Clear statuses */
4222 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
4225 /* Call the driver */
4226 (VOID
)IoCallDriver(DeviceExtension
->DeviceObject
, Irp
);
4228 DPRINT("SpiSendRequestSense() done\n");
4235 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4236 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
4237 OUT PBOOLEAN NeedToCallStartIo
)
4239 PSCSI_REQUEST_BLOCK Srb
;
4240 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4243 //ULONG SequenceNumber;
4246 Irp
= Srb
->OriginalRequest
;
4248 /* Get Lun extension */
4249 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4254 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
&&
4255 DeviceExtension
->MapBuffers
&&
4258 /* MDL is shared if transfer is broken into smaller parts */
4259 Srb
->DataBuffer
= (PCCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
4260 ((PCCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
4262 /* In case of data going in, flush the buffers */
4263 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
4265 KeFlushIoBuffers(Irp
->MdlAddress
,
4271 /* Flush adapter if needed */
4272 if (SrbInfo
->BaseOfMapRegister
)
4274 /* TODO: Implement */
4278 /* Clear the request */
4279 SrbInfo
->Srb
= NULL
;
4281 /* If disconnect is disabled... */
4282 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
4284 /* Acquire the spinlock since we mess with flags */
4285 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4287 /* Set corresponding flag */
4288 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
4290 /* Clear the timer if needed */
4291 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
))
4292 DeviceExtension
->TimerCount
= -1;
4294 /* Spinlock is not needed anymore */
4295 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4297 if (!(DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
) &&
4298 !(DeviceExtension
->Flags
& SCSI_PORT_DEVICE_BUSY
) &&
4299 !(*NeedToCallStartIo
))
4301 /* We're not busy, but we have a request pending */
4302 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4306 /* Scatter/gather */
4307 if (Srb
->SrbFlags
& SRB_FLAGS_SGLIST_FROM_POOL
)
4309 /* TODO: Implement */
4313 /* Acquire spinlock (we're freeing SrbExtension) */
4314 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4316 /* Free it (if needed) */
4317 if (Srb
->SrbExtension
)
4319 if (Srb
->SenseInfoBuffer
!= NULL
&& DeviceExtension
->SupportsAutoSense
)
4321 ASSERT(Srb
->SenseInfoBuffer
== NULL
|| SrbInfo
->SaveSenseRequest
!= NULL
);
4323 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)
4325 /* Copy sense data to the buffer */
4326 RtlCopyMemory(SrbInfo
->SaveSenseRequest
,
4327 Srb
->SenseInfoBuffer
,
4328 Srb
->SenseInfoBufferLength
);
4331 /* And restore the pointer */
4332 Srb
->SenseInfoBuffer
= SrbInfo
->SaveSenseRequest
;
4335 /* Put it into the free srb extensions list */
4336 *((PVOID
*)Srb
->SrbExtension
) = DeviceExtension
->FreeSrbExtensions
;
4337 DeviceExtension
->FreeSrbExtensions
= Srb
->SrbExtension
;
4340 /* Save transfer length in the IRP */
4341 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
4343 //SequenceNumber = SrbInfo->SequenceNumber;
4344 SrbInfo
->SequenceNumber
= 0;
4346 /* Decrement the queue count */
4347 LunExtension
->QueueCount
--;
4349 /* Free Srb, if needed*/
4350 if (Srb
->QueueTag
!= SP_UNTAGGED
)
4352 /* Put it into the free list */
4353 SrbInfo
->Requests
.Blink
= NULL
;
4354 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
4355 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
4358 /* SrbInfo is not used anymore */
4361 if (DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
)
4363 /* Clear the flag */
4364 DeviceExtension
->Flags
&= ~SCSI_PORT_REQUEST_PENDING
;
4366 /* Note the caller about StartIo */
4367 *NeedToCallStartIo
= TRUE
;
4370 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
4372 /* Start the packet */
4373 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4375 if (!(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
) &&
4376 LunExtension
->RequestTimeout
== -1)
4378 /* Start the next packet */
4379 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4383 /* Release the spinlock */
4384 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4387 DPRINT("IoCompleting request IRP 0x%p\n", Irp
);
4389 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4391 /* Decrement number of active requests, and analyze the result */
4392 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4395 !DeviceExtension
->MapRegisters
&&
4396 DeviceExtension
->AdapterObject
!= NULL
)
4398 /* Nullify map registers */
4399 DeviceExtension
->MapRegisterBase
= NULL
;
4400 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4403 /* Exit, we're done */
4407 /* Decrement number of active requests, and analyze the result */
4408 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4411 !DeviceExtension
->MapRegisters
&&
4412 DeviceExtension
->AdapterObject
!= NULL
)
4414 /* Result is negative, so this is a slave, free map registers */
4415 DeviceExtension
->MapRegisterBase
= NULL
;
4416 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4419 /* Convert status */
4420 Irp
->IoStatus
.Status
= SpiStatusSrbToNt(Srb
->SrbStatus
);
4422 /* It's not a bypass, it's busy or the queue is full? */
4423 if ((Srb
->ScsiStatus
== SCSISTAT_BUSY
||
4424 Srb
->SrbStatus
== SRB_STATUS_BUSY
||
4425 Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
) &&
4426 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
))
4429 DPRINT("Busy SRB status %x\n", Srb
->SrbStatus
);
4431 /* Requeue, if needed */
4432 if (LunExtension
->Flags
& (LUNEX_FROZEN_QUEUE
| LUNEX_BUSY
))
4434 DPRINT("it's being requeued\n");
4436 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4437 Srb
->ScsiStatus
= 0;
4439 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4440 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
4443 /* It's a big f.ck up if we got here */
4444 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
4445 Srb
->ScsiStatus
= SCSISTAT_BUSY
;
4451 /* Release the spinlock */
4452 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4455 else if (LunExtension
->AttemptCount
++ < 20)
4457 /* LUN is still busy */
4458 Srb
->ScsiStatus
= 0;
4459 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4461 LunExtension
->BusyRequest
= Irp
;
4462 LunExtension
->Flags
|= LUNEX_BUSY
;
4464 /* Release the spinlock */
4465 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4470 /* Freeze the queue*/
4471 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4472 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4474 /* "Unfull" the queue */
4475 LunExtension
->Flags
&= ~LUNEX_FULL_QUEUE
;
4477 /* Release the spinlock */
4478 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4480 /* Return status that the device is not ready */
4481 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
4482 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4488 /* Start the next request, if LUN is idle, and this is sense request */
4489 if (((Srb
->ScsiStatus
!= SCSISTAT_CHECK_CONDITION
) ||
4490 (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) ||
4491 !Srb
->SenseInfoBuffer
|| !Srb
->SenseInfoBufferLength
)
4492 && (Srb
->SrbFlags
& SRB_FLAGS_NO_QUEUE_FREEZE
))
4494 if (LunExtension
->RequestTimeout
== -1)
4495 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4497 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4501 /* Freeze the queue */
4502 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4503 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4505 /* Do we need a request sense? */
4506 if (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4507 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
4508 Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
)
4510 /* If LUN is busy, we have to requeue it in order to allow request sense */
4511 if (LunExtension
->Flags
& LUNEX_BUSY
)
4513 DPRINT("Requeuing busy request to allow request sense\n");
4515 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4516 &LunExtension
->BusyRequest
->Tail
.Overlay
.DeviceQueueEntry
,
4519 /* We should never get here */
4522 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4523 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4528 /* Clear busy flags */
4529 LunExtension
->Flags
&= ~(LUNEX_FULL_QUEUE
| LUNEX_BUSY
);
4532 /* Release the spinlock */
4533 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4535 /* Send RequestSense */
4536 SpiSendRequestSense(DeviceExtension
, Srb
);
4542 /* Release the spinlock */
4543 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4546 /* Complete the request */
4547 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4552 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
4556 PSCSI_REQUEST_BLOCK Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
4557 PSCSI_REQUEST_BLOCK InitialSrb
;
4560 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp
);
4562 if ((Srb
->Function
== SRB_FUNCTION_RESET_BUS
) ||
4563 (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
))
4565 /* Deallocate SRB and IRP and exit */
4569 return STATUS_MORE_PROCESSING_REQUIRED
;
4572 /* Get a pointer to the SRB and IRP which were initially sent */
4573 InitialSrb
= *((PVOID
*)(Srb
+1));
4574 InitialIrp
= InitialSrb
->OriginalRequest
;
4576 if ((SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
) ||
4577 (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_DATA_OVERRUN
))
4579 /* Sense data is OK */
4580 InitialSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
4582 /* Set length to be the same */
4583 InitialSrb
->SenseInfoBufferLength
= (UCHAR
)Srb
->DataTransferLength
;
4586 /* Make sure initial SRB's queue is frozen */
4587 ASSERT(InitialSrb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
);
4589 /* Complete this request */
4590 IoCompleteRequest(InitialIrp
, IO_DISK_INCREMENT
);
4592 /* Deallocate everything (internal) */
4595 if (Irp
->MdlAddress
!= NULL
)
4597 MmUnlockPages(Irp
->MdlAddress
);
4598 IoFreeMdl(Irp
->MdlAddress
);
4599 Irp
->MdlAddress
= NULL
;
4603 return STATUS_MORE_PROCESSING_REQUIRED
;
4606 static BOOLEAN NTAPI
4607 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
4608 IN PVOID ServiceContext
)
4610 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4612 DPRINT("ScsiPortIsr() called!\n");
4614 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
4616 /* If interrupts are disabled - we don't expect any */
4617 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_DISABLE_INTERRUPTS
)
4620 /* Call miniport's HwInterrupt routine */
4621 if (DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
) == FALSE
)
4623 /* This interrupt doesn't belong to us */
4627 /* If flag of notification is set - queue a DPC */
4628 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4630 IoRequestDpc(DeviceExtension
->DeviceObject
,
4631 DeviceExtension
->CurrentIrp
,
4640 SpiSaveInterruptData(IN PVOID Context
)
4642 PSCSI_PORT_SAVE_INTERRUPT InterruptContext
= Context
;
4643 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4644 PSCSI_REQUEST_BLOCK Srb
;
4645 PSCSI_REQUEST_BLOCK_INFO SrbInfo
, NextSrbInfo
;
4646 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4649 /* Get pointer to the device extension */
4650 DeviceExtension
= InterruptContext
->DeviceExtension
;
4652 /* If we don't have anything pending - return */
4653 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
))
4656 /* Actually save the interrupt data */
4657 *InterruptContext
->InterruptData
= DeviceExtension
->InterruptData
;
4659 /* Clear the data stored in the device extension */
4660 DeviceExtension
->InterruptData
.Flags
&=
4661 (SCSI_PORT_RESET
| SCSI_PORT_RESET_REQUEST
| SCSI_PORT_DISABLE_INTERRUPTS
);
4662 DeviceExtension
->InterruptData
.CompletedAbort
= NULL
;
4663 DeviceExtension
->InterruptData
.ReadyLun
= NULL
;
4664 DeviceExtension
->InterruptData
.CompletedRequests
= NULL
;
4666 /* Loop through the list of completed requests */
4667 SrbInfo
= InterruptContext
->InterruptData
->CompletedRequests
;
4671 /* Make sure we have SRV */
4672 ASSERT(SrbInfo
->Srb
);
4674 /* Get SRB and LunExtension */
4677 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4682 /* We have to check special cases if request is unsuccessful*/
4683 if (Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
)
4685 /* Check if we need request sense by a few conditions */
4686 if (Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
&&
4687 Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4688 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
))
4690 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
4692 /* It means: we tried to send REQUEST SENSE, but failed */
4694 Srb
->ScsiStatus
= 0;
4695 Srb
->SrbStatus
= SRB_STATUS_REQUEST_SENSE_FAILED
;
4699 /* Set the corresponding flag, so that REQUEST SENSE
4701 LunExtension
->Flags
|= LUNEX_NEED_REQUEST_SENSE
;
4706 /* Check for a full queue */
4707 if (Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
)
4709 /* TODO: Implement when it's encountered */
4714 /* Let's decide if we need to watch timeout or not */
4715 if (Srb
->QueueTag
== SP_UNTAGGED
)
4721 if (LunExtension
->SrbInfo
.Requests
.Flink
== &SrbInfo
->Requests
)
4726 /* Remove it from the queue */
4727 RemoveEntryList(&SrbInfo
->Requests
);
4732 /* We have to maintain timeout counter */
4733 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
))
4735 LunExtension
->RequestTimeout
= -1;
4739 NextSrbInfo
= CONTAINING_RECORD(LunExtension
->SrbInfo
.Requests
.Flink
,
4740 SCSI_REQUEST_BLOCK_INFO
,
4743 Srb
= NextSrbInfo
->Srb
;
4745 /* Update timeout counter */
4746 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
4750 SrbInfo
= SrbInfo
->CompletedRequests
;
4758 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4759 IN PSCSI_PORT_LUN_EXTENSION LunExtension
)
4761 PIO_STACK_LOCATION IrpStack
;
4763 PKDEVICE_QUEUE_ENTRY Entry
;
4764 PSCSI_REQUEST_BLOCK Srb
;
4767 /* If LUN is not active or queue is more than maximum allowed */
4768 if (LunExtension
->QueueCount
>= LunExtension
->MaxQueueCount
||
4769 !(LunExtension
->Flags
& SCSI_PORT_LU_ACTIVE
))
4771 /* Release the spinlock and exit */
4772 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4776 /* Check if we can get a next request */
4777 if (LunExtension
->Flags
&
4778 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_BUSY
|
4779 LUNEX_FULL_QUEUE
| LUNEX_FROZEN_QUEUE
| LUNEX_REQUEST_PENDING
))
4781 /* Pending requests can only be started if the queue is empty */
4782 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
) &&
4783 !(LunExtension
->Flags
&
4784 (LUNEX_BUSY
| LUNEX_FROZEN_QUEUE
| LUNEX_FULL_QUEUE
| LUNEX_NEED_REQUEST_SENSE
)))
4786 /* Make sure we have SRB */
4787 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
4789 /* Clear active and pending flags */
4790 LunExtension
->Flags
&= ~(LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
);
4792 /* Get next Irp, and clear pending requests list */
4793 NextIrp
= LunExtension
->PendingRequest
;
4794 LunExtension
->PendingRequest
= NULL
;
4796 /* Set attempt counter to zero */
4797 LunExtension
->AttemptCount
= 0;
4799 /* Release the spinlock */
4800 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4802 /* Start the next pending request */
4803 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4809 /* Release the spinlock, without clearing any flags and exit */
4810 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4816 /* Reset active flag */
4817 LunExtension
->Flags
&= ~SCSI_PORT_LU_ACTIVE
;
4819 /* Set attempt counter to zero */
4820 LunExtension
->AttemptCount
= 0;
4822 /* Remove packet from the device queue */
4823 Entry
= KeRemoveByKeyDeviceQueue(&LunExtension
->DeviceQueue
, LunExtension
->SortKey
);
4827 /* Get pointer to the next irp */
4828 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
4830 /* Get point to the SRB */
4831 IrpStack
= IoGetCurrentIrpStackLocation(NextIrp
);
4832 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
4835 LunExtension
->SortKey
= Srb
->QueueSortKey
;
4836 LunExtension
->SortKey
++;
4838 /* Release the spinlock */
4839 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4841 /* Start the next pending request */
4842 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4846 /* Release the spinlock */
4847 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4853 // ScsiPortDpcForIsr
4860 // IN PDEVICE_OBJECT DpcDeviceObject
4862 // IN PVOID DpcContext
4865 ScsiPortDpcForIsr(IN PKDPC Dpc
,
4866 IN PDEVICE_OBJECT DpcDeviceObject
,
4868 IN PVOID DpcContext
)
4870 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DpcDeviceObject
->DeviceExtension
;
4871 SCSI_PORT_INTERRUPT_DATA InterruptData
;
4872 SCSI_PORT_SAVE_INTERRUPT Context
;
4873 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4874 BOOLEAN NeedToStartIo
;
4875 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
4876 LARGE_INTEGER TimerValue
;
4878 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4879 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
4881 /* We need to acquire spinlock */
4882 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4884 RtlZeroMemory(&InterruptData
, sizeof(SCSI_PORT_INTERRUPT_DATA
));
4888 /* Interrupt structure must be snapshotted, and only then analyzed */
4889 Context
.InterruptData
= &InterruptData
;
4890 Context
.DeviceExtension
= DeviceExtension
;
4892 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
4893 SpiSaveInterruptData
,
4896 /* Nothing - just return (don't forget to release the spinlock */
4897 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4898 DPRINT("ScsiPortDpcForIsr() done\n");
4902 /* If flush of adapters is needed - do it */
4903 if (InterruptData
.Flags
& SCSI_PORT_FLUSH_ADAPTERS
)
4905 /* TODO: Implement */
4909 /* Check for IoMapTransfer */
4910 if (InterruptData
.Flags
& SCSI_PORT_MAP_TRANSFER
)
4912 /* TODO: Implement */
4916 /* Check if timer is needed */
4917 if (InterruptData
.Flags
& SCSI_PORT_TIMER_NEEDED
)
4919 /* Save the timer routine */
4920 DeviceExtension
->HwScsiTimer
= InterruptData
.HwScsiTimer
;
4922 if (InterruptData
.MiniportTimerValue
== 0)
4924 /* Cancel the timer */
4925 KeCancelTimer(&DeviceExtension
->MiniportTimer
);
4929 /* Convert timer value */
4930 TimerValue
.QuadPart
= Int32x32To64(InterruptData
.MiniportTimerValue
, -10);
4933 KeSetTimer(&DeviceExtension
->MiniportTimer
,
4935 &DeviceExtension
->MiniportTimerDpc
);
4939 /* If it's ready for the next request */
4940 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4942 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4943 if ((DeviceExtension
->Flags
&
4944 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
)) ==
4945 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
))
4947 /* Clear busy flag set by ScsiPortStartPacket() */
4948 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4950 if (!(InterruptData
.Flags
& SCSI_PORT_RESET
))
4952 /* Ready for next, and no reset is happening */
4953 DeviceExtension
->TimerCount
= -1;
4958 /* Not busy, but not ready for the next request */
4959 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4960 InterruptData
.Flags
&= ~SCSI_PORT_NEXT_REQUEST_READY
;
4965 if (InterruptData
.Flags
& SCSI_PORT_RESET_REPORTED
)
4967 /* Hold for a bit */
4968 DeviceExtension
->TimerCount
= 4;
4971 /* Any ready LUN? */
4972 if (InterruptData
.ReadyLun
!= NULL
)
4975 /* Process all LUNs from the list*/
4978 /* Remove it from the list first (as processed) */
4979 LunExtension
= InterruptData
.ReadyLun
;
4980 InterruptData
.ReadyLun
= LunExtension
->ReadyLun
;
4981 LunExtension
->ReadyLun
= NULL
;
4983 /* Get next request for this LUN */
4984 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4986 /* Still ready requests exist?
4987 If yes - get spinlock, if no - stop here */
4988 if (InterruptData
.ReadyLun
!= NULL
)
4989 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4996 /* Release the spinlock */
4997 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5000 /* If we ready for next packet, start it */
5001 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
5002 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
5004 NeedToStartIo
= FALSE
;
5006 /* Loop the completed request list */
5007 while (InterruptData
.CompletedRequests
)
5009 /* Remove the request */
5010 SrbInfo
= InterruptData
.CompletedRequests
;
5011 InterruptData
.CompletedRequests
= SrbInfo
->CompletedRequests
;
5012 SrbInfo
->CompletedRequests
= NULL
;
5015 SpiProcessCompletedRequest(DeviceExtension
,
5020 /* Loop abort request list */
5021 while (InterruptData
.CompletedAbort
)
5023 LunExtension
= InterruptData
.CompletedAbort
;
5025 /* Remove the request */
5026 InterruptData
.CompletedAbort
= LunExtension
->CompletedAbortRequests
;
5028 /* Get spinlock since we're going to change flags */
5029 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5031 /* TODO: Put SrbExtension to the list of free extensions */
5035 /* If we need - call StartIo routine */
5038 /* Make sure CurrentIrp is not null! */
5039 ASSERT(DpcDeviceObject
->CurrentIrp
!= NULL
);
5040 ScsiPortStartIo(DpcDeviceObject
, DpcDeviceObject
->CurrentIrp
);
5043 /* Everything has been done, check */
5044 if (InterruptData
.Flags
& SCSI_PORT_ENABLE_INT_REQUEST
)
5046 /* Synchronize using spinlock */
5047 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5049 /* Request an interrupt */
5050 DeviceExtension
->HwInterrupt(DeviceExtension
->MiniPortDeviceExtension
);
5052 ASSERT(DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
);
5054 /* Should interrupts be enabled again? */
5055 if (DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
)
5057 /* Clear this flag */
5058 DeviceExtension
->Flags
&= ~SCSI_PORT_DISABLE_INT_REQUESET
;
5060 /* Call a special routine to do this */
5063 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
5064 SpiEnableInterrupts
,
5069 /* If we need a notification again - loop */
5070 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5073 /* Release the spinlock */
5074 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5077 DPRINT("ScsiPortDpcForIsr() done\n");
5082 SpiProcessTimeout(PVOID ServiceContext
)
5084 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
5085 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
5088 DPRINT("SpiProcessTimeout() entered\n");
5090 DeviceExtension
->TimerCount
= -1;
5092 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
5094 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET
;
5096 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET_REQUEST
)
5098 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET_REQUEST
;
5099 ScsiPortStartPacket(ServiceContext
);
5106 DPRINT("Resetting the bus\n");
5108 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
5110 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
, Bus
);
5112 /* Reset flags and set reset timeout to 4 seconds */
5113 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
5114 DeviceExtension
->TimerCount
= 4;
5117 /* If miniport requested - request a dpc for it */
5118 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5119 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
5128 SpiResetBus(PVOID ServiceContext
)
5130 PRESETBUS_PARAMS ResetParams
= (PRESETBUS_PARAMS
)ServiceContext
;
5131 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5133 /* Perform the bus reset */
5134 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ResetParams
->DeviceExtension
;
5135 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
,
5136 ResetParams
->PathId
);
5138 /* Set flags and start the timer */
5139 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
5140 DeviceExtension
->TimerCount
= 4;
5142 /* If miniport requested - give him a DPC */
5143 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5144 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
5151 // This function handles timeouts and other time delayed processing
5156 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
5157 // IN PVOID Context the Controller extension for the
5158 // controller the device is on
5161 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
5164 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5165 PSCSI_PORT_LUN_EXTENSION LunExtension
;
5169 DPRINT("ScsiPortIoTimer()\n");
5171 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
5173 /* Protect with the spinlock */
5174 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5176 /* Check timeouts */
5177 if (DeviceExtension
->TimerCount
> 0)
5179 /* Decrease the timeout counter */
5180 DeviceExtension
->TimerCount
--;
5182 if (DeviceExtension
->TimerCount
== 0)
5184 /* Timeout, process it */
5185 if (KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
5187 DeviceExtension
->DeviceObject
))
5189 DPRINT("Error happened during processing timeout, but nothing critical\n");
5193 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5195 /* We should exit now, since timeout is processed */
5199 /* Per-Lun scanning of timeouts is needed... */
5200 for (Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
5202 LunExtension
= DeviceExtension
->LunExtensionList
[Lun
];
5204 while (LunExtension
)
5206 if (LunExtension
->Flags
& LUNEX_BUSY
)
5208 if (!(LunExtension
->Flags
&
5209 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_FROZEN_QUEUE
)))
5211 DPRINT("Retrying busy request\n");
5213 /* Clear flags, and retry busy request */
5214 LunExtension
->Flags
&= ~(LUNEX_BUSY
| LUNEX_FULL_QUEUE
);
5215 Irp
= LunExtension
->BusyRequest
;
5217 /* Clearing busy request */
5218 LunExtension
->BusyRequest
= NULL
;
5220 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5222 IoStartPacket(DeviceObject
, Irp
, (PULONG
)NULL
, NULL
);
5224 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5227 else if (LunExtension
->RequestTimeout
== 0)
5229 RESETBUS_PARAMS ResetParams
;
5231 LunExtension
->RequestTimeout
= -1;
5233 DPRINT("Request timed out, resetting bus\n");
5235 /* Pass params to the bus reset routine */
5236 ResetParams
.PathId
= LunExtension
->PathId
;
5237 ResetParams
.DeviceExtension
= DeviceExtension
;
5239 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
5243 DPRINT1("Reset failed\n");
5246 else if (LunExtension
->RequestTimeout
> 0)
5248 /* Decrement the timeout counter */
5249 LunExtension
->RequestTimeout
--;
5252 LunExtension
= LunExtension
->Next
;
5256 /* Release the spinlock */
5257 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5260 /**********************************************************************
5265 * Builds the registry device map of all device which are attached
5266 * to the given SCSI HBA port. The device map is located at:
5267 * \Registry\Machine\DeviceMap\Scsi
5277 * Name of registry driver service key.
5284 SpiBuildDeviceMap(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5285 IN PUNICODE_STRING RegistryPath
)
5287 PSCSI_PORT_LUN_EXTENSION LunExtension
;
5288 OBJECT_ATTRIBUTES ObjectAttributes
;
5289 UNICODE_STRING KeyName
;
5290 UNICODE_STRING ValueName
;
5291 WCHAR NameBuffer
[64];
5294 HANDLE ScsiPortKey
= NULL
;
5295 HANDLE ScsiBusKey
= NULL
;
5296 HANDLE ScsiInitiatorKey
= NULL
;
5297 HANDLE ScsiTargetKey
= NULL
;
5298 HANDLE ScsiLunKey
= NULL
;
5301 ULONG CurrentTarget
;
5308 DPRINT("SpiBuildDeviceMap() called\n");
5310 if (DeviceExtension
== NULL
|| RegistryPath
== NULL
)
5312 DPRINT1("Invalid parameter\n");
5313 return STATUS_INVALID_PARAMETER
;
5316 /* Open or create the 'Scsi' subkey */
5317 RtlInitUnicodeString(&KeyName
,
5318 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
5319 InitializeObjectAttributes(&ObjectAttributes
,
5321 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_KERNEL_HANDLE
,
5324 Status
= ZwCreateKey(&ScsiKey
,
5329 REG_OPTION_VOLATILE
,
5331 if (!NT_SUCCESS(Status
))
5333 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5337 /* Create new 'Scsi Port X' subkey */
5338 DPRINT("Scsi Port %lu\n", DeviceExtension
->PortNumber
);
5340 swprintf(NameBuffer
,
5342 DeviceExtension
->PortNumber
);
5343 RtlInitUnicodeString(&KeyName
, NameBuffer
);
5344 InitializeObjectAttributes(&ObjectAttributes
,
5349 Status
= ZwCreateKey(&ScsiPortKey
,
5354 REG_OPTION_VOLATILE
,
5357 if (!NT_SUCCESS(Status
))
5359 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5364 * Create port-specific values
5367 /* Set 'DMA Enabled' (REG_DWORD) value */
5368 UlongData
= (ULONG
)!DeviceExtension
->PortCapabilities
.AdapterUsesPio
;
5369 DPRINT(" DMA Enabled = %s\n", UlongData
? "TRUE" : "FALSE");
5370 RtlInitUnicodeString(&ValueName
, L
"DMA Enabled");
5371 Status
= ZwSetValueKey(ScsiPortKey
,
5377 if (!NT_SUCCESS(Status
))
5379 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status
);
5380 ZwClose(ScsiPortKey
);
5384 /* Set 'Driver' (REG_SZ) value */
5385 DriverName
= wcsrchr(RegistryPath
->Buffer
, L
'\\') + 1;
5386 RtlInitUnicodeString(&ValueName
, L
"Driver");
5387 Status
= ZwSetValueKey(ScsiPortKey
,
5392 (ULONG
)((wcslen(DriverName
) + 1) * sizeof(WCHAR
)));
5393 if (!NT_SUCCESS(Status
))
5395 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status
);
5396 ZwClose(ScsiPortKey
);
5400 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
5401 UlongData
= (ULONG
)DeviceExtension
->PortConfig
->BusInterruptLevel
;
5402 DPRINT(" Interrupt = %lu\n", UlongData
);
5403 RtlInitUnicodeString(&ValueName
, L
"Interrupt");
5404 Status
= ZwSetValueKey(ScsiPortKey
,
5410 if (!NT_SUCCESS(Status
))
5412 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status
);
5413 ZwClose(ScsiPortKey
);
5417 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
5418 UlongData
= ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension
->PortConfig
->AccessRanges
)[0].RangeStart
);
5419 DPRINT(" IOAddress = %lx\n", UlongData
);
5420 RtlInitUnicodeString(&ValueName
, L
"IOAddress");
5421 Status
= ZwSetValueKey(ScsiPortKey
,
5427 if (!NT_SUCCESS(Status
))
5429 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status
);
5430 ZwClose(ScsiPortKey
);
5434 /* Enumerate buses */
5435 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
->NumberOfBuses
; BusNumber
++)
5437 /* Create 'Scsi Bus X' key */
5438 DPRINT(" Scsi Bus %lu\n", BusNumber
);
5439 swprintf(NameBuffer
,
5442 RtlInitUnicodeString(&KeyName
, NameBuffer
);
5443 InitializeObjectAttributes(&ObjectAttributes
,
5448 Status
= ZwCreateKey(&ScsiBusKey
,
5453 REG_OPTION_VOLATILE
,
5455 if (!NT_SUCCESS(Status
))
5457 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5461 /* Create 'Initiator Id X' key */
5462 DPRINT(" Initiator Id %lu\n",
5463 DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5464 swprintf(NameBuffer
,
5465 L
"Initiator Id %lu",
5466 (ULONG
)(UCHAR
)DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5467 RtlInitUnicodeString(&KeyName
, NameBuffer
);
5468 InitializeObjectAttributes(&ObjectAttributes
,
5473 Status
= ZwCreateKey(&ScsiInitiatorKey
,
5478 REG_OPTION_VOLATILE
,
5480 if (!NT_SUCCESS(Status
))
5482 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5486 /* FIXME: Are there any initiator values (??) */
5488 ZwClose(ScsiInitiatorKey
);
5489 ScsiInitiatorKey
= NULL
;
5492 /* Enumerate targets */
5493 CurrentTarget
= (ULONG
)-1;
5494 ScsiTargetKey
= NULL
;
5495 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
5497 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
5499 LunExtension
= SpiGetLunExtension(DeviceExtension
,
5503 if (LunExtension
== NULL
)
5506 if (Target
!= CurrentTarget
)
5508 /* Close old target key */
5509 if (ScsiTargetKey
!= NULL
)
5511 ZwClose(ScsiTargetKey
);
5512 ScsiTargetKey
= NULL
;
5515 /* Create 'Target Id X' key */
5516 DPRINT(" Target Id %lu\n", Target
);
5517 swprintf(NameBuffer
,
5520 RtlInitUnicodeString(&KeyName
, NameBuffer
);
5521 InitializeObjectAttributes(&ObjectAttributes
,
5526 Status
= ZwCreateKey(&ScsiTargetKey
,
5531 REG_OPTION_VOLATILE
,
5533 if (!NT_SUCCESS(Status
))
5535 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5539 CurrentTarget
= Target
;
5542 /* Create 'Logical Unit Id X' key */
5543 DPRINT(" Logical Unit Id %lu\n", Lun
);
5544 swprintf(NameBuffer
,
5545 L
"Logical Unit Id %lu",
5547 RtlInitUnicodeString(&KeyName
, NameBuffer
);
5548 InitializeObjectAttributes(&ObjectAttributes
,
5553 Status
= ZwCreateKey(&ScsiLunKey
,
5558 REG_OPTION_VOLATILE
,
5560 if (!NT_SUCCESS(Status
))
5562 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5566 /* Set 'Identifier' (REG_SZ) value */
5567 swprintf(NameBuffer
,
5569 LunExtension
->InquiryData
.VendorId
,
5570 LunExtension
->InquiryData
.ProductId
,
5571 LunExtension
->InquiryData
.ProductRevisionLevel
);
5572 DPRINT(" Identifier = '%S'\n", NameBuffer
);
5573 RtlInitUnicodeString(&ValueName
, L
"Identifier");
5574 Status
= ZwSetValueKey(ScsiLunKey
,
5579 (ULONG
)((wcslen(NameBuffer
) + 1) * sizeof(WCHAR
)));
5580 if (!NT_SUCCESS(Status
))
5582 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status
);
5586 /* Set 'Type' (REG_SZ) value */
5588 * See https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices
5589 * and https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-scsi-devices
5590 * for a list of types with their human-readable forms.
5592 switch (LunExtension
->InquiryData
.DeviceType
)
5595 TypeName
= L
"DiskPeripheral";
5598 TypeName
= L
"TapePeripheral";
5601 TypeName
= L
"PrinterPeripheral";
5603 // case 3: "ProcessorPeripheral", classified as 'other': fall back to default case.
5605 TypeName
= L
"WormPeripheral";
5608 TypeName
= L
"CdRomPeripheral";
5611 TypeName
= L
"ScannerPeripheral";
5614 TypeName
= L
"OpticalDiskPeripheral";
5617 TypeName
= L
"MediumChangerPeripheral";
5620 TypeName
= L
"CommunicationsPeripheral";
5623 /* New peripheral types (SCSI only) */
5625 TypeName
= L
"ASCPrePressGraphicsPeripheral";
5628 TypeName
= L
"ArrayPeripheral";
5631 TypeName
= L
"EnclosurePeripheral";
5634 TypeName
= L
"RBCPeripheral";
5637 TypeName
= L
"CardReaderPeripheral";
5640 TypeName
= L
"BridgePeripheral";
5644 TypeName
= L
"OtherPeripheral";
5647 DPRINT(" Type = '%S'\n", TypeName
);
5648 RtlInitUnicodeString(&ValueName
, L
"Type");
5649 Status
= ZwSetValueKey(ScsiLunKey
,
5654 (ULONG
)((wcslen(TypeName
) + 1) * sizeof(WCHAR
)));
5655 if (!NT_SUCCESS(Status
))
5657 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status
);
5661 ZwClose(ScsiLunKey
);
5665 /* Close old target key */
5666 if (ScsiTargetKey
!= NULL
)
5668 ZwClose(ScsiTargetKey
);
5669 ScsiTargetKey
= NULL
;
5673 ZwClose(ScsiBusKey
);
5678 if (ScsiLunKey
!= NULL
)
5679 ZwClose(ScsiLunKey
);
5681 if (ScsiInitiatorKey
!= NULL
)
5682 ZwClose(ScsiInitiatorKey
);
5684 if (ScsiTargetKey
!= NULL
)
5685 ZwClose(ScsiTargetKey
);
5687 if (ScsiBusKey
!= NULL
)
5688 ZwClose(ScsiBusKey
);
5690 if (ScsiPortKey
!= NULL
)
5691 ZwClose(ScsiPortKey
);
5693 DPRINT("SpiBuildDeviceMap() done\n");
5700 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
5701 IN PVOID DeviceObject
,
5702 IN PVOID SystemArgument1
,
5703 IN PVOID SystemArgument2
)
5705 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5707 DPRINT("Miniport timer DPC\n");
5709 DeviceExtension
= ((PDEVICE_OBJECT
)DeviceObject
)->DeviceExtension
;
5711 /* Acquire the spinlock */
5712 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5714 /* Call the timer routine */
5715 if (DeviceExtension
->HwScsiTimer
!= NULL
)
5717 DeviceExtension
->HwScsiTimer(&DeviceExtension
->MiniPortDeviceExtension
);
5720 /* Release the spinlock */
5721 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5723 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5725 ScsiPortDpcForIsr(NULL
,
5726 DeviceExtension
->DeviceObject
,
5733 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5734 PHW_INITIALIZATION_DATA HwInitData
,
5735 PCONFIGURATION_INFO InternalConfigInfo
,
5736 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5739 UNICODE_STRING UnicodeString
;
5740 OBJECT_ATTRIBUTES ObjectAttributes
;
5741 PCONFIGURATION_INFORMATION DdkConfigInformation
;
5742 HANDLE RootKey
, Key
;
5744 WCHAR DeviceBuffer
[16];
5745 WCHAR StrBuffer
[512];
5749 /* Zero out the struct if told so */
5752 /* First zero the portconfig */
5753 RtlZeroMemory(ConfigInfo
, sizeof(PORT_CONFIGURATION_INFORMATION
));
5755 /* Then access ranges */
5756 RtlZeroMemory(InternalConfigInfo
->AccessRanges
,
5757 HwInitData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
5759 /* Initialize the struct */
5760 ConfigInfo
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
5761 ConfigInfo
->AdapterInterfaceType
= HwInitData
->AdapterInterfaceType
;
5762 ConfigInfo
->InterruptMode
= Latched
;
5763 ConfigInfo
->DmaChannel
= SP_UNINITIALIZED_VALUE
;
5764 ConfigInfo
->DmaPort
= SP_UNINITIALIZED_VALUE
;
5765 ConfigInfo
->DmaChannel2
= SP_UNINITIALIZED_VALUE
;
5766 ConfigInfo
->DmaPort2
= SP_UNINITIALIZED_VALUE
;
5767 ConfigInfo
->MaximumTransferLength
= SP_UNINITIALIZED_VALUE
;
5768 ConfigInfo
->NumberOfAccessRanges
= HwInitData
->NumberOfAccessRanges
;
5769 ConfigInfo
->MaximumNumberOfTargets
= 8;
5771 /* Store parameters */
5772 ConfigInfo
->NeedPhysicalAddresses
= HwInitData
->NeedPhysicalAddresses
;
5773 ConfigInfo
->MapBuffers
= HwInitData
->MapBuffers
;
5774 ConfigInfo
->AutoRequestSense
= HwInitData
->AutoRequestSense
;
5775 ConfigInfo
->ReceiveEvent
= HwInitData
->ReceiveEvent
;
5776 ConfigInfo
->TaggedQueuing
= HwInitData
->TaggedQueuing
;
5777 ConfigInfo
->MultipleRequestPerLu
= HwInitData
->MultipleRequestPerLu
;
5779 /* Get the disk usage */
5780 DdkConfigInformation
= IoGetConfigurationInformation();
5781 ConfigInfo
->AtdiskPrimaryClaimed
= DdkConfigInformation
->AtDiskPrimaryAddressClaimed
;
5782 ConfigInfo
->AtdiskSecondaryClaimed
= DdkConfigInformation
->AtDiskSecondaryAddressClaimed
;
5784 /* Initiator bus id is not set */
5785 for (Bus
= 0; Bus
< 8; Bus
++)
5786 ConfigInfo
->InitiatorBusId
[Bus
] = (CCHAR
)SP_UNINITIALIZED_VALUE
;
5789 ConfigInfo
->NumberOfPhysicalBreaks
= 17;
5791 /* Clear this information */
5792 InternalConfigInfo
->DisableTaggedQueueing
= FALSE
;
5793 InternalConfigInfo
->DisableMultipleLun
= FALSE
;
5795 /* Store Bus Number */
5796 ConfigInfo
->SystemIoBusNumber
= InternalConfigInfo
->BusNumber
;
5800 if (ConfigInfo
->AdapterInterfaceType
== Internal
)
5802 /* Open registry key for HW database */
5803 InitializeObjectAttributes(&ObjectAttributes
,
5804 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
5805 OBJ_CASE_INSENSITIVE
,
5809 Status
= ZwOpenKey(&RootKey
,
5813 if (NT_SUCCESS(Status
))
5815 /* Create name for it */
5816 swprintf(StrBuffer
, L
"ScsiAdapter\\%lu",
5817 InternalConfigInfo
->AdapterNumber
);
5819 RtlInitUnicodeString(&UnicodeString
, StrBuffer
);
5821 /* Open device key */
5822 InitializeObjectAttributes(&ObjectAttributes
,
5824 OBJ_CASE_INSENSITIVE
,
5828 Status
= ZwOpenKey(&Key
,
5834 if (NT_SUCCESS(Status
))
5836 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5838 DPRINT("Hardware info found at %S\n", StrBuffer
);
5841 SpiParseDeviceInfo(DeviceExtension
,
5847 InternalConfigInfo
->BusNumber
= 0;
5851 /* Try the next adapter */
5852 InternalConfigInfo
->AdapterNumber
++;
5858 /* Info was not found, exit */
5859 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status
);
5860 return STATUS_DEVICE_DOES_NOT_EXIST
;
5865 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status
);
5869 /* Look at device params */
5871 if (InternalConfigInfo
->Parameter
)
5873 ExFreePool(InternalConfigInfo
->Parameter
);
5874 InternalConfigInfo
->Parameter
= NULL
;
5877 if (InternalConfigInfo
->ServiceKey
!= NULL
)
5879 swprintf(DeviceBuffer
, L
"Device%lu", InternalConfigInfo
->AdapterNumber
);
5880 RtlInitUnicodeString(&UnicodeString
, DeviceBuffer
);
5882 /* Open the service key */
5883 InitializeObjectAttributes(&ObjectAttributes
,
5885 OBJ_CASE_INSENSITIVE
,
5886 InternalConfigInfo
->ServiceKey
,
5889 Status
= ZwOpenKey(&Key
,
5894 /* Parse device key */
5895 if (InternalConfigInfo
->DeviceKey
!= NULL
)
5897 SpiParseDeviceInfo(DeviceExtension
,
5898 InternalConfigInfo
->DeviceKey
,
5904 /* Then parse hw info */
5907 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5909 SpiParseDeviceInfo(DeviceExtension
,
5920 /* Adapter not found, go try the next one */
5921 InternalConfigInfo
->AdapterNumber
++;
5930 /* Update the last adapter number */
5931 InternalConfigInfo
->LastAdapterNumber
= InternalConfigInfo
->AdapterNumber
;
5933 /* Do we have this kind of bus at all? */
5935 Status
= IoQueryDeviceDescription(&HwInitData
->AdapterInterfaceType
,
5936 &InternalConfigInfo
->BusNumber
,
5941 SpQueryDeviceCallout
,
5944 /* This bus was not found */
5947 INTERFACE_TYPE InterfaceType
= Eisa
;
5949 /* Check for EISA */
5950 if (HwInitData
->AdapterInterfaceType
== Isa
)
5952 Status
= IoQueryDeviceDescription(&InterfaceType
,
5953 &InternalConfigInfo
->BusNumber
,
5958 SpQueryDeviceCallout
,
5961 /* Return respectively */
5963 return STATUS_SUCCESS
;
5965 return STATUS_DEVICE_DOES_NOT_EXIST
;
5969 return STATUS_DEVICE_DOES_NOT_EXIST
;
5974 return STATUS_SUCCESS
;
5979 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5981 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5982 IN PCONFIGURATION_INFO InternalConfigInfo
,
5985 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
5986 PCM_FULL_RESOURCE_DESCRIPTOR FullResource
;
5987 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
5988 PCM_SCSI_DEVICE_DATA ScsiDeviceData
;
5989 ULONG Length
, Count
, Dma
= 0, Interrupt
= 0;
5990 ULONG Index
= 0, RangeCount
= 0;
5991 UNICODE_STRING UnicodeString
;
5992 ANSI_STRING AnsiString
;
5993 NTSTATUS Status
= STATUS_SUCCESS
;
5996 KeyValueInformation
= (PKEY_VALUE_FULL_INFORMATION
) Buffer
;
5998 /* Loop through all values in the device node */
6001 Status
= ZwEnumerateValueKey(Key
,
6003 KeyValueFullInformation
,
6008 if (!NT_SUCCESS(Status
))
6013 /* Length for DWORD is ok? */
6014 if (KeyValueInformation
->Type
== REG_DWORD
&&
6015 KeyValueInformation
->DataLength
!= sizeof(ULONG
))
6020 /* Get MaximumLogicalUnit */
6021 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumLogicalUnit",
6022 KeyValueInformation
->NameLength
/2) == 0)
6025 if (KeyValueInformation
->Type
!= REG_DWORD
)
6027 DPRINT("Bad data type for MaximumLogicalUnit\n");
6031 DeviceExtension
->MaxLunCount
= *((PUCHAR
)
6032 (Buffer
+ KeyValueInformation
->DataOffset
));
6034 /* Check / reset if needed */
6035 if (DeviceExtension
->MaxLunCount
> SCSI_MAXIMUM_LOGICAL_UNITS
)
6036 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
6038 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension
->MaxLunCount
);
6041 /* Get InitiatorTargetId */
6042 if (_wcsnicmp(KeyValueInformation
->Name
, L
"InitiatorTargetId",
6043 KeyValueInformation
->NameLength
/ 2) == 0)
6046 if (KeyValueInformation
->Type
!= REG_DWORD
)
6048 DPRINT("Bad data type for InitiatorTargetId\n");
6052 ConfigInfo
->InitiatorBusId
[0] = *((PUCHAR
)
6053 (Buffer
+ KeyValueInformation
->DataOffset
));
6055 /* Check / reset if needed */
6056 if (ConfigInfo
->InitiatorBusId
[0] > ConfigInfo
->MaximumNumberOfTargets
- 1)
6057 ConfigInfo
->InitiatorBusId
[0] = (CCHAR
)-1;
6059 DPRINT("InitiatorTargetId = %d\n", ConfigInfo
->InitiatorBusId
[0]);
6063 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ScsiDebug",
6064 KeyValueInformation
->NameLength
/2) == 0)
6066 DPRINT("ScsiDebug key not supported\n");
6069 /* Check for a breakpoint */
6070 if (_wcsnicmp(KeyValueInformation
->Name
, L
"BreakPointOnEntry",
6071 KeyValueInformation
->NameLength
/2) == 0)
6073 DPRINT1("Breakpoint on entry requested!\n");
6077 /* Get DisableSynchronousTransfers */
6078 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableSynchronousTransfers",
6079 KeyValueInformation
->NameLength
/2) == 0)
6081 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6082 DPRINT("Synch transfers disabled\n");
6085 /* Get DisableDisconnects */
6086 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableDisconnects",
6087 KeyValueInformation
->NameLength
/2) == 0)
6089 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
6090 DPRINT("Disconnects disabled\n");
6093 /* Get DisableTaggedQueuing */
6094 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableTaggedQueuing",
6095 KeyValueInformation
->NameLength
/2) == 0)
6097 InternalConfigInfo
->DisableTaggedQueueing
= TRUE
;
6098 DPRINT("Tagged queueing disabled\n");
6101 /* Get DisableMultipleRequests */
6102 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableMultipleRequests",
6103 KeyValueInformation
->NameLength
/2) == 0)
6105 InternalConfigInfo
->DisableMultipleLun
= TRUE
;
6106 DPRINT("Multiple requests disabled\n");
6109 /* Get DriverParameters */
6110 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DriverParameters",
6111 KeyValueInformation
->NameLength
/2) == 0)
6113 /* Skip if nothing */
6114 if (KeyValueInformation
->DataLength
== 0)
6117 /* If there was something previously allocated - free it */
6118 if (InternalConfigInfo
->Parameter
!= NULL
)
6119 ExFreePool(InternalConfigInfo
->Parameter
);
6122 InternalConfigInfo
->Parameter
= ExAllocatePoolWithTag(NonPagedPool
,
6123 KeyValueInformation
->DataLength
, TAG_SCSIPORT
);
6125 if (InternalConfigInfo
->Parameter
!= NULL
)
6127 if (KeyValueInformation
->Type
!= REG_SZ
)
6131 InternalConfigInfo
->Parameter
,
6132 (PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
,
6133 KeyValueInformation
->DataLength
);
6137 /* If it's a unicode string, convert it to ansi */
6138 UnicodeString
.Length
= (USHORT
)KeyValueInformation
->DataLength
;
6139 UnicodeString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
6140 UnicodeString
.Buffer
=
6141 (PWSTR
)((PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
6143 AnsiString
.Length
= 0;
6144 AnsiString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
6145 AnsiString
.Buffer
= (PCHAR
)InternalConfigInfo
->Parameter
;
6147 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
6151 /* In case of error, free the allocated space */
6152 if (!NT_SUCCESS(Status
))
6154 ExFreePool(InternalConfigInfo
->Parameter
);
6155 InternalConfigInfo
->Parameter
= NULL
;
6161 DPRINT("Found driver parameter\n");
6164 /* Get MaximumSGList */
6165 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumSGList",
6166 KeyValueInformation
->NameLength
/2) == 0)
6168 if (KeyValueInformation
->Type
!= REG_DWORD
)
6170 DPRINT("Bad data type for MaximumSGList\n");
6174 ConfigInfo
->NumberOfPhysicalBreaks
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
6177 if (ConfigInfo
->NumberOfPhysicalBreaks
> SCSI_MAXIMUM_PHYSICAL_BREAKS
)
6179 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MAXIMUM_PHYSICAL_BREAKS
;
6181 else if (ConfigInfo
->NumberOfPhysicalBreaks
< SCSI_MINIMUM_PHYSICAL_BREAKS
)
6183 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MINIMUM_PHYSICAL_BREAKS
;
6186 DPRINT("MaximumSGList = %d\n", ConfigInfo
->NumberOfPhysicalBreaks
);
6189 /* Get NumberOfRequests */
6190 if (_wcsnicmp(KeyValueInformation
->Name
, L
"NumberOfRequests",
6191 KeyValueInformation
->NameLength
/2) == 0)
6193 if (KeyValueInformation
->Type
!= REG_DWORD
)
6195 DPRINT("NumberOfRequests has wrong data type\n");
6199 DeviceExtension
->RequestsNumber
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
6202 if (DeviceExtension
->RequestsNumber
< 16)
6204 DeviceExtension
->RequestsNumber
= 16;
6206 else if (DeviceExtension
->RequestsNumber
> 512)
6208 DeviceExtension
->RequestsNumber
= 512;
6211 DPRINT("Number Of Requests = %d\n", DeviceExtension
->RequestsNumber
);
6214 /* Get resource list */
6215 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ResourceList",
6216 KeyValueInformation
->NameLength
/2) == 0 ||
6217 _wcsnicmp(KeyValueInformation
->Name
, L
"Configuration Data",
6218 KeyValueInformation
->NameLength
/2) == 0 )
6220 if (KeyValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
||
6221 KeyValueInformation
->DataLength
< sizeof(REG_FULL_RESOURCE_DESCRIPTOR
))
6223 DPRINT("Bad data type for ResourceList\n");
6228 DPRINT("Found ResourceList\n");
6231 FullResource
= (PCM_FULL_RESOURCE_DESCRIPTOR
)(Buffer
+ KeyValueInformation
->DataOffset
);
6233 /* Copy some info from it */
6234 InternalConfigInfo
->BusNumber
= FullResource
->BusNumber
;
6235 ConfigInfo
->SystemIoBusNumber
= FullResource
->BusNumber
;
6237 /* Loop through it */
6238 for (Count
= 0; Count
< FullResource
->PartialResourceList
.Count
; Count
++)
6240 /* Get partial descriptor */
6242 &FullResource
->PartialResourceList
.PartialDescriptors
[Count
];
6244 /* Check datalength */
6245 if ((ULONG
)((PCHAR
)(PartialDescriptor
+ 1) -
6246 (PCHAR
)FullResource
) > KeyValueInformation
->DataLength
)
6248 DPRINT("Resource data is of incorrect size\n");
6252 switch (PartialDescriptor
->Type
)
6254 case CmResourceTypePort
:
6255 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
6257 DPRINT("Too many access ranges\n");
6261 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= FALSE
;
6262 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Port
.Start
;
6263 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Port
.Length
;
6268 case CmResourceTypeMemory
:
6269 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
6271 DPRINT("Too many access ranges\n");
6275 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= TRUE
;
6276 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Memory
.Start
;
6277 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Memory
.Length
;
6282 case CmResourceTypeInterrupt
:
6286 ConfigInfo
->BusInterruptLevel
=
6287 PartialDescriptor
->u
.Interrupt
.Level
;
6289 ConfigInfo
->BusInterruptVector
=
6290 PartialDescriptor
->u
.Interrupt
.Vector
;
6292 ConfigInfo
->InterruptMode
= (PartialDescriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
) ? Latched
: LevelSensitive
;
6294 else if (Interrupt
== 1)
6296 ConfigInfo
->BusInterruptLevel2
=
6297 PartialDescriptor
->u
.Interrupt
.Level
;
6299 ConfigInfo
->BusInterruptVector2
=
6300 PartialDescriptor
->u
.Interrupt
.Vector
;
6302 ConfigInfo
->InterruptMode2
= (PartialDescriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
) ? Latched
: LevelSensitive
;
6308 case CmResourceTypeDma
:
6312 ConfigInfo
->DmaChannel
= PartialDescriptor
->u
.Dma
.Channel
;
6313 ConfigInfo
->DmaPort
= PartialDescriptor
->u
.Dma
.Port
;
6315 if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8
)
6316 ConfigInfo
->DmaWidth
= Width8Bits
;
6317 else if ((PartialDescriptor
->Flags
& CM_RESOURCE_DMA_16
) ||
6318 (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
6319 ConfigInfo
->DmaWidth
= Width16Bits
;
6320 else if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_32
)
6321 ConfigInfo
->DmaWidth
= Width32Bits
;
6325 ConfigInfo
->DmaChannel2
= PartialDescriptor
->u
.Dma
.Channel
;
6326 ConfigInfo
->DmaPort2
= PartialDescriptor
->u
.Dma
.Port
;
6328 if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8
)
6329 ConfigInfo
->DmaWidth2
= Width8Bits
;
6330 else if ((PartialDescriptor
->Flags
& CM_RESOURCE_DMA_16
) ||
6331 (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
6332 ConfigInfo
->DmaWidth2
= Width16Bits
;
6333 else if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_32
)
6334 ConfigInfo
->DmaWidth2
= Width32Bits
;
6340 case CmResourceTypeDeviceSpecific
:
6341 if (PartialDescriptor
->u
.DeviceSpecificData
.DataSize
<
6342 sizeof(CM_SCSI_DEVICE_DATA
) ||
6343 (PCHAR
) (PartialDescriptor
+ 1) - (PCHAR
)FullResource
+
6344 PartialDescriptor
->u
.DeviceSpecificData
.DataSize
>
6345 KeyValueInformation
->DataLength
)
6347 DPRINT("Resource data length is incorrect");
6351 /* Set only one field from it */
6352 ScsiDeviceData
= (PCM_SCSI_DEVICE_DATA
) (PartialDescriptor
+1);
6353 ConfigInfo
->InitiatorBusId
[0] = ScsiDeviceData
->HostIdentifier
;
6363 SpQueryDeviceCallout(IN PVOID Context
,
6364 IN PUNICODE_STRING PathName
,
6365 IN INTERFACE_TYPE BusType
,
6367 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
6368 IN CONFIGURATION_TYPE ControllerType
,
6369 IN ULONG ControllerNumber
,
6370 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
6371 IN CONFIGURATION_TYPE PeripheralType
,
6372 IN ULONG PeripheralNumber
,
6373 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
6375 PBOOLEAN Found
= (PBOOLEAN
)Context
;
6376 /* We just set our Found variable to TRUE */
6379 return STATUS_SUCCESS
;
6382 IO_ALLOCATION_ACTION
6384 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject
,
6386 IN PVOID MapRegisterBase
,
6390 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
6392 /* Guard access with the spinlock */
6393 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
6395 /* Save MapRegisterBase we've got here */
6396 DeviceExtension
->MapRegisterBase
= MapRegisterBase
;
6398 /* Start pending request */
6399 KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
6400 ScsiPortStartPacket
, DeviceObject
);
6402 /* Release spinlock we took */
6403 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
6410 SpiStatusSrbToNt(UCHAR SrbStatus
)
6412 switch (SRB_STATUS(SrbStatus
))
6414 case SRB_STATUS_TIMEOUT
:
6415 case SRB_STATUS_COMMAND_TIMEOUT
:
6416 return STATUS_IO_TIMEOUT
;
6418 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH
:
6419 case SRB_STATUS_BAD_FUNCTION
:
6420 return STATUS_INVALID_DEVICE_REQUEST
;
6422 case SRB_STATUS_NO_DEVICE
:
6423 case SRB_STATUS_INVALID_LUN
:
6424 case SRB_STATUS_INVALID_TARGET_ID
:
6425 case SRB_STATUS_NO_HBA
:
6426 return STATUS_DEVICE_DOES_NOT_EXIST
;
6428 case SRB_STATUS_DATA_OVERRUN
:
6429 return STATUS_BUFFER_OVERFLOW
;
6431 case SRB_STATUS_SELECTION_TIMEOUT
:
6432 return STATUS_DEVICE_NOT_CONNECTED
;
6435 return STATUS_IO_DEVICE_ERROR
;
6438 return STATUS_IO_DEVICE_ERROR
;
6442 #undef ScsiPortConvertPhysicalAddressToUlong
6447 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
6449 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
6450 return(Address
.u
.LowPart
);