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 *****************************************************************/
44 #include "scsiport_int.h"
46 ULONG InternalDebugLevel
= 0x00;
48 #undef ScsiPortMoveMemory
50 /* TYPES *********************************************************************/
52 /* GLOBALS *******************************************************************/
55 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
56 IN PDEVICE_OBJECT DeviceObject
,
57 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
58 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
59 IN PUNICODE_STRING RegistryPath
,
61 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
);
64 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
67 static DRIVER_DISPATCH ScsiPortDispatchScsi
;
69 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
73 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
76 static DRIVER_STARTIO ScsiPortStartIo
;
78 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
82 ScsiPortStartPacket(IN OUT PVOID Context
);
86 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
87 PVOID MapRegisterBase
, PVOID Context
);
89 static PSCSI_PORT_LUN_EXTENSION
90 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
92 static PSCSI_PORT_LUN_EXTENSION
93 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
98 static PSCSI_REQUEST_BLOCK_INFO
99 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
100 PSCSI_PORT_LUN_EXTENSION LunExtension
,
101 PSCSI_REQUEST_BLOCK Srb
);
104 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
105 IN PSCSI_LUN_INFO LunInfo
);
108 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
111 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
114 static PSCSI_REQUEST_BLOCK_INFO
115 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
122 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
123 IN PVOID ServiceContext
);
126 ScsiPortDpcForIsr(IN PKDPC Dpc
,
127 IN PDEVICE_OBJECT DpcDeviceObject
,
129 IN PVOID DpcContext
);
132 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
137 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject
,
139 IN PVOID MapRegisterBase
,
143 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
144 PUNICODE_STRING RegistryPath
);
147 SpiStatusSrbToNt(UCHAR SrbStatus
);
150 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
151 IN PSCSI_REQUEST_BLOCK Srb
);
153 static IO_COMPLETION_ROUTINE SpiCompletionRoutine
;
155 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
161 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
162 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
163 OUT PBOOLEAN NeedToCallStartIo
);
166 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
167 IN PSCSI_PORT_LUN_EXTENSION LunExtension
);
170 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
171 IN PVOID DeviceObject
,
172 IN PVOID SystemArgument1
,
173 IN PVOID SystemArgument2
);
176 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
177 PHW_INITIALIZATION_DATA HwInitData
,
178 PCONFIGURATION_INFO InternalConfigInfo
,
179 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
183 SpQueryDeviceCallout(IN PVOID Context
,
184 IN PUNICODE_STRING PathName
,
185 IN INTERFACE_TYPE BusType
,
187 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
188 IN CONFIGURATION_TYPE ControllerType
,
189 IN ULONG ControllerNumber
,
190 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
191 IN CONFIGURATION_TYPE PeripheralType
,
192 IN ULONG PeripheralNumber
,
193 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
);
196 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
198 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
199 IN PCONFIGURATION_INFO InternalConfigInfo
,
203 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
204 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
205 IN PPORT_CONFIGURATION_INFORMATION PortConfig
);
207 static PCM_RESOURCE_LIST
208 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
209 PPORT_CONFIGURATION_INFORMATION PortConfig
);
212 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
215 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
219 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
);
221 NTHALAPI ULONG NTAPI
HalGetBusData(BUS_DATA_TYPE
, ULONG
, ULONG
, PVOID
, ULONG
);
222 NTHALAPI ULONG NTAPI
HalGetInterruptVector(INTERFACE_TYPE
, ULONG
, ULONG
, ULONG
, PKIRQL
, PKAFFINITY
);
223 NTHALAPI NTSTATUS NTAPI
HalAssignSlotResources(PUNICODE_STRING
, PUNICODE_STRING
, PDRIVER_OBJECT
, PDEVICE_OBJECT
, INTERFACE_TYPE
, ULONG
, ULONG
, PCM_RESOURCE_LIST
*);
225 /* FUNCTIONS *****************************************************************/
227 /**********************************************************************
232 * This function initializes the driver.
239 * System allocated Driver Object for this driver.
242 * Name of registry driver service key.
249 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
250 IN PUNICODE_STRING RegistryPath
)
252 DPRINT("ScsiPort Driver %s\n", VERSION
);
253 return(STATUS_SUCCESS
);
257 /**********************************************************************
262 * Prints debugging messages.
269 * Debug level of the given message.
272 * Pointer to printf()-compatible format string.
275 Additional output data (see printf()).
284 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
285 IN PCHAR DebugMessage
,
291 if (DebugPrintLevel
> InternalDebugLevel
)
294 va_start(ap
, DebugMessage
);
295 vsprintf(Buffer
, DebugMessage
, ap
);
301 /* An internal helper function for ScsiPortCompleteRequest */
304 SpiCompleteRequest(IN PVOID HwDeviceExtension
,
305 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
308 PSCSI_REQUEST_BLOCK Srb
;
310 /* Get current SRB */
313 /* Return if there is no SRB or it is not active */
314 if (!Srb
|| !(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
)) return;
317 Srb
->SrbStatus
= SrbStatus
;
319 /* Set data transfered to 0 */
320 Srb
->DataTransferLength
= 0;
323 ScsiPortNotification(RequestComplete
,
332 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
338 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
339 PSCSI_PORT_LUN_EXTENSION LunExtension
;
340 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
341 PLIST_ENTRY ListEntry
;
345 DPRINT("ScsiPortCompleteRequest() called\n");
347 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
348 SCSI_PORT_DEVICE_EXTENSION
,
349 MiniPortDeviceExtension
);
351 /* Go through all buses */
352 for (BusNumber
= 0; BusNumber
< 8; BusNumber
++)
354 /* Go through all targets */
355 for (Target
= 0; Target
< DeviceExtension
->MaxTargedIds
; Target
++)
357 /* Get logical unit list head */
358 LunExtension
= DeviceExtension
->LunExtensionList
[Target
% 8];
360 /* Go through all logical units */
363 /* Now match what caller asked with what we are at now */
364 if ((PathId
== SP_UNTAGGED
|| PathId
== LunExtension
->PathId
) &&
365 (TargetId
== SP_UNTAGGED
|| TargetId
== LunExtension
->TargetId
) &&
366 (Lun
== SP_UNTAGGED
|| Lun
== LunExtension
->Lun
))
368 /* Yes, that's what caller asked for. Complete abort requests */
369 if (LunExtension
->CompletedAbortRequests
)
371 /* TODO: Save SrbStatus in this request */
372 DPRINT1("Completing abort request without setting SrbStatus!\n");
374 /* Issue a notification request */
375 ScsiPortNotification(RequestComplete
,
377 LunExtension
->CompletedAbortRequests
);
380 /* Complete the request using our helper */
381 SpiCompleteRequest(HwDeviceExtension
,
382 &LunExtension
->SrbInfo
,
385 /* Go through the queue and complete everything there too */
386 ListEntry
= LunExtension
->SrbInfo
.Requests
.Flink
;
387 while (ListEntry
!= &LunExtension
->SrbInfo
.Requests
)
389 /* Get the actual SRB info entry */
390 SrbInfo
= CONTAINING_RECORD(ListEntry
,
391 SCSI_REQUEST_BLOCK_INFO
,
395 SpiCompleteRequest(HwDeviceExtension
,
399 /* Advance to the next request in queue */
400 ListEntry
= SrbInfo
->Requests
.Flink
;
404 /* Advance to the next one */
405 LunExtension
= LunExtension
->Next
;
415 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
417 DPRINT("ScsiPortFlushDma()\n");
426 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
427 IN PVOID MappedAddress
)
429 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
430 PMAPPED_ADDRESS NextMa
, LastMa
;
432 //DPRINT("ScsiPortFreeDeviceBase() called\n");
434 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
435 SCSI_PORT_DEVICE_EXTENSION
,
436 MiniPortDeviceExtension
);
438 /* Initialize our pointers */
439 NextMa
= DeviceExtension
->MappedAddressList
;
444 if (NextMa
->MappedAddress
== MappedAddress
)
447 MmUnmapIoSpace(MappedAddress
, NextMa
->NumberOfBytes
);
449 /* Remove it from the list */
450 if (NextMa
== DeviceExtension
->MappedAddressList
)
452 /* Remove the first entry */
453 DeviceExtension
->MappedAddressList
= NextMa
->NextMappedAddress
;
457 LastMa
->NextMappedAddress
= NextMa
->NextMappedAddress
;
460 /* Free the resources and quit */
468 NextMa
= NextMa
->NextMappedAddress
;
478 ScsiPortGetBusData(IN PVOID DeviceExtension
,
479 IN ULONG BusDataType
,
480 IN ULONG SystemIoBusNumber
,
485 DPRINT("ScsiPortGetBusData()\n");
489 /* If Length is non-zero, just forward the call to
490 HalGetBusData() function */
491 return HalGetBusData(BusDataType
,
498 /* We have a more complex case here */
507 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
508 IN ULONG BusDataType
,
509 IN ULONG SystemIoBusNumber
,
515 DPRINT("ScsiPortSetBusDataByOffset()\n");
516 return HalSetBusDataByOffset(BusDataType
,
528 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
529 IN INTERFACE_TYPE BusType
,
530 IN ULONG SystemIoBusNumber
,
531 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
532 IN ULONG NumberOfBytes
,
533 IN BOOLEAN InIoSpace
)
535 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
536 PHYSICAL_ADDRESS TranslatedAddress
;
537 PMAPPED_ADDRESS DeviceBase
;
541 //DPRINT ("ScsiPortGetDeviceBase() called\n");
543 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
544 SCSI_PORT_DEVICE_EXTENSION
,
545 MiniPortDeviceExtension
);
547 AddressSpace
= (ULONG
)InIoSpace
;
548 if (HalTranslateBusAddress(BusType
,
552 &TranslatedAddress
) == FALSE
)
558 if (AddressSpace
!= 0)
559 return((PVOID
)(ULONG_PTR
)TranslatedAddress
.QuadPart
);
561 MappedAddress
= MmMapIoSpace(TranslatedAddress
,
565 DeviceBase
= ExAllocatePoolWithTag(NonPagedPool
,
566 sizeof(MAPPED_ADDRESS
), TAG_SCSIPORT
);
568 if (DeviceBase
== NULL
)
569 return MappedAddress
;
571 DeviceBase
->MappedAddress
= MappedAddress
;
572 DeviceBase
->NumberOfBytes
= NumberOfBytes
;
573 DeviceBase
->IoAddress
= IoAddress
;
574 DeviceBase
->BusNumber
= SystemIoBusNumber
;
576 /* Link it to the Device Extension list */
577 DeviceBase
->NextMappedAddress
= DeviceExtension
->MappedAddressList
;
578 DeviceExtension
->MappedAddressList
= DeviceBase
;
580 return MappedAddress
;
587 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
594 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
595 PSCSI_PORT_LUN_EXTENSION LunExtension
;
598 DPRINT("ScsiPortGetLogicalUnit() called\n");
600 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
601 SCSI_PORT_DEVICE_EXTENSION
,
602 MiniPortDeviceExtension
);
603 if (IsListEmpty(&DeviceExtension
->LunExtensionListHead
))
606 Entry
= DeviceExtension
->LunExtensionListHead
.Flink
;
607 while (Entry
!= &DeviceExtension
->LunExtensionListHead
)
609 LunExtension
= CONTAINING_RECORD(Entry
,
610 SCSI_PORT_LUN_EXTENSION
,
612 if (LunExtension
->PathId
== PathId
&&
613 LunExtension
->TargetId
== TargetId
&&
614 LunExtension
->Lun
== Lun
)
616 return (PVOID
)&LunExtension
->MiniportLunExtension
;
619 Entry
= Entry
->Flink
;
629 SCSI_PHYSICAL_ADDRESS NTAPI
630 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
631 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
632 IN PVOID VirtualAddress
,
635 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
636 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
637 ULONG BufferLength
= 0;
639 PSCSI_SG_ADDRESS SGList
;
640 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
642 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
643 HwDeviceExtension
, Srb
, VirtualAddress
, Length
);
645 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
646 SCSI_PORT_DEVICE_EXTENSION
,
647 MiniPortDeviceExtension
);
649 if (Srb
== NULL
|| Srb
->SenseInfoBuffer
== VirtualAddress
)
651 /* Simply look it up in the allocated common buffer */
652 Offset
= (PUCHAR
)VirtualAddress
- (PUCHAR
)DeviceExtension
->SrbExtensionBuffer
;
654 BufferLength
= DeviceExtension
->CommonBufferLength
- Offset
;
655 PhysicalAddress
.QuadPart
= DeviceExtension
->PhysicalAddress
.QuadPart
+ Offset
;
657 else if (DeviceExtension
->MapRegisters
)
659 /* Scatter-gather list must be used */
660 SrbInfo
= SpiGetSrbData(DeviceExtension
,
666 SGList
= SrbInfo
->ScatterGather
;
668 /* Find needed item in the SG list */
669 Offset
= (PCHAR
)VirtualAddress
- (PCHAR
)Srb
->DataBuffer
;
670 while (Offset
>= SGList
->Length
)
672 Offset
-= SGList
->Length
;
676 /* We're done, store length and physical address */
677 BufferLength
= SGList
->Length
- Offset
;
678 PhysicalAddress
.QuadPart
= SGList
->PhysicalAddress
.QuadPart
+ Offset
;
684 PhysicalAddress
.QuadPart
= (LONGLONG
)(SP_UNINITIALIZED_VALUE
);
687 *Length
= BufferLength
;
688 return PhysicalAddress
;
695 PSCSI_REQUEST_BLOCK NTAPI
696 ScsiPortGetSrb(IN PVOID DeviceExtension
,
702 DPRINT1("ScsiPortGetSrb() unimplemented\n");
712 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
713 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
714 IN ULONG NumberOfBytes
)
716 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
717 DEVICE_DESCRIPTION DeviceDescription
;
718 ULONG MapRegistersCount
;
721 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
722 HwDeviceExtension
, ConfigInfo
, NumberOfBytes
);
724 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
725 SCSI_PORT_DEVICE_EXTENSION
,
726 MiniPortDeviceExtension
);
728 /* Check for allocated common DMA buffer */
729 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
)
731 DPRINT1("The HBA has already got a common DMA buffer!\n");
735 /* Check for DMA adapter object */
736 if (DeviceExtension
->AdapterObject
== NULL
)
738 /* Initialize DMA adapter description */
739 RtlZeroMemory(&DeviceDescription
, sizeof(DEVICE_DESCRIPTION
));
741 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
742 DeviceDescription
.Master
= ConfigInfo
->Master
;
743 DeviceDescription
.ScatterGather
= ConfigInfo
->ScatterGather
;
744 DeviceDescription
.DemandMode
= ConfigInfo
->DemandMode
;
745 DeviceDescription
.Dma32BitAddresses
= ConfigInfo
->Dma32BitAddresses
;
746 DeviceDescription
.BusNumber
= ConfigInfo
->SystemIoBusNumber
;
747 DeviceDescription
.DmaChannel
= ConfigInfo
->DmaChannel
;
748 DeviceDescription
.InterfaceType
= ConfigInfo
->AdapterInterfaceType
;
749 DeviceDescription
.DmaWidth
= ConfigInfo
->DmaWidth
;
750 DeviceDescription
.DmaSpeed
= ConfigInfo
->DmaSpeed
;
751 DeviceDescription
.MaximumLength
= ConfigInfo
->MaximumTransferLength
;
752 DeviceDescription
.DmaPort
= ConfigInfo
->DmaPort
;
754 /* Get a DMA adapter object */
755 DeviceExtension
->AdapterObject
=
756 HalGetAdapter(&DeviceDescription
, &MapRegistersCount
);
758 /* Fail in case of error */
759 if (DeviceExtension
->AdapterObject
== NULL
)
761 DPRINT1("HalGetAdapter() failed\n");
765 /* Set number of physical breaks */
766 if (ConfigInfo
->NumberOfPhysicalBreaks
!= 0 &&
767 MapRegistersCount
> ConfigInfo
->NumberOfPhysicalBreaks
)
769 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
=
770 ConfigInfo
->NumberOfPhysicalBreaks
;
774 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
= MapRegistersCount
;
778 /* Update auto request sense feature */
779 DeviceExtension
->SupportsAutoSense
= ConfigInfo
->AutoRequestSense
;
781 /* Update Srb extension size */
782 if (DeviceExtension
->SrbExtensionSize
!= ConfigInfo
->SrbExtensionSize
)
783 DeviceExtension
->SrbExtensionSize
= ConfigInfo
->SrbExtensionSize
;
785 /* Update Srb extension alloc flag */
786 if (ConfigInfo
->AutoRequestSense
|| DeviceExtension
->SrbExtensionSize
)
787 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
789 /* Allocate a common DMA buffer */
790 Status
= SpiAllocateCommonBuffer(DeviceExtension
, NumberOfBytes
);
792 if (!NT_SUCCESS(Status
))
794 DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status
);
798 return DeviceExtension
->NonCachedExtension
;
802 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
)
804 PVOID
*SrbExtension
, CommonBuffer
;
805 ULONG CommonBufferLength
, BufSize
;
807 /* If size is 0, set it to 16 */
808 if (!DeviceExtension
->SrbExtensionSize
)
809 DeviceExtension
->SrbExtensionSize
= 16;
812 BufSize
= DeviceExtension
->SrbExtensionSize
;
814 /* Add autosense data size if needed */
815 if (DeviceExtension
->SupportsAutoSense
)
816 BufSize
+= sizeof(SENSE_DATA
);
820 BufSize
= (BufSize
+ sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
822 /* Sum up into the total common buffer length, and round it to page size */
824 ROUND_TO_PAGES(NonCachedSize
+ BufSize
* DeviceExtension
->RequestsNumber
);
827 if (!DeviceExtension
->AdapterObject
)
829 /* From nonpaged pool if there is no DMA */
830 CommonBuffer
= ExAllocatePoolWithTag(NonPagedPool
, CommonBufferLength
, TAG_SCSIPORT
);
834 /* Perform a full request since we have a DMA adapter*/
835 CommonBuffer
= HalAllocateCommonBuffer(DeviceExtension
->AdapterObject
,
837 &DeviceExtension
->PhysicalAddress
,
841 /* Fail in case of error */
843 return STATUS_INSUFFICIENT_RESOURCES
;
846 RtlZeroMemory(CommonBuffer
, CommonBufferLength
);
848 /* Store its size in Device Extension */
849 DeviceExtension
->CommonBufferLength
= CommonBufferLength
;
851 /* SrbExtension buffer is located at the beginning of the buffer */
852 DeviceExtension
->SrbExtensionBuffer
= CommonBuffer
;
854 /* Non-cached extension buffer is located at the end of
858 CommonBufferLength
-= NonCachedSize
;
859 DeviceExtension
->NonCachedExtension
= (PUCHAR
)CommonBuffer
+ CommonBufferLength
;
863 DeviceExtension
->NonCachedExtension
= NULL
;
866 if (DeviceExtension
->NeedSrbExtensionAlloc
)
868 /* Look up how many SRB data structures we need */
869 DeviceExtension
->SrbDataCount
= CommonBufferLength
/ BufSize
;
871 /* Initialize the free SRB extensions list */
872 SrbExtension
= (PVOID
*)CommonBuffer
;
873 DeviceExtension
->FreeSrbExtensions
= SrbExtension
;
875 /* Fill the remainding pointers (if we have more than 1 SRB) */
876 while (CommonBufferLength
>= 2 * BufSize
)
878 *SrbExtension
= (PVOID
*)((PCHAR
)SrbExtension
+ BufSize
);
879 SrbExtension
= *SrbExtension
;
881 CommonBufferLength
-= BufSize
;
885 return STATUS_SUCCESS
;
894 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
895 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
897 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
900 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
901 HwDeviceExtension
, PhysicalAddress
.QuadPart
);
903 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
904 SCSI_PORT_DEVICE_EXTENSION
,
905 MiniPortDeviceExtension
);
907 if (DeviceExtension
->PhysicalAddress
.QuadPart
> PhysicalAddress
.QuadPart
)
910 Offset
= (ULONG
)(PhysicalAddress
.QuadPart
- DeviceExtension
->PhysicalAddress
.QuadPart
);
912 if (Offset
>= DeviceExtension
->CommonBufferLength
)
915 return (PVOID
)((ULONG_PTR
)DeviceExtension
->SrbExtensionBuffer
+ Offset
);
919 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo
, PUNICODE_STRING RegistryPath
)
921 OBJECT_ATTRIBUTES ObjectAttributes
;
922 UNICODE_STRING KeyName
;
925 /* Open the service key */
926 InitializeObjectAttributes(&ObjectAttributes
,
928 OBJ_CASE_INSENSITIVE
,
932 Status
= ZwOpenKey(&ConfigInfo
->ServiceKey
,
936 if (!NT_SUCCESS(Status
))
938 DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath
, Status
);
939 ConfigInfo
->ServiceKey
= NULL
;
942 /* If we could open driver's service key, then proceed to the Parameters key */
943 if (ConfigInfo
->ServiceKey
!= NULL
)
945 RtlInitUnicodeString(&KeyName
, L
"Parameters");
946 InitializeObjectAttributes(&ObjectAttributes
,
948 OBJ_CASE_INSENSITIVE
,
949 ConfigInfo
->ServiceKey
,
950 (PSECURITY_DESCRIPTOR
) NULL
);
953 Status
= ZwOpenKey(&ConfigInfo
->DeviceKey
,
957 if (NT_SUCCESS(Status
))
959 /* Yes, Parameters key exist, and it must be used instead of
961 ZwClose(ConfigInfo
->ServiceKey
);
962 ConfigInfo
->ServiceKey
= ConfigInfo
->DeviceKey
;
963 ConfigInfo
->DeviceKey
= NULL
;
967 if (ConfigInfo
->ServiceKey
!= NULL
)
969 /* Open the Device key */
970 RtlInitUnicodeString(&KeyName
, L
"Device");
971 InitializeObjectAttributes(&ObjectAttributes
,
973 OBJ_CASE_INSENSITIVE
,
974 ConfigInfo
->ServiceKey
,
977 /* We don't check for failure here - not needed */
978 ZwOpenKey(&ConfigInfo
->DeviceKey
,
985 /**********************************************************************
990 * Initializes SCSI port driver specific data.
997 * Pointer to the miniport driver's driver object.
1000 * Pointer to the miniport driver's registry path.
1002 * HwInitializationData
1003 * Pointer to port driver specific configuration data.
1006 Miniport driver specific context.
1015 ScsiPortInitialize(IN PVOID Argument1
,
1017 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
1020 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
1021 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
1022 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
1023 PCONFIGURATION_INFORMATION SystemConfig
;
1024 PPORT_CONFIGURATION_INFORMATION PortConfig
;
1025 PORT_CONFIGURATION_INFORMATION InitialPortConfig
;
1026 CONFIGURATION_INFO ConfigInfo
;
1027 ULONG DeviceExtensionSize
;
1028 ULONG PortConfigSize
;
1030 BOOLEAN DeviceFound
= FALSE
;
1031 BOOLEAN FirstConfigCall
= TRUE
;
1035 ULONG BusNumber
= 0;
1036 PCI_SLOT_NUMBER SlotNumber
;
1038 PDEVICE_OBJECT PortDeviceObject
;
1039 WCHAR NameBuffer
[80];
1040 UNICODE_STRING DeviceName
;
1041 WCHAR DosNameBuffer
[80];
1042 UNICODE_STRING DosDeviceName
;
1043 PIO_SCSI_CAPABILITIES PortCapabilities
;
1046 PCM_RESOURCE_LIST ResourceList
;
1050 DPRINT ("ScsiPortInitialize() called!\n");
1052 /* Check params for validity */
1053 if ((HwInitializationData
->HwInitialize
== NULL
) ||
1054 (HwInitializationData
->HwStartIo
== NULL
) ||
1055 (HwInitializationData
->HwInterrupt
== NULL
) ||
1056 (HwInitializationData
->HwFindAdapter
== NULL
) ||
1057 (HwInitializationData
->HwResetBus
== NULL
))
1059 return STATUS_INVALID_PARAMETER
;
1063 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
1064 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
1065 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
1066 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
1067 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
1068 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
1070 /* Obtain configuration information */
1071 SystemConfig
= IoGetConfigurationInformation();
1073 /* Zero the internal configuration info structure */
1074 RtlZeroMemory(&ConfigInfo
, sizeof(CONFIGURATION_INFO
));
1076 /* Zero starting slot number */
1077 SlotNumber
.u
.AsULONG
= 0;
1079 /* Allocate space for access ranges */
1080 if (HwInitializationData
->NumberOfAccessRanges
)
1082 ConfigInfo
.AccessRanges
=
1083 ExAllocatePoolWithTag(PagedPool
,
1084 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
), TAG_SCSIPORT
);
1086 /* Fail if failed */
1087 if (ConfigInfo
.AccessRanges
== NULL
)
1088 return STATUS_INSUFFICIENT_RESOURCES
;
1091 /* Open registry keys */
1092 SpiInitOpenKeys(&ConfigInfo
, (PUNICODE_STRING
)Argument2
);
1094 /* Last adapter number = not known */
1095 ConfigInfo
.LastAdapterNumber
= SP_UNINITIALIZED_VALUE
;
1097 /* Calculate sizes of DeviceExtension and PortConfig */
1098 DeviceExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
1099 HwInitializationData
->DeviceExtensionSize
;
1101 MaxBus
= (HwInitializationData
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
1102 DPRINT("MaxBus: %lu\n", MaxBus
);
1106 /* Create a unicode device name */
1107 swprintf(NameBuffer
,
1108 L
"\\Device\\ScsiPort%lu",
1109 SystemConfig
->ScsiPortCount
);
1110 RtlInitUnicodeString(&DeviceName
, NameBuffer
);
1112 DPRINT("Creating device: %wZ\n", &DeviceName
);
1114 /* Create the port device */
1115 Status
= IoCreateDevice(DriverObject
,
1116 DeviceExtensionSize
,
1118 FILE_DEVICE_CONTROLLER
,
1123 if (!NT_SUCCESS(Status
))
1125 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
1126 PortDeviceObject
= NULL
;
1130 DPRINT ("Created device: %wZ (%p)\n", &DeviceName
, PortDeviceObject
);
1132 /* Set the buffering strategy here... */
1133 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1134 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
; /* FIXME: Is this really needed? */
1136 /* Fill Device Extension */
1137 DeviceExtension
= PortDeviceObject
->DeviceExtension
;
1138 RtlZeroMemory(DeviceExtension
, DeviceExtensionSize
);
1139 DeviceExtension
->Length
= DeviceExtensionSize
;
1140 DeviceExtension
->DeviceObject
= PortDeviceObject
;
1141 DeviceExtension
->PortNumber
= SystemConfig
->ScsiPortCount
;
1143 /* Driver's routines... */
1144 DeviceExtension
->HwInitialize
= HwInitializationData
->HwInitialize
;
1145 DeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
1146 DeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
1147 DeviceExtension
->HwResetBus
= HwInitializationData
->HwResetBus
;
1148 DeviceExtension
->HwDmaStarted
= HwInitializationData
->HwDmaStarted
;
1150 /* Extensions sizes */
1151 DeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
1152 DeviceExtension
->LunExtensionSize
= HwInitializationData
->SpecificLuExtensionSize
;
1153 DeviceExtension
->SrbExtensionSize
= HwInitializationData
->SrbExtensionSize
;
1155 /* Round Srb extension size to the quadword */
1156 DeviceExtension
->SrbExtensionSize
=
1157 ~(sizeof(LONGLONG
) - 1) & (DeviceExtension
->SrbExtensionSize
+
1158 sizeof(LONGLONG
) - 1);
1160 /* Fill some numbers (bus count, lun count, etc) */
1161 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
1162 DeviceExtension
->RequestsNumber
= 16;
1164 /* Initialize the spin lock in the controller extension */
1165 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1166 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
1168 /* Initialize the DPC object */
1169 IoInitializeDpcRequest(PortDeviceObject
,
1172 /* Initialize the device timer */
1173 DeviceExtension
->TimerCount
= -1;
1174 IoInitializeTimer(PortDeviceObject
,
1178 /* Initialize miniport timer */
1179 KeInitializeTimer(&DeviceExtension
->MiniportTimer
);
1180 KeInitializeDpc(&DeviceExtension
->MiniportTimerDpc
,
1181 SpiMiniportTimerDpc
,
1186 Status
= SpiCreatePortConfig(DeviceExtension
,
1187 HwInitializationData
,
1192 if (!NT_SUCCESS(Status
))
1194 DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status
);
1198 /* Allocate and initialize port configuration info */
1199 PortConfigSize
= (sizeof(PORT_CONFIGURATION_INFORMATION
) +
1200 HwInitializationData
->NumberOfAccessRanges
*
1201 sizeof(ACCESS_RANGE
) + 7) & ~7;
1202 DeviceExtension
->PortConfig
= ExAllocatePoolWithTag(NonPagedPool
, PortConfigSize
, TAG_SCSIPORT
);
1204 /* Fail if failed */
1205 if (DeviceExtension
->PortConfig
== NULL
)
1207 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1211 PortConfig
= DeviceExtension
->PortConfig
;
1213 /* Copy information here */
1214 RtlCopyMemory(PortConfig
,
1216 sizeof(PORT_CONFIGURATION_INFORMATION
));
1219 /* Copy extension sizes into the PortConfig */
1220 PortConfig
->SpecificLuExtensionSize
= DeviceExtension
->LunExtensionSize
;
1221 PortConfig
->SrbExtensionSize
= DeviceExtension
->SrbExtensionSize
;
1223 /* Initialize Access ranges */
1224 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1226 PortConfig
->AccessRanges
= (PVOID
)(PortConfig
+1);
1228 /* Align to LONGLONG */
1229 PortConfig
->AccessRanges
= (PVOID
)((ULONG_PTR
)(PortConfig
->AccessRanges
) + 7);
1230 PortConfig
->AccessRanges
= (PVOID
)((ULONG_PTR
)(PortConfig
->AccessRanges
) & ~7);
1233 RtlCopyMemory(PortConfig
->AccessRanges
,
1234 ConfigInfo
.AccessRanges
,
1235 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
1238 /* Search for matching PCI device */
1239 if ((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1240 (HwInitializationData
->VendorIdLength
> 0) &&
1241 (HwInitializationData
->VendorId
!= NULL
) &&
1242 (HwInitializationData
->DeviceIdLength
> 0) &&
1243 (HwInitializationData
->DeviceId
!= NULL
))
1245 PortConfig
->BusInterruptLevel
= 0;
1247 /* Get PCI device data */
1248 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1249 HwInitializationData
->VendorIdLength
,
1250 HwInitializationData
->VendorId
,
1251 HwInitializationData
->DeviceIdLength
,
1252 HwInitializationData
->DeviceId
);
1254 if (!SpiGetPciConfigData(DriverObject
,
1256 HwInitializationData
,
1259 ConfigInfo
.BusNumber
,
1262 /* Continue to the next bus, nothing here */
1263 ConfigInfo
.BusNumber
++;
1264 DeviceExtension
->PortConfig
= NULL
;
1265 ExFreePool(PortConfig
);
1267 goto CreatePortConfig
;
1270 if (!PortConfig
->BusInterruptLevel
)
1272 /* Bypass this slot, because no interrupt was assigned */
1273 DeviceExtension
->PortConfig
= NULL
;
1274 ExFreePool(PortConfig
);
1275 goto CreatePortConfig
;
1280 DPRINT("Non-pci bus\n");
1283 /* Note: HwFindAdapter is called once for each bus */
1285 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
1286 Result
= (HwInitializationData
->HwFindAdapter
)(&DeviceExtension
->MiniPortDeviceExtension
,
1288 0, /* BusInformation */
1289 ConfigInfo
.Parameter
, /* ArgumentString */
1293 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1294 Result
, (Again
) ? "True" : "False");
1296 /* Free MapRegisterBase, it's not needed anymore */
1297 if (DeviceExtension
->MapRegisterBase
!= NULL
)
1299 ExFreePool(DeviceExtension
->MapRegisterBase
);
1300 DeviceExtension
->MapRegisterBase
= NULL
;
1303 /* If result is nothing good... */
1304 if (Result
!= SP_RETURN_FOUND
)
1306 DPRINT("HwFindAdapter() Result: %lu\n", Result
);
1308 if (Result
== SP_RETURN_NOT_FOUND
)
1310 /* We can continue on the next bus */
1311 ConfigInfo
.BusNumber
++;
1314 DeviceExtension
->PortConfig
= NULL
;
1315 ExFreePool(PortConfig
);
1316 goto CreatePortConfig
;
1319 /* Otherwise, break */
1320 Status
= STATUS_INTERNAL_ERROR
;
1324 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1325 PortConfig
->BusInterruptVector
, PortConfig
->InitiatorBusId
[0]);
1327 /* If the SRB extension size was updated */
1328 if (!DeviceExtension
->NonCachedExtension
&&
1329 (PortConfig
->SrbExtensionSize
!= DeviceExtension
->SrbExtensionSize
))
1331 /* Set it (rounding to LONGLONG again) */
1332 DeviceExtension
->SrbExtensionSize
=
1333 (PortConfig
->SrbExtensionSize
+
1334 sizeof(LONGLONG
)) & ~(sizeof(LONGLONG
) - 1);
1337 /* The same with LUN extension size */
1338 if (PortConfig
->SpecificLuExtensionSize
!= DeviceExtension
->LunExtensionSize
)
1339 DeviceExtension
->LunExtensionSize
= PortConfig
->SpecificLuExtensionSize
;
1342 if (!((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1343 (HwInitializationData
->VendorIdLength
> 0) &&
1344 (HwInitializationData
->VendorId
!= NULL
) &&
1345 (HwInitializationData
->DeviceIdLength
> 0) &&
1346 (HwInitializationData
->DeviceId
!= NULL
)))
1348 /* Construct a resource list */
1349 ResourceList
= SpiConfigToResource(DeviceExtension
,
1354 UNICODE_STRING UnicodeString
;
1355 RtlInitUnicodeString(&UnicodeString
, L
"ScsiAdapter");
1356 DPRINT("Reporting resources\n");
1357 Status
= IoReportResourceUsage(&UnicodeString
,
1363 FIELD_OFFSET(CM_RESOURCE_LIST
,
1364 List
[0].PartialResourceList
.PartialDescriptors
) +
1365 ResourceList
->List
[0].PartialResourceList
.Count
1366 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
1369 ExFreePool(ResourceList
);
1371 /* In case of a failure or a conflict, break */
1372 if (Conflict
|| (!NT_SUCCESS(Status
)))
1375 Status
= STATUS_CONFLICTING_ADDRESSES
;
1381 /* Reset the Conflict var */
1384 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1385 if (PortConfig
->MaximumNumberOfTargets
> SCSI_MAXIMUM_TARGETS_PER_BUS
)
1386 DeviceExtension
->MaxTargedIds
= SCSI_MAXIMUM_TARGETS_PER_BUS
;
1388 DeviceExtension
->MaxTargedIds
= PortConfig
->MaximumNumberOfTargets
;
1390 DeviceExtension
->BusNum
= PortConfig
->NumberOfBuses
;
1391 DeviceExtension
->CachesData
= PortConfig
->CachesData
;
1392 DeviceExtension
->ReceiveEvent
= PortConfig
->ReceiveEvent
;
1393 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->TaggedQueuing
;
1394 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
;
1396 /* If something was disabled via registry - apply it */
1397 if (ConfigInfo
.DisableMultipleLun
)
1398 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1400 if (ConfigInfo
.DisableTaggedQueueing
)
1401 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1403 /* Check if we need to alloc SRB data */
1404 if (DeviceExtension
->SupportsTaggedQueuing
||
1405 DeviceExtension
->MultipleReqsPerLun
)
1407 DeviceExtension
->NeedSrbDataAlloc
= TRUE
;
1411 DeviceExtension
->NeedSrbDataAlloc
= FALSE
;
1414 /* Get a pointer to the port capabilities */
1415 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1417 /* Copy one field there */
1418 DeviceExtension
->MapBuffers
= PortConfig
->MapBuffers
;
1419 PortCapabilities
->AdapterUsesPio
= PortConfig
->MapBuffers
;
1421 if (DeviceExtension
->AdapterObject
== NULL
&&
1422 (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
|| PortConfig
->Master
))
1424 DPRINT1("DMA is not supported yet\n");
1428 if (DeviceExtension
->SrbExtensionBuffer
== NULL
&&
1429 (DeviceExtension
->SrbExtensionSize
!= 0 ||
1430 PortConfig
->AutoRequestSense
))
1432 DeviceExtension
->SupportsAutoSense
= PortConfig
->AutoRequestSense
;
1433 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
1435 /* Allocate common buffer */
1436 Status
= SpiAllocateCommonBuffer(DeviceExtension
, 0);
1438 /* Check for failure */
1439 if (!NT_SUCCESS(Status
))
1443 /* Allocate SrbData, if needed */
1444 if (DeviceExtension
->NeedSrbDataAlloc
)
1447 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1449 if (DeviceExtension
->SrbDataCount
!= 0)
1450 Count
= DeviceExtension
->SrbDataCount
;
1452 Count
= DeviceExtension
->RequestsNumber
* 2;
1454 /* Allocate the data */
1455 SrbData
= ExAllocatePoolWithTag(NonPagedPool
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
), TAG_SCSIPORT
);
1456 if (SrbData
== NULL
)
1457 return STATUS_INSUFFICIENT_RESOURCES
;
1459 RtlZeroMemory(SrbData
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
));
1461 DeviceExtension
->SrbInfo
= SrbData
;
1462 DeviceExtension
->FreeSrbInfo
= SrbData
;
1463 DeviceExtension
->SrbDataCount
= Count
;
1465 /* Link it to the list */
1468 SrbData
->Requests
.Flink
= (PLIST_ENTRY
)(SrbData
+ 1);
1473 /* Mark the last entry of the list */
1475 SrbData
->Requests
.Flink
= NULL
;
1478 /* Initialize port capabilities */
1479 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1480 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1481 PortCapabilities
->MaximumTransferLength
= PortConfig
->MaximumTransferLength
;
1483 if (PortConfig
->ReceiveEvent
)
1484 PortCapabilities
->SupportedAsynchronousEvents
|= SRBEV_SCSI_ASYNC_NOTIFICATION
;
1486 PortCapabilities
->TaggedQueuing
= DeviceExtension
->SupportsTaggedQueuing
;
1487 PortCapabilities
->AdapterScansDown
= PortConfig
->AdapterScansDown
;
1489 if (PortConfig
->AlignmentMask
> PortDeviceObject
->AlignmentRequirement
)
1490 PortDeviceObject
->AlignmentRequirement
= PortConfig
->AlignmentMask
;
1492 PortCapabilities
->AlignmentMask
= PortDeviceObject
->AlignmentRequirement
;
1494 if (PortCapabilities
->MaximumPhysicalPages
== 0)
1496 PortCapabilities
->MaximumPhysicalPages
=
1497 BYTES_TO_PAGES(PortCapabilities
->MaximumTransferLength
);
1499 /* Apply miniport's limits */
1500 if (PortConfig
->NumberOfPhysicalBreaks
< PortCapabilities
->MaximumPhysicalPages
)
1502 PortCapabilities
->MaximumPhysicalPages
= PortConfig
->NumberOfPhysicalBreaks
;
1506 /* Deal with interrupts */
1507 if (DeviceExtension
->HwInterrupt
== NULL
||
1508 (PortConfig
->BusInterruptLevel
== 0 && PortConfig
->BusInterruptVector
== 0))
1511 DeviceExtension
->InterruptCount
= 0;
1513 DPRINT1("Interrupt Count: 0\n");
1517 /* This code path will ALWAYS crash so stop it now */
1522 BOOLEAN InterruptShareable
;
1523 KINTERRUPT_MODE InterruptMode
[2];
1524 ULONG InterruptVector
[2], i
, MappedIrq
[2];
1525 KIRQL Dirql
[2], MaxDirql
;
1526 KAFFINITY Affinity
[2];
1528 DeviceExtension
->InterruptLevel
[0] = PortConfig
->BusInterruptLevel
;
1529 DeviceExtension
->InterruptLevel
[1] = PortConfig
->BusInterruptLevel2
;
1531 InterruptVector
[0] = PortConfig
->BusInterruptVector
;
1532 InterruptVector
[1] = PortConfig
->BusInterruptVector2
;
1534 InterruptMode
[0] = PortConfig
->InterruptMode
;
1535 InterruptMode
[1] = PortConfig
->InterruptMode2
;
1537 DeviceExtension
->InterruptCount
= (PortConfig
->BusInterruptLevel2
!= 0 || PortConfig
->BusInterruptVector2
!= 0) ? 2 : 1;
1539 for (i
= 0; i
< DeviceExtension
->InterruptCount
; i
++)
1541 /* Register an interrupt handler for this device */
1542 MappedIrq
[i
] = HalGetInterruptVector(PortConfig
->AdapterInterfaceType
,
1543 PortConfig
->SystemIoBusNumber
,
1544 DeviceExtension
->InterruptLevel
[i
],
1550 if (DeviceExtension
->InterruptCount
== 1 || Dirql
[0] > Dirql
[1])
1551 MaxDirql
= Dirql
[0];
1553 MaxDirql
= Dirql
[1];
1555 for (i
= 0; i
< DeviceExtension
->InterruptCount
; i
++)
1557 /* Determing IRQ sharability as usual */
1558 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1559 InterruptMode
[i
] == LevelSensitive
)
1561 InterruptShareable
= TRUE
;
1565 InterruptShareable
= FALSE
;
1568 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
[i
],
1569 (PKSERVICE_ROUTINE
)ScsiPortIsr
,
1571 &DeviceExtension
->IrqLock
,
1580 if (!(NT_SUCCESS(Status
)))
1582 DPRINT1("Could not connect interrupt %d\n",
1583 InterruptVector
[i
]);
1584 DeviceExtension
->Interrupt
[i
] = NULL
;
1589 if (!NT_SUCCESS(Status
))
1593 /* Save IoAddress (from access ranges) */
1594 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1596 DeviceExtension
->IoAddress
=
1597 ((*(PortConfig
->AccessRanges
))[0]).RangeStart
.LowPart
;
1599 DPRINT("Io Address %x\n", DeviceExtension
->IoAddress
);
1602 /* Set flag that it's allowed to disconnect during this command */
1603 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
1605 /* Initialize counter of active requests (-1 means there are none) */
1606 DeviceExtension
->ActiveRequestCounter
= -1;
1608 /* Analyze what we have about DMA */
1609 if (DeviceExtension
->AdapterObject
!= NULL
&&
1610 PortConfig
->Master
&&
1611 PortConfig
->NeedPhysicalAddresses
)
1613 DeviceExtension
->MapRegisters
= TRUE
;
1617 DeviceExtension
->MapRegisters
= FALSE
;
1620 /* Call HwInitialize at DISPATCH_LEVEL */
1621 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1623 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
1624 DeviceExtension
->HwInitialize
,
1625 DeviceExtension
->MiniPortDeviceExtension
))
1627 DPRINT1("HwInitialize() failed!\n");
1628 KeLowerIrql(OldIrql
);
1629 Status
= STATUS_ADAPTER_HARDWARE_ERROR
;
1633 /* Check if a notification is needed */
1634 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
1636 /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1637 ScsiPortDpcForIsr(NULL
,
1638 DeviceExtension
->DeviceObject
,
1643 /* Lower irql back to what it was */
1644 KeLowerIrql(OldIrql
);
1646 /* Start our timer */
1647 IoStartTimer(PortDeviceObject
);
1649 /* Initialize bus scanning information */
1650 DeviceExtension
->BusesConfig
= ExAllocatePoolWithTag(PagedPool
,
1651 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1652 + sizeof(ULONG
), TAG_SCSIPORT
);
1654 if (!DeviceExtension
->BusesConfig
)
1656 DPRINT1("Out of resources!\n");
1657 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1662 RtlZeroMemory(DeviceExtension
->BusesConfig
,
1663 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1666 /* Store number of buses there */
1667 DeviceExtension
->BusesConfig
->NumberOfBuses
= (UCHAR
)DeviceExtension
->BusNum
;
1669 /* Scan the adapter for devices */
1670 SpiScanAdapter(DeviceExtension
);
1672 /* Build the registry device map */
1673 SpiBuildDeviceMap(DeviceExtension
,
1674 (PUNICODE_STRING
)Argument2
);
1676 /* Create the dos device link */
1677 swprintf(DosNameBuffer
,
1679 SystemConfig
->ScsiPortCount
);
1680 RtlInitUnicodeString(&DosDeviceName
, DosNameBuffer
);
1681 IoCreateSymbolicLink(&DosDeviceName
, &DeviceName
);
1683 /* Increase the port count */
1684 SystemConfig
->ScsiPortCount
++;
1685 FirstConfigCall
= FALSE
;
1687 /* Increase adapter number and bus number respectively */
1688 ConfigInfo
.AdapterNumber
++;
1691 ConfigInfo
.BusNumber
++;
1693 DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber
, MaxBus
);
1698 /* Clean up the mess */
1699 SpiCleanupAfterInit(DeviceExtension
);
1701 /* Close registry keys */
1702 if (ConfigInfo
.ServiceKey
!= NULL
)
1703 ZwClose(ConfigInfo
.ServiceKey
);
1705 if (ConfigInfo
.DeviceKey
!= NULL
)
1706 ZwClose(ConfigInfo
.DeviceKey
);
1708 if (ConfigInfo
.BusKey
!= NULL
)
1709 ZwClose(ConfigInfo
.BusKey
);
1711 if (ConfigInfo
.AccessRanges
!= NULL
)
1712 ExFreePool(ConfigInfo
.AccessRanges
);
1714 if (ConfigInfo
.Parameter
!= NULL
)
1715 ExFreePool(ConfigInfo
.Parameter
);
1717 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1718 Status
, DeviceFound
);
1720 return (DeviceFound
== FALSE
) ? Status
: STATUS_SUCCESS
;
1724 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1726 PSCSI_LUN_INFO LunInfo
;
1730 /* Check if we have something to clean up */
1731 if (DeviceExtension
== NULL
)
1734 /* Stop the timer */
1735 IoStopTimer(DeviceExtension
->DeviceObject
);
1737 /* Disconnect the interrupts */
1738 while (DeviceExtension
->InterruptCount
)
1740 if (DeviceExtension
->Interrupt
[--DeviceExtension
->InterruptCount
])
1741 IoDisconnectInterrupt(DeviceExtension
->Interrupt
[DeviceExtension
->InterruptCount
]);
1744 /* Delete ConfigInfo */
1745 if (DeviceExtension
->BusesConfig
)
1747 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
1749 if (!DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
])
1752 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
1756 /* Free current, but save pointer to the next one */
1757 Ptr
= LunInfo
->Next
;
1758 ExFreePool(LunInfo
);
1762 ExFreePool(DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]);
1765 ExFreePool(DeviceExtension
->BusesConfig
);
1768 /* Free PortConfig */
1769 if (DeviceExtension
->PortConfig
)
1770 ExFreePool(DeviceExtension
->PortConfig
);
1773 for(Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
1775 while (DeviceExtension
->LunExtensionList
[Lun
])
1777 Ptr
= DeviceExtension
->LunExtensionList
[Lun
];
1778 DeviceExtension
->LunExtensionList
[Lun
] = DeviceExtension
->LunExtensionList
[Lun
]->Next
;
1784 /* Free common buffer (if it exists) */
1785 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
&&
1786 DeviceExtension
->CommonBufferLength
!= 0)
1788 if (!DeviceExtension
->AdapterObject
)
1790 ExFreePool(DeviceExtension
->SrbExtensionBuffer
);
1794 HalFreeCommonBuffer(DeviceExtension
->AdapterObject
,
1795 DeviceExtension
->CommonBufferLength
,
1796 DeviceExtension
->PhysicalAddress
,
1797 DeviceExtension
->SrbExtensionBuffer
,
1803 if (DeviceExtension
->SrbInfo
!= NULL
)
1804 ExFreePool(DeviceExtension
->SrbInfo
);
1806 /* Unmap mapped addresses */
1807 while (DeviceExtension
->MappedAddressList
!= NULL
)
1809 MmUnmapIoSpace(DeviceExtension
->MappedAddressList
->MappedAddress
,
1810 DeviceExtension
->MappedAddressList
->NumberOfBytes
);
1812 Ptr
= DeviceExtension
->MappedAddressList
;
1813 DeviceExtension
->MappedAddressList
= DeviceExtension
->MappedAddressList
->NextMappedAddress
;
1818 /* Finally delete the device object */
1819 DPRINT("Deleting device %p\n", DeviceExtension
->DeviceObject
);
1820 IoDeleteDevice(DeviceExtension
->DeviceObject
);
1827 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
1828 IN PSCSI_REQUEST_BLOCK Srb
,
1829 IN PVOID LogicalAddress
,
1832 DPRINT1("ScsiPortIoMapTransfer()\n");
1840 ScsiPortLogError(IN PVOID HwDeviceExtension
,
1841 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
1848 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1850 DPRINT1("ScsiPortLogError() called\n");
1852 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1853 SCSI_PORT_DEVICE_EXTENSION
,
1854 MiniPortDeviceExtension
);
1857 DPRINT("ScsiPortLogError() done\n");
1864 ScsiPortMoveMemory(OUT PVOID Destination
,
1868 RtlMoveMemory(Destination
,
1878 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
1879 IN PVOID HwDeviceExtension
,
1882 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1885 DPRINT("ScsiPortNotification() called\n");
1887 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1888 SCSI_PORT_DEVICE_EXTENSION
,
1889 MiniPortDeviceExtension
);
1891 DPRINT("DeviceExtension %p\n", DeviceExtension
);
1893 va_start(ap
, HwDeviceExtension
);
1895 switch (NotificationType
)
1897 case RequestComplete
:
1899 PSCSI_REQUEST_BLOCK Srb
;
1900 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1902 Srb
= (PSCSI_REQUEST_BLOCK
) va_arg (ap
, PSCSI_REQUEST_BLOCK
);
1904 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb
);
1906 /* Make sure Srb is allright */
1907 ASSERT(Srb
->SrbStatus
!= SRB_STATUS_PENDING
);
1908 ASSERT(Srb
->Function
!= SRB_FUNCTION_EXECUTE_SCSI
|| Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
|| Srb
->ScsiStatus
== SCSISTAT_GOOD
);
1910 if (!(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
1912 /* It's been already completed */
1917 /* It's not active anymore */
1918 Srb
->SrbFlags
&= ~SRB_FLAGS_IS_ACTIVE
;
1920 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
1922 /* TODO: Treat it specially */
1927 /* Get the SRB data */
1928 SrbData
= SpiGetSrbData(DeviceExtension
,
1934 /* Make sure there are no CompletedRequests and there is a Srb */
1935 ASSERT(SrbData
->CompletedRequests
== NULL
&& SrbData
->Srb
!= NULL
);
1937 /* If it's a read/write request, make sure it has data inside it */
1938 if ((Srb
->SrbStatus
== SRB_STATUS_SUCCESS
) &&
1939 ((Srb
->Cdb
[0] == SCSIOP_READ
) || (Srb
->Cdb
[0] == SCSIOP_WRITE
)))
1941 ASSERT(Srb
->DataTransferLength
);
1944 SrbData
->CompletedRequests
= DeviceExtension
->InterruptData
.CompletedRequests
;
1945 DeviceExtension
->InterruptData
.CompletedRequests
= SrbData
;
1951 DPRINT("Notify: NextRequest\n");
1952 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1960 PSCSI_PORT_LUN_EXTENSION LunExtension
;
1962 PathId
= (UCHAR
) va_arg (ap
, int);
1963 TargetId
= (UCHAR
) va_arg (ap
, int);
1964 Lun
= (UCHAR
) va_arg (ap
, int);
1966 DPRINT("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1967 PathId
, TargetId
, Lun
);
1969 /* Mark it in the flags field */
1970 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1972 /* Get the LUN extension */
1973 LunExtension
= SpiGetLunExtension(DeviceExtension
,
1978 /* If returned LunExtension is NULL, break out */
1979 if (!LunExtension
) break;
1981 /* This request should not be processed if */
1982 if ((LunExtension
->ReadyLun
) ||
1983 (LunExtension
->SrbInfo
.Srb
))
1985 /* Nothing to do here */
1989 /* Add this LUN to the list */
1990 LunExtension
->ReadyLun
= DeviceExtension
->InterruptData
.ReadyLun
;
1991 DeviceExtension
->InterruptData
.ReadyLun
= LunExtension
;
1996 DPRINT("Notify: ResetDetected\n");
1997 /* Add RESET flags */
1998 DeviceExtension
->InterruptData
.Flags
|=
1999 SCSI_PORT_RESET
| SCSI_PORT_RESET_REPORTED
;
2002 case CallDisableInterrupts
:
2003 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
2006 case CallEnableInterrupts
:
2007 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
2010 case RequestTimerCall
:
2011 DPRINT("Notify: RequestTimerCall\n");
2012 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_TIMER_NEEDED
;
2013 DeviceExtension
->InterruptData
.HwScsiTimer
= (PHW_TIMER
)va_arg(ap
, PHW_TIMER
);
2014 DeviceExtension
->InterruptData
.MiniportTimerValue
= (ULONG
)va_arg(ap
, ULONG
);
2017 case BusChangeDetected
:
2018 DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
2022 DPRINT1 ("Unsupported notification from WMI: %lu\n", NotificationType
);
2028 /* Request a DPC after we're done with the interrupt */
2029 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NOTIFICATION_NEEDED
;
2036 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
2037 IN INTERFACE_TYPE BusType
,
2038 IN ULONG SystemIoBusNumber
,
2039 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
2040 IN ULONG NumberOfBytes
,
2041 IN BOOLEAN InIoSpace
)
2043 DPRINT("ScsiPortValidateRange()\n");
2048 /* INTERNAL FUNCTIONS ********************************************************/
2051 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
2052 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
2053 IN PPORT_CONFIGURATION_INFORMATION PortConfig
)
2055 PACCESS_RANGE AccessRange
;
2056 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData
;
2059 ULONG Interrupt
= 0;
2064 /* Loop through all entries */
2065 for (Index
= 0; Index
< ResourceDescriptor
->PartialResourceList
.Count
; Index
++)
2067 PartialData
= &ResourceDescriptor
->PartialResourceList
.PartialDescriptors
[Index
];
2069 switch (PartialData
->Type
)
2071 case CmResourceTypePort
:
2072 /* Copy access ranges */
2073 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
2075 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
2077 AccessRange
->RangeStart
= PartialData
->u
.Port
.Start
;
2078 AccessRange
->RangeLength
= PartialData
->u
.Port
.Length
;
2080 AccessRange
->RangeInMemory
= FALSE
;
2085 case CmResourceTypeMemory
:
2086 /* Copy access ranges */
2087 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
2089 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
2091 AccessRange
->RangeStart
= PartialData
->u
.Memory
.Start
;
2092 AccessRange
->RangeLength
= PartialData
->u
.Memory
.Length
;
2094 AccessRange
->RangeInMemory
= TRUE
;
2099 case CmResourceTypeInterrupt
:
2103 /* Copy interrupt data */
2104 PortConfig
->BusInterruptLevel
= PartialData
->u
.Interrupt
.Level
;
2105 PortConfig
->BusInterruptVector
= PartialData
->u
.Interrupt
.Vector
;
2107 /* Set interrupt mode accordingly to the resource */
2108 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
2110 PortConfig
->InterruptMode
= Latched
;
2112 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
2114 PortConfig
->InterruptMode
= LevelSensitive
;
2117 else if (Interrupt
== 1)
2119 /* Copy interrupt data */
2120 PortConfig
->BusInterruptLevel2
= PartialData
->u
.Interrupt
.Level
;
2121 PortConfig
->BusInterruptVector2
= PartialData
->u
.Interrupt
.Vector
;
2123 /* Set interrupt mode accordingly to the resource */
2124 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
2126 PortConfig
->InterruptMode2
= Latched
;
2128 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
2130 PortConfig
->InterruptMode2
= LevelSensitive
;
2137 case CmResourceTypeDma
:
2141 PortConfig
->DmaChannel
= PartialData
->u
.Dma
.Channel
;
2142 PortConfig
->DmaPort
= PartialData
->u
.Dma
.Port
;
2144 if (PartialData
->Flags
& CM_RESOURCE_DMA_8
)
2145 PortConfig
->DmaWidth
= Width8Bits
;
2146 else if ((PartialData
->Flags
& CM_RESOURCE_DMA_16
) ||
2147 (PartialData
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
2148 PortConfig
->DmaWidth
= Width16Bits
;
2149 else if (PartialData
->Flags
& CM_RESOURCE_DMA_32
)
2150 PortConfig
->DmaWidth
= Width32Bits
;
2154 PortConfig
->DmaChannel2
= PartialData
->u
.Dma
.Channel
;
2155 PortConfig
->DmaPort2
= PartialData
->u
.Dma
.Port
;
2157 if (PartialData
->Flags
& CM_RESOURCE_DMA_8
)
2158 PortConfig
->DmaWidth2
= Width8Bits
;
2159 else if ((PartialData
->Flags
& CM_RESOURCE_DMA_16
) ||
2160 (PartialData
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
2161 PortConfig
->DmaWidth2
= Width16Bits
;
2162 else if (PartialData
->Flags
& CM_RESOURCE_DMA_32
)
2163 PortConfig
->DmaWidth2
= Width32Bits
;
2170 static PCM_RESOURCE_LIST
2171 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2172 PPORT_CONFIGURATION_INFORMATION PortConfig
)
2174 PCONFIGURATION_INFORMATION ConfigInfo
;
2175 PCM_RESOURCE_LIST ResourceList
;
2176 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
2177 PACCESS_RANGE AccessRange
;
2178 ULONG ListLength
= 0, i
, FullSize
;
2179 ULONG Interrupt
, Dma
;
2181 /* Get current Atdisk usage from the system */
2182 ConfigInfo
= IoGetConfigurationInformation();
2184 if (PortConfig
->AtdiskPrimaryClaimed
)
2185 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
2187 if (PortConfig
->AtdiskSecondaryClaimed
)
2188 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
2190 /* Do we use DMA? */
2191 if (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
||
2192 PortConfig
->DmaPort
!= SP_UNINITIALIZED_VALUE
)
2196 if (PortConfig
->DmaChannel2
!= SP_UNINITIALIZED_VALUE
||
2197 PortConfig
->DmaPort2
!= SP_UNINITIALIZED_VALUE
)
2206 /* How many interrupts to we have? */
2207 Interrupt
= DeviceExtension
->InterruptCount
;
2208 ListLength
+= Interrupt
;
2210 /* How many access ranges do we use? */
2211 AccessRange
= &((*(PortConfig
->AccessRanges
))[0]);
2212 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2214 if (AccessRange
->RangeLength
!= 0)
2220 /* Allocate the resource list, since we know its size now */
2221 FullSize
= sizeof(CM_RESOURCE_LIST
) + (ListLength
- 1) *
2222 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
2224 ResourceList
= (PCM_RESOURCE_LIST
)ExAllocatePoolWithTag(PagedPool
, FullSize
, TAG_SCSIPORT
);
2230 RtlZeroMemory(ResourceList
, FullSize
);
2233 ResourceList
->Count
= 1;
2234 ResourceList
->List
[0].InterfaceType
= PortConfig
->AdapterInterfaceType
;
2235 ResourceList
->List
[0].BusNumber
= PortConfig
->SystemIoBusNumber
;
2236 ResourceList
->List
[0].PartialResourceList
.Count
= ListLength
;
2237 ResourceDescriptor
= ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
;
2239 /* Copy access ranges array over */
2240 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2242 AccessRange
= &((*(PortConfig
->AccessRanges
))[i
]);
2244 /* If the range is empty - skip it */
2245 if (AccessRange
->RangeLength
== 0)
2248 if (AccessRange
->RangeInMemory
)
2250 ResourceDescriptor
->Type
= CmResourceTypeMemory
;
2251 ResourceDescriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
;
2255 ResourceDescriptor
->Type
= CmResourceTypePort
;
2256 ResourceDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
2259 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2261 ResourceDescriptor
->u
.Memory
.Start
= AccessRange
->RangeStart
;
2262 ResourceDescriptor
->u
.Memory
.Length
= AccessRange
->RangeLength
;
2264 ResourceDescriptor
++;
2267 /* If we use interrupt(s), copy them */
2270 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2272 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2273 ((Interrupt
== 2) ? PortConfig
->InterruptMode2
: PortConfig
->InterruptMode
) == LevelSensitive
)
2275 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2276 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2280 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2281 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2284 ResourceDescriptor
->u
.Interrupt
.Level
= (Interrupt
== 2) ? PortConfig
->BusInterruptLevel2
: PortConfig
->BusInterruptLevel
;
2285 ResourceDescriptor
->u
.Interrupt
.Vector
= (Interrupt
== 2) ? PortConfig
->BusInterruptVector2
: PortConfig
->BusInterruptVector
;
2286 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2288 ResourceDescriptor
++;
2295 ResourceDescriptor
->Type
= CmResourceTypeDma
;
2296 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2297 ResourceDescriptor
->u
.Dma
.Channel
= (Dma
== 2) ? PortConfig
->DmaChannel2
: PortConfig
->DmaChannel
;
2298 ResourceDescriptor
->u
.Dma
.Port
= (Dma
== 2) ? PortConfig
->DmaPort2
: PortConfig
->DmaPort
;
2299 ResourceDescriptor
->Flags
= 0;
2301 if (((Dma
== 2) ? PortConfig
->DmaWidth2
: PortConfig
->DmaWidth
) == Width8Bits
)
2302 ResourceDescriptor
->Flags
|= CM_RESOURCE_DMA_8
;
2303 else if (((Dma
== 2) ? PortConfig
->DmaWidth2
: PortConfig
->DmaWidth
) == Width16Bits
)
2304 ResourceDescriptor
->Flags
|= CM_RESOURCE_DMA_16
;
2306 ResourceDescriptor
->Flags
|= CM_RESOURCE_DMA_32
;
2308 if (((Dma
== 2) ? PortConfig
->DmaChannel2
: PortConfig
->DmaChannel
) == SP_UNINITIALIZED_VALUE
)
2309 ResourceDescriptor
->u
.Dma
.Channel
= 0;
2311 if (((Dma
== 2) ? PortConfig
->DmaPort2
: PortConfig
->DmaPort
) == SP_UNINITIALIZED_VALUE
)
2312 ResourceDescriptor
->u
.Dma
.Port
= 0;
2314 ResourceDescriptor
++;
2318 return ResourceList
;
2323 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
2324 IN PDEVICE_OBJECT DeviceObject
,
2325 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
2326 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
2327 IN PUNICODE_STRING RegistryPath
,
2329 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
)
2331 PCI_COMMON_CONFIG PciConfig
;
2332 PCI_SLOT_NUMBER SlotNumber
;
2335 ULONG FunctionNumber
;
2336 CHAR VendorIdString
[8];
2337 CHAR DeviceIdString
[8];
2338 UNICODE_STRING UnicodeStr
;
2339 PCM_RESOURCE_LIST ResourceList
;
2342 DPRINT ("SpiGetPciConfiguration() called\n");
2344 RtlZeroMemory(&ResourceList
, sizeof(PCM_RESOURCE_LIST
));
2345 SlotNumber
.u
.AsULONG
= 0;
2347 /* Loop through all devices */
2348 for (DeviceNumber
= NextSlotNumber
->u
.bits
.DeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
2350 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
2352 /* Loop through all functions */
2353 for (FunctionNumber
= NextSlotNumber
->u
.bits
.FunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
2355 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
2357 /* Get PCI config bytes */
2358 DataSize
= HalGetBusData(PCIConfiguration
,
2360 SlotNumber
.u
.AsULONG
,
2364 /* If result of HalGetBusData is 0, then the bus is wrong */
2368 /* If result is PCI_INVALID_VENDORID, then this device has no more
2370 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
2373 sprintf (VendorIdString
, "%04hx", PciConfig
.VendorID
);
2374 sprintf (DeviceIdString
, "%04hx", PciConfig
.DeviceID
);
2376 if (_strnicmp(VendorIdString
, HwInitializationData
->VendorId
, HwInitializationData
->VendorIdLength
) ||
2377 _strnicmp(DeviceIdString
, HwInitializationData
->DeviceId
, HwInitializationData
->DeviceIdLength
))
2379 /* It is not our device */
2383 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2387 SlotNumber
.u
.bits
.DeviceNumber
,
2388 SlotNumber
.u
.bits
.FunctionNumber
);
2391 RtlInitUnicodeString(&UnicodeStr
, L
"ScsiAdapter");
2392 Status
= HalAssignSlotResources(RegistryPath
,
2398 SlotNumber
.u
.AsULONG
,
2401 if (!NT_SUCCESS(Status
))
2404 /* Create configuration information */
2405 SpiResourceToConfig(HwInitializationData
,
2409 /* Free the resource list */
2410 ExFreePool(ResourceList
);
2412 /* Set dev & fn numbers */
2413 NextSlotNumber
->u
.bits
.DeviceNumber
= DeviceNumber
;
2414 NextSlotNumber
->u
.bits
.FunctionNumber
= FunctionNumber
+ 1;
2416 /* Save the slot number */
2417 PortConfig
->SlotNumber
= SlotNumber
.u
.AsULONG
;
2421 NextSlotNumber
->u
.bits
.FunctionNumber
= 0;
2424 NextSlotNumber
->u
.bits
.DeviceNumber
= 0;
2425 DPRINT ("No device found\n");
2432 /**********************************************************************
2434 * ScsiPortCreateClose
2437 * Answer requests for Create/Close calls: a null operation.
2444 * Pointer to a device object.
2447 * Pointer to an IRP.
2453 static NTSTATUS NTAPI
2454 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
2457 DPRINT("ScsiPortCreateClose()\n");
2459 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2460 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2462 return STATUS_SUCCESS
;
2466 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2469 PSCSI_LUN_INFO LunInfo
;
2470 PIO_STACK_LOCATION IrpStack
;
2471 PDEVICE_OBJECT DeviceObject
;
2472 PSCSI_REQUEST_BLOCK Srb
;
2475 /* Get pointer to the SRB */
2476 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2477 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
2479 /* Check if PathId matches number of buses */
2480 if (DeviceExtension
->BusesConfig
== NULL
||
2481 DeviceExtension
->BusesConfig
->NumberOfBuses
<= Srb
->PathId
)
2483 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2484 return STATUS_DEVICE_DOES_NOT_EXIST
;
2487 /* Get pointer to LunInfo */
2488 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Srb
->PathId
]->LunInfo
;
2490 /* Find matching LunInfo */
2493 if (LunInfo
->PathId
== Srb
->PathId
&&
2494 LunInfo
->TargetId
== Srb
->TargetId
&&
2495 LunInfo
->Lun
== Srb
->Lun
)
2500 LunInfo
= LunInfo
->Next
;
2503 /* If we couldn't find it - exit */
2504 if (LunInfo
== NULL
)
2505 return STATUS_DEVICE_DOES_NOT_EXIST
;
2509 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2511 /* Release, if asked */
2512 if (Srb
->Function
== SRB_FUNCTION_RELEASE_DEVICE
)
2514 LunInfo
->DeviceClaimed
= FALSE
;
2515 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2516 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2518 return STATUS_SUCCESS
;
2521 /* Attach, if not already claimed */
2522 if (LunInfo
->DeviceClaimed
)
2524 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2525 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
2527 return STATUS_DEVICE_BUSY
;
2530 /* Save the device object */
2531 DeviceObject
= LunInfo
->DeviceObject
;
2533 if (Srb
->Function
== SRB_FUNCTION_CLAIM_DEVICE
)
2534 LunInfo
->DeviceClaimed
= TRUE
;
2536 if (Srb
->Function
== SRB_FUNCTION_ATTACH_DEVICE
)
2537 LunInfo
->DeviceObject
= Srb
->DataBuffer
;
2539 Srb
->DataBuffer
= DeviceObject
;
2541 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2542 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2544 return STATUS_SUCCESS
;
2548 /**********************************************************************
2550 * ScsiPortDispatchScsi
2553 * Answer requests for SCSI calls
2559 * Standard dispatch arguments
2565 static NTSTATUS NTAPI
2566 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
2569 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2570 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2571 PIO_STACK_LOCATION Stack
;
2572 PSCSI_REQUEST_BLOCK Srb
;
2574 NTSTATUS Status
= STATUS_SUCCESS
;
2575 PIRP NextIrp
, IrpList
;
2576 PKDEVICE_QUEUE_ENTRY Entry
;
2578 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2581 DeviceExtension
= DeviceObject
->DeviceExtension
;
2582 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2584 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2587 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2588 Status
= STATUS_UNSUCCESSFUL
;
2590 Irp
->IoStatus
.Status
= Status
;
2591 Irp
->IoStatus
.Information
= 0;
2593 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2598 DPRINT("Srb: %p\n", Srb
);
2599 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
2600 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
2602 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2606 if (LunExtension
== NULL
)
2608 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2609 Status
= STATUS_NO_SUCH_DEVICE
;
2611 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2612 Irp
->IoStatus
.Status
= Status
;
2613 Irp
->IoStatus
.Information
= 0;
2615 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2620 switch (Srb
->Function
)
2622 case SRB_FUNCTION_SHUTDOWN
:
2623 case SRB_FUNCTION_FLUSH
:
2624 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2625 if (DeviceExtension
->CachesData
== FALSE
)
2627 /* All success here */
2628 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2629 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2630 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2631 return STATUS_SUCCESS
;
2633 /* Fall through to a usual execute operation */
2635 case SRB_FUNCTION_EXECUTE_SCSI
:
2636 case SRB_FUNCTION_IO_CONTROL
:
2637 /* Mark IRP as pending in all cases */
2638 IoMarkIrpPending(Irp
);
2640 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2642 /* Start IO directly */
2643 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2649 /* We need to be at DISPATCH_LEVEL */
2650 KeRaiseIrql (DISPATCH_LEVEL
, &oldIrql
);
2652 /* Insert IRP into the queue */
2653 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
2654 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
2657 /* It means the queue is empty, and we just start this request */
2658 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2661 /* Back to the old IRQL */
2662 KeLowerIrql (oldIrql
);
2664 return STATUS_PENDING
;
2666 case SRB_FUNCTION_CLAIM_DEVICE
:
2667 case SRB_FUNCTION_ATTACH_DEVICE
:
2668 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2670 /* Reference device object and keep the device object */
2671 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2674 case SRB_FUNCTION_RELEASE_DEVICE
:
2675 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2677 /* Dereference device object and clear the device object */
2678 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2681 case SRB_FUNCTION_RELEASE_QUEUE
:
2682 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2684 /* Guard with the spinlock */
2685 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2687 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2689 DPRINT("Queue is not frozen really\n");
2691 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2692 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2693 Status
= STATUS_SUCCESS
;
2698 /* Unfreeze the queue */
2699 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2701 if (LunExtension
->SrbInfo
.Srb
== NULL
)
2703 /* Get next logical unit request */
2704 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
2706 /* SpiGetNextRequestFromLun() releases the spinlock */
2711 DPRINT("The queue has active request\n");
2712 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2716 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2717 Status
= STATUS_SUCCESS
;
2720 case SRB_FUNCTION_FLUSH_QUEUE
:
2721 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2723 /* Guard with the spinlock */
2724 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2726 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2728 DPRINT("Queue is not frozen really\n");
2730 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2731 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2735 /* Make sure there is no active request */
2736 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
2738 /* Compile a list from the device queue */
2740 while ((Entry
= KeRemoveDeviceQueue(&LunExtension
->DeviceQueue
)) != NULL
)
2742 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
2745 Stack
= IoGetCurrentIrpStackLocation(NextIrp
);
2746 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2749 Srb
->SrbStatus
= SRB_STATUS_REQUEST_FLUSHED
;
2750 NextIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2752 /* Add then to the list */
2753 NextIrp
->Tail
.Overlay
.ListEntry
.Flink
= (PLIST_ENTRY
)IrpList
;
2757 /* Unfreeze the queue */
2758 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2760 /* Release the spinlock */
2761 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2763 /* Complete those requests */
2767 IrpList
= (PIRP
)NextIrp
->Tail
.Overlay
.ListEntry
.Flink
;
2769 IoCompleteRequest(NextIrp
, 0);
2772 Status
= STATUS_SUCCESS
;
2776 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
2777 Status
= STATUS_NOT_IMPLEMENTED
;
2781 Irp
->IoStatus
.Status
= Status
;
2783 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2789 /**********************************************************************
2791 * ScsiPortDeviceControl
2794 * Answer requests for device control calls
2800 * Standard dispatch arguments
2806 static NTSTATUS NTAPI
2807 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
2810 PIO_STACK_LOCATION Stack
;
2811 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2812 PDUMP_POINTERS DumpPointers
;
2815 DPRINT("ScsiPortDeviceControl()\n");
2817 Irp
->IoStatus
.Information
= 0;
2819 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2820 DeviceExtension
= DeviceObject
->DeviceExtension
;
2822 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
2824 case IOCTL_SCSI_GET_DUMP_POINTERS
:
2825 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2827 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DUMP_POINTERS
))
2829 Status
= STATUS_BUFFER_OVERFLOW
;
2830 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2834 DumpPointers
= Irp
->AssociatedIrp
.SystemBuffer
;
2835 DumpPointers
->DeviceObject
= DeviceObject
;
2838 Status
= STATUS_SUCCESS
;
2839 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2842 case IOCTL_SCSI_GET_CAPABILITIES
:
2843 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2844 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
== sizeof(PVOID
))
2846 *((PVOID
*)Irp
->AssociatedIrp
.SystemBuffer
) = &DeviceExtension
->PortCapabilities
;
2848 Irp
->IoStatus
.Information
= sizeof(PVOID
);
2849 Status
= STATUS_SUCCESS
;
2853 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(IO_SCSI_CAPABILITIES
))
2855 Status
= STATUS_BUFFER_TOO_SMALL
;
2859 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2860 &DeviceExtension
->PortCapabilities
,
2861 sizeof(IO_SCSI_CAPABILITIES
));
2863 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
2864 Status
= STATUS_SUCCESS
;
2867 case IOCTL_SCSI_GET_INQUIRY_DATA
:
2868 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2870 /* Copy inquiry data to the port device extension */
2871 Status
= SpiGetInquiryData(DeviceExtension
, Irp
);
2874 case IOCTL_SCSI_MINIPORT
:
2875 DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
2876 Status
= STATUS_NOT_IMPLEMENTED
;
2879 case IOCTL_SCSI_PASS_THROUGH
:
2880 DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
2881 Status
= STATUS_NOT_IMPLEMENTED
;
2885 DPRINT1(" unknown ioctl code: 0x%lX\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2886 Status
= STATUS_NOT_IMPLEMENTED
;
2890 /* Complete the request with the given status */
2891 Irp
->IoStatus
.Status
= Status
;
2892 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2899 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
2902 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2903 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2904 PIO_STACK_LOCATION IrpStack
;
2905 PSCSI_REQUEST_BLOCK Srb
;
2906 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2910 DPRINT("ScsiPortStartIo() called!\n");
2912 DeviceExtension
= DeviceObject
->DeviceExtension
;
2913 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2915 DPRINT("DeviceExtension %p\n", DeviceExtension
);
2917 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2919 /* Apply "default" flags */
2920 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
2922 /* Get LUN extension */
2923 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2928 if (DeviceExtension
->NeedSrbDataAlloc
||
2929 DeviceExtension
->NeedSrbExtensionAlloc
)
2932 SrbInfo
= SpiAllocateSrbStructures(DeviceExtension
,
2936 /* Couldn't alloc one or both data structures, return */
2937 if (SrbInfo
== NULL
)
2939 /* We have to call IoStartNextPacket, because this request
2941 if (LunExtension
->Flags
& LUNEX_REQUEST_PENDING
)
2942 IoStartNextPacket(DeviceObject
, FALSE
);
2949 /* No allocations are needed */
2950 SrbInfo
= &LunExtension
->SrbInfo
;
2951 Srb
->SrbExtension
= NULL
;
2952 Srb
->QueueTag
= SP_UNTAGGED
;
2955 /* Increase sequence number of SRB */
2956 if (!SrbInfo
->SequenceNumber
)
2958 /* Increase global sequence number */
2959 DeviceExtension
->SequenceNumber
++;
2962 SrbInfo
->SequenceNumber
= DeviceExtension
->SequenceNumber
;
2965 /* Check some special SRBs */
2966 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2968 /* Some special handling */
2969 DPRINT1("Abort command! Unimplemented now\n");
2976 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
)
2978 // Store the MDL virtual address in SrbInfo structure
2979 SrbInfo
->DataOffset
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2981 if (DeviceExtension
->MapBuffers
)
2983 /* Calculate offset within DataBuffer */
2984 SrbInfo
->DataOffset
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
2985 Srb
->DataBuffer
= SrbInfo
->DataOffset
+
2986 (ULONG
)((PUCHAR
)Srb
->DataBuffer
-
2987 (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2990 if (DeviceExtension
->AdapterObject
)
2993 KeFlushIoBuffers(Irp
->MdlAddress
,
2994 Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? TRUE
: FALSE
,
2998 if (DeviceExtension
->MapRegisters
)
3000 /* Calculate number of needed map registers */
3001 SrbInfo
->NumberOfMapRegisters
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
3003 Srb
->DataTransferLength
);
3005 /* Allocate adapter channel */
3006 Status
= IoAllocateAdapterChannel(DeviceExtension
->AdapterObject
,
3007 DeviceExtension
->DeviceObject
,
3008 SrbInfo
->NumberOfMapRegisters
,
3012 if (!NT_SUCCESS(Status
))
3014 DPRINT1("IoAllocateAdapterChannel() failed!\n");
3016 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
3017 ScsiPortNotification(RequestComplete
,
3018 DeviceExtension
+ 1,
3021 ScsiPortNotification(NextRequest
,
3022 DeviceExtension
+ 1);
3024 /* Request DPC for that work */
3025 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3028 /* Control goes to SpiAdapterControl */
3033 /* Increase active request counter */
3034 CounterResult
= InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
3036 if (CounterResult
== 0 &&
3037 DeviceExtension
->AdapterObject
!= NULL
&&
3038 !DeviceExtension
->MapRegisters
)
3040 IoAllocateAdapterChannel(
3041 DeviceExtension
->AdapterObject
,
3043 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
,
3044 ScsiPortAllocateAdapterChannel
,
3051 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3053 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
3054 ScsiPortStartPacket
,
3057 DPRINT("Synchronization failed!\n");
3059 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3060 Irp
->IoStatus
.Information
= 0;
3061 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3063 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3067 /* Release the spinlock only */
3068 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3072 DPRINT("ScsiPortStartIo() done\n");
3076 static BOOLEAN NTAPI
3077 ScsiPortStartPacket(IN OUT PVOID Context
)
3079 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3080 PIO_STACK_LOCATION IrpStack
;
3081 PSCSI_REQUEST_BLOCK Srb
;
3082 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)Context
;
3083 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3084 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3088 DPRINT("ScsiPortStartPacket() called\n");
3090 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3092 IrpStack
= IoGetCurrentIrpStackLocation(DeviceObject
->CurrentIrp
);
3093 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
3095 /* Get LUN extension */
3096 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3101 /* Check if we are in a reset state */
3102 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
3104 /* Mark the we've got requests while being in the reset state */
3105 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET_REQUEST
;
3109 /* Set the time out value */
3110 DeviceExtension
->TimerCount
= Srb
->TimeOutValue
;
3113 DeviceExtension
->Flags
|= SCSI_PORT_DEVICE_BUSY
;
3115 if (LunExtension
->RequestTimeout
!= -1)
3117 /* Timer already active */
3122 /* It hasn't been initialized yet */
3123 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
3127 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
3129 /* Handle bypass-requests */
3131 /* Is this an abort request? */
3132 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
3134 /* Get pointer to SRB info structure */
3135 SrbInfo
= SpiGetSrbData(DeviceExtension
,
3141 /* Check if the request is still "active" */
3142 if (SrbInfo
== NULL
||
3143 SrbInfo
->Srb
== NULL
||
3144 !(SrbInfo
->Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
3146 /* It's not, mark it as active then */
3147 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
3150 LunExtension
->RequestTimeout
= -1;
3152 DPRINT("Request has been already completed, but abort request came\n");
3153 Srb
->SrbStatus
= SRB_STATUS_ABORT_FAILED
;
3155 /* Notify about request complete */
3156 ScsiPortNotification(RequestComplete
,
3157 DeviceExtension
->MiniPortDeviceExtension
,
3160 /* and about readiness for the next request */
3161 ScsiPortNotification(NextRequest
,
3162 DeviceExtension
->MiniPortDeviceExtension
);
3164 /* They might ask for some work, so queue the DPC for them */
3165 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3167 /* We're done in this branch */
3173 /* Add number of queued requests */
3174 LunExtension
->QueueCount
++;
3177 /* Bypass requests don't need request sense */
3178 LunExtension
->Flags
&= ~LUNEX_NEED_REQUEST_SENSE
;
3180 /* Is disconnect disabled for this request? */
3181 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3183 /* Set the corresponding flag */
3184 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3187 /* Transfer timeout value from Srb to Lun */
3188 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
3192 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3194 /* It's a disconnect, so no more requests can go */
3195 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3198 LunExtension
->Flags
|= SCSI_PORT_LU_ACTIVE
;
3200 /* Increment queue count */
3201 LunExtension
->QueueCount
++;
3203 /* If it's tagged - special thing */
3204 if (Srb
->QueueTag
!= SP_UNTAGGED
)
3206 SrbInfo
= &DeviceExtension
->SrbInfo
[Srb
->QueueTag
- 1];
3208 /* Chek for consistency */
3209 ASSERT(SrbInfo
->Requests
.Blink
== NULL
);
3211 /* Insert it into the list of requests */
3212 InsertTailList(&LunExtension
->SrbInfo
.Requests
, &SrbInfo
->Requests
);
3216 /* Mark this Srb active */
3217 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
3219 /* Call HwStartIo routine */
3220 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
3223 /* If notification is needed, then request a DPC */
3224 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
3225 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3230 IO_ALLOCATION_ACTION
3232 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
,
3234 PVOID MapRegisterBase
,
3237 PSCSI_REQUEST_BLOCK Srb
;
3238 PSCSI_SG_ADDRESS ScatterGatherList
;
3240 PIO_STACK_LOCATION IrpStack
;
3241 ULONG TotalLength
= 0;
3242 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3243 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3245 BOOLEAN WriteToDevice
;
3247 /* Get pointers to SrbInfo and DeviceExtension */
3248 SrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)Context
;
3249 DeviceExtension
= DeviceObject
->DeviceExtension
;
3251 /* Get pointer to SRB */
3252 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3253 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
3255 /* Depending on the map registers number, we allocate
3256 either from NonPagedPool, or from our static list */
3257 if (SrbInfo
->NumberOfMapRegisters
> MAX_SG_LIST
)
3259 SrbInfo
->ScatterGather
= ExAllocatePoolWithTag(
3260 NonPagedPool
, SrbInfo
->NumberOfMapRegisters
* sizeof(SCSI_SG_ADDRESS
), TAG_SCSIPORT
);
3262 if (SrbInfo
->ScatterGather
== NULL
)
3265 Srb
->SrbFlags
|= SRB_FLAGS_SGLIST_FROM_POOL
;
3269 SrbInfo
->ScatterGather
= SrbInfo
->ScatterGatherList
;
3272 /* Use chosen SG list source */
3273 ScatterGatherList
= SrbInfo
->ScatterGather
;
3275 /* Save map registers base */
3276 SrbInfo
->BaseOfMapRegister
= MapRegisterBase
;
3278 /* Determine WriteToDevice flag */
3279 WriteToDevice
= Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
? TRUE
: FALSE
;
3281 /* Get virtual address of the data buffer */
3282 DataVA
= (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
3283 ((PCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
3285 /* Build the actual SG list */
3286 while (TotalLength
< Srb
->DataTransferLength
)
3288 if (!ScatterGatherList
)
3291 ScatterGatherList
->Length
= Srb
->DataTransferLength
- TotalLength
;
3292 ScatterGatherList
->PhysicalAddress
= IoMapTransfer(NULL
,
3295 DataVA
+ TotalLength
,
3296 &ScatterGatherList
->Length
,
3299 TotalLength
+= ScatterGatherList
->Length
;
3300 ScatterGatherList
++;
3303 /* Schedule an active request */
3304 InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
3305 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &CurrentIrql
);
3306 KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
3307 ScsiPortStartPacket
,
3309 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, CurrentIrql
);
3311 return DeallocateObjectKeepRegisters
;
3314 static PSCSI_PORT_LUN_EXTENSION
3315 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3317 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3318 ULONG LunExtensionSize
;
3320 DPRINT("SpiAllocateLunExtension (%p)\n",
3323 /* Round LunExtensionSize first to the sizeof LONGLONG */
3324 LunExtensionSize
= (DeviceExtension
->LunExtensionSize
+
3325 sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
3327 LunExtensionSize
+= sizeof(SCSI_PORT_LUN_EXTENSION
);
3328 DPRINT("LunExtensionSize %lu\n", LunExtensionSize
);
3330 LunExtension
= ExAllocatePoolWithTag(NonPagedPool
, LunExtensionSize
, TAG_SCSIPORT
);
3331 if (LunExtension
== NULL
)
3333 DPRINT1("Out of resources!\n");
3337 /* Zero everything */
3338 RtlZeroMemory(LunExtension
, LunExtensionSize
);
3340 /* Initialize a list of requests */
3341 InitializeListHead(&LunExtension
->SrbInfo
.Requests
);
3343 /* Initialize timeout counter */
3344 LunExtension
->RequestTimeout
= -1;
3346 /* Set maximum queue size */
3347 LunExtension
->MaxQueueCount
= 256;
3349 /* Initialize request queue */
3350 KeInitializeDeviceQueue (&LunExtension
->DeviceQueue
);
3352 return LunExtension
;
3355 static PSCSI_PORT_LUN_EXTENSION
3356 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3361 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3363 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3364 DeviceExtension
, PathId
, TargetId
, Lun
);
3366 /* Get appropriate list */
3367 LunExtension
= DeviceExtension
->LunExtensionList
[(TargetId
+ Lun
) % LUS_NUMBER
];
3369 /* Iterate it until we find what we need */
3370 while (LunExtension
)
3372 if (LunExtension
->TargetId
== TargetId
&&
3373 LunExtension
->Lun
== Lun
&&
3374 LunExtension
->PathId
== PathId
)
3376 /* All matches, return */
3377 return LunExtension
;
3380 /* Advance to the next item */
3381 LunExtension
= LunExtension
->Next
;
3384 /* We did not find anything */
3385 DPRINT("Nothing found\n");
3389 static PSCSI_REQUEST_BLOCK_INFO
3390 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3391 PSCSI_PORT_LUN_EXTENSION LunExtension
,
3392 PSCSI_REQUEST_BLOCK Srb
)
3395 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3397 /* Spinlock must be held while this function executes */
3398 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3400 /* Allocate SRB data structure */
3401 if (DeviceExtension
->NeedSrbDataAlloc
)
3403 /* Treat the abort request in a special way */
3404 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
3406 SrbInfo
= SpiGetSrbData(DeviceExtension
,
3412 else if (Srb
->SrbFlags
&
3413 (SRB_FLAGS_QUEUE_ACTION_ENABLE
| SRB_FLAGS_NO_QUEUE_FREEZE
) &&
3414 !(Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3417 /* Do not process tagged commands if need request sense is set */
3418 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
3420 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3422 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3423 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3425 /* Relese the spinlock and return */
3426 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3430 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
3431 SrbInfo
= DeviceExtension
->FreeSrbInfo
;
3433 if (SrbInfo
== NULL
)
3435 /* No SRB structures left in the list. We have to leave
3436 and wait while we are called again */
3438 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3439 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3443 DeviceExtension
->FreeSrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)SrbInfo
->Requests
.Flink
;
3445 /* QueueTag must never be 0, so +1 to it */
3446 Srb
->QueueTag
= (UCHAR
)(SrbInfo
- DeviceExtension
->SrbInfo
) + 1;
3450 /* Usual untagged command */
3452 (!IsListEmpty(&LunExtension
->SrbInfo
.Requests
) ||
3453 LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
) &&
3454 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
3457 /* Mark it as pending and leave */
3458 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3459 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3460 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3462 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3466 Srb
->QueueTag
= SP_UNTAGGED
;
3467 SrbInfo
= &LunExtension
->SrbInfo
;
3472 Srb
->QueueTag
= SP_UNTAGGED
;
3473 SrbInfo
= &LunExtension
->SrbInfo
;
3476 /* Allocate SRB extension structure */
3477 if (DeviceExtension
->NeedSrbExtensionAlloc
)
3479 /* Check the list of free extensions */
3480 SrbExtension
= DeviceExtension
->FreeSrbExtensions
;
3482 /* If no free extensions... */
3483 if (SrbExtension
== NULL
)
3486 if (Srb
->Function
!= SRB_FUNCTION_ABORT_COMMAND
&&
3487 Srb
->QueueTag
!= SP_UNTAGGED
)
3489 SrbInfo
->Requests
.Blink
= NULL
;
3490 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
3491 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
3494 /* Return, in order to be called again later */
3495 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3496 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3500 /* Remove that free SRB extension from the list (since
3501 we're going to use it) */
3502 DeviceExtension
->FreeSrbExtensions
= *((PVOID
*)SrbExtension
);
3504 /* Spinlock can be released now */
3505 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3507 Srb
->SrbExtension
= SrbExtension
;
3509 if (Srb
->SenseInfoBuffer
!= NULL
&&
3510 DeviceExtension
->SupportsAutoSense
)
3512 /* Store pointer to the SenseInfo buffer */
3513 SrbInfo
->SaveSenseRequest
= Srb
->SenseInfoBuffer
;
3515 /* Does data fit the buffer? */
3516 if (Srb
->SenseInfoBufferLength
> sizeof(SENSE_DATA
))
3518 /* No, disabling autosense at all */
3519 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_AUTOSENSE
;
3523 /* Yes, update the buffer pointer */
3524 Srb
->SenseInfoBuffer
= SrbExtension
+ DeviceExtension
->SrbExtensionSize
;
3531 Srb
->SrbExtension
= NULL
;
3532 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3540 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
3541 IN PSCSI_LUN_INFO LunInfo
)
3543 IO_STATUS_BLOCK IoStatusBlock
;
3544 PIO_STACK_LOCATION IrpStack
;
3549 PINQUIRYDATA InquiryBuffer
;
3550 PSENSE_DATA SenseBuffer
;
3551 BOOLEAN KeepTrying
= TRUE
;
3552 ULONG RetryCount
= 0;
3553 SCSI_REQUEST_BLOCK Srb
;
3555 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3556 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3558 DPRINT ("SpiSendInquiry() called\n");
3560 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3562 InquiryBuffer
= ExAllocatePoolWithTag (NonPagedPool
, INQUIRYDATABUFFERSIZE
, TAG_SCSIPORT
);
3563 if (InquiryBuffer
== NULL
)
3564 return STATUS_INSUFFICIENT_RESOURCES
;
3566 SenseBuffer
= ExAllocatePoolWithTag (NonPagedPool
, SENSE_BUFFER_SIZE
, TAG_SCSIPORT
);
3567 if (SenseBuffer
== NULL
)
3569 ExFreePool(InquiryBuffer
);
3570 return STATUS_INSUFFICIENT_RESOURCES
;
3575 /* Initialize event for waiting */
3576 KeInitializeEvent(&Event
,
3581 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN
,
3586 INQUIRYDATABUFFERSIZE
,
3592 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3593 return STATUS_INSUFFICIENT_RESOURCES
;
3597 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3599 Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
3600 Srb
.OriginalRequest
= Irp
;
3601 Srb
.PathId
= LunInfo
->PathId
;
3602 Srb
.TargetId
= LunInfo
->TargetId
;
3603 Srb
.Lun
= LunInfo
->Lun
;
3604 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3605 Srb
.SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3606 Srb
.TimeOutValue
= 4;
3609 Srb
.SenseInfoBuffer
= SenseBuffer
;
3610 Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3612 Srb
.DataBuffer
= InquiryBuffer
;
3613 Srb
.DataTransferLength
= INQUIRYDATABUFFERSIZE
;
3615 /* Attach Srb to the Irp */
3616 IrpStack
= IoGetNextIrpStackLocation (Irp
);
3617 IrpStack
->Parameters
.Scsi
.Srb
= &Srb
;
3620 Cdb
= (PCDB
)Srb
.Cdb
;
3621 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_INQUIRY
;
3622 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= LunInfo
->Lun
;
3623 Cdb
->CDB6INQUIRY
.AllocationLength
= INQUIRYDATABUFFERSIZE
;
3625 /* Call the driver */
3626 Status
= IoCallDriver(DeviceObject
, Irp
);
3628 /* Wait for it to complete */
3629 if (Status
== STATUS_PENDING
)
3631 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3632 KeWaitForSingleObject(&Event
,
3637 Status
= IoStatusBlock
.Status
;
3640 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status
);
3642 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_SUCCESS
)
3644 /* All fine, copy data over */
3645 RtlCopyMemory(LunInfo
->InquiryData
,
3647 INQUIRYDATABUFFERSIZE
);
3649 Status
= STATUS_SUCCESS
;
3654 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb
.SrbStatus
);
3655 /* Check if the queue is frozen */
3656 if (Srb
.SrbStatus
& SRB_STATUS_QUEUE_FROZEN
)
3658 /* Something weird happened, deal with it (unfreeze the queue) */
3661 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb
.TargetId
);
3663 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3668 /* Clear frozen flag */
3669 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
3671 /* Acquire the spinlock */
3672 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
3674 /* Process the request */
3675 SpiGetNextRequestFromLun(DeviceObject
->DeviceExtension
, LunExtension
);
3677 /* SpiGetNextRequestFromLun() releases the spinlock,
3678 so we just lower irql back to what it was before */
3682 /* Check if data overrun happened */
3683 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
3685 DPRINT("Data overrun at TargetId %d\n", LunInfo
->TargetId
);
3686 /* Nothing dramatic, just copy data, but limiting the size */
3687 RtlCopyMemory(LunInfo
->InquiryData
,
3689 (Srb
.DataTransferLength
> INQUIRYDATABUFFERSIZE
) ?
3690 INQUIRYDATABUFFERSIZE
: Srb
.DataTransferLength
);
3692 Status
= STATUS_SUCCESS
;
3695 else if ((Srb
.SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3696 SenseBuffer
->SenseKey
== SCSI_SENSE_ILLEGAL_REQUEST
)
3698 /* LUN is not valid, but some device responds there.
3699 Mark it as invalid anyway */
3701 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3706 /* Retry a couple of times if no timeout happened */
3707 if ((RetryCount
< 2) &&
3708 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_NO_DEVICE
) &&
3709 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_SELECTION_TIMEOUT
))
3716 /* That's all, go to exit */
3719 /* Set status according to SRB status */
3720 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_FUNCTION
||
3721 SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH
)
3723 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3727 Status
= STATUS_IO_DEVICE_ERROR
;
3735 ExFreePool(InquiryBuffer
);
3736 ExFreePool(SenseBuffer
);
3738 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status
);
3744 /* Scans all SCSI buses */
3746 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3748 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3752 PSCSI_BUS_SCAN_INFO BusScanInfo
;
3753 PSCSI_LUN_INFO LastLunInfo
, LunInfo
, LunInfoExists
;
3754 BOOLEAN DeviceExists
;
3759 DPRINT("SpiScanAdapter() called\n");
3761 /* Scan all buses */
3762 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
3764 DPRINT(" Scanning bus %d\n", Bus
);
3767 /* Get pointer to the scan information */
3768 BusScanInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
];
3772 /* Find the last LUN info in the list */
3773 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3774 LastLunInfo
= LunInfo
;
3776 while (LunInfo
!= NULL
)
3778 LastLunInfo
= LunInfo
;
3779 LunInfo
= LunInfo
->Next
;
3784 /* We need to allocate this buffer */
3785 BusScanInfo
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_BUS_SCAN_INFO
), TAG_SCSIPORT
);
3789 DPRINT1("Out of resources!\n");
3793 /* Store the pointer in the BusScanInfo array */
3794 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
] = BusScanInfo
;
3796 /* Fill this struct (length and bus ids for now) */
3797 BusScanInfo
->Length
= sizeof(SCSI_BUS_SCAN_INFO
);
3798 BusScanInfo
->LogicalUnitsCount
= 0;
3799 BusScanInfo
->BusIdentifier
= DeviceExtension
->PortConfig
->InitiatorBusId
[Bus
];
3800 BusScanInfo
->LunInfo
= NULL
;
3802 /* Set pointer to the last LUN info to NULL */
3806 /* Create LUN information structure */
3807 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3809 if (LunInfo
== NULL
)
3811 DPRINT1("Out of resources!\n");
3815 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3817 /* Create LunExtension */
3818 LunExtension
= SpiAllocateLunExtension (DeviceExtension
);
3820 /* And send INQUIRY to every target */
3821 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
3823 /* TODO: Support scan bottom-up */
3825 /* Skip if it's the same address */
3826 if (Target
== BusScanInfo
->BusIdentifier
)
3829 /* Try to find an existing device here */
3830 DeviceExists
= FALSE
;
3831 LunInfoExists
= BusScanInfo
->LunInfo
;
3833 /* Find matching address on this bus */
3834 while (LunInfoExists
)
3836 if (LunInfoExists
->TargetId
== Target
)
3838 DeviceExists
= TRUE
;
3842 /* Advance to the next one */
3843 LunInfoExists
= LunInfoExists
->Next
;
3846 /* No need to bother rescanning, since we already did that before */
3850 /* Scan all logical units */
3851 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
3853 if ((!LunExtension
) || (!LunInfo
))
3856 /* Add extension to the list */
3857 Hint
= (Target
+ Lun
) % LUS_NUMBER
;
3858 LunExtension
->Next
= DeviceExtension
->LunExtensionList
[Hint
];
3859 DeviceExtension
->LunExtensionList
[Hint
] = LunExtension
;
3861 /* Fill Path, Target, Lun fields */
3862 LunExtension
->PathId
= LunInfo
->PathId
= (UCHAR
)Bus
;
3863 LunExtension
->TargetId
= LunInfo
->TargetId
= (UCHAR
) Target
;
3864 LunExtension
->Lun
= LunInfo
->Lun
= (UCHAR
)Lun
;
3866 /* Set flag to prevent race conditions */
3867 LunExtension
->Flags
|= SCSI_PORT_SCAN_IN_PROGRESS
;
3869 /* Zero LU extension contents */
3870 if (DeviceExtension
->LunExtensionSize
)
3872 RtlZeroMemory(LunExtension
+ 1,
3873 DeviceExtension
->LunExtensionSize
);
3876 /* Finally send the inquiry command */
3877 Status
= SpiSendInquiry(DeviceExtension
->DeviceObject
, LunInfo
);
3879 if (NT_SUCCESS(Status
))
3881 /* Let's see if we really found a device */
3882 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3884 /* Check if this device is unsupported */
3885 if (InquiryData
->DeviceTypeQualifier
== DEVICE_QUALIFIER_NOT_SUPPORTED
)
3887 DeviceExtension
->LunExtensionList
[Hint
] =
3888 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3893 /* Clear the "in scan" flag */
3894 LunExtension
->Flags
&= ~SCSI_PORT_SCAN_IN_PROGRESS
;
3896 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3897 InquiryData
->DeviceType
, Bus
, Target
, Lun
);
3899 /* Add this info to the linked list */
3900 LunInfo
->Next
= NULL
;
3902 LastLunInfo
->Next
= LunInfo
;
3904 BusScanInfo
->LunInfo
= LunInfo
;
3906 /* Store the last LUN info */
3907 LastLunInfo
= LunInfo
;
3909 /* Store DeviceObject */
3910 LunInfo
->DeviceObject
= DeviceExtension
->DeviceObject
;
3912 /* Allocate another buffer */
3913 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3917 DPRINT1("Out of resources!\n");
3921 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3923 /* Create a new LU extension */
3924 LunExtension
= SpiAllocateLunExtension(DeviceExtension
);
3930 /* Remove this LUN from the list */
3931 DeviceExtension
->LunExtensionList
[Hint
] =
3932 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3934 /* Decide whether we are continuing or not */
3935 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
3943 /* Free allocated buffers */
3945 ExFreePool(LunExtension
);
3948 ExFreePool(LunInfo
);
3950 /* Sum what we found */
3951 BusScanInfo
->LogicalUnitsCount
+= (UCHAR
) DevicesFound
;
3952 DPRINT(" Found %d devices on bus %d\n", DevicesFound
, Bus
);
3955 DPRINT ("SpiScanAdapter() done\n");
3960 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3963 ULONG InquiryDataSize
;
3964 PSCSI_LUN_INFO LunInfo
;
3965 ULONG BusCount
, LunCount
, Length
;
3966 PIO_STACK_LOCATION IrpStack
;
3967 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
3968 PSCSI_INQUIRY_DATA InquiryData
;
3969 PSCSI_BUS_DATA BusData
;
3973 DPRINT("SpiGetInquiryData() called\n");
3975 /* Get pointer to the buffer */
3976 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3977 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3979 /* Initialize bus and LUN counters */
3980 BusCount
= DeviceExtension
->BusesConfig
->NumberOfBuses
;
3983 /* Calculate total number of LUNs */
3984 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3985 LunCount
+= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3987 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
3989 ((sizeof(SCSI_INQUIRY_DATA
) - 1 + INQUIRYDATABUFFERSIZE
+
3990 sizeof(ULONG
) - 1) & ~(sizeof(ULONG
) - 1));
3992 /* Calculate data size */
3993 Length
= sizeof(SCSI_ADAPTER_BUS_INFO
) + (BusCount
- 1) *
3994 sizeof(SCSI_BUS_DATA
);
3996 Length
+= InquiryDataSize
* LunCount
;
3998 /* Check, if all data is going to fit into provided buffer */
3999 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< Length
)
4001 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4002 return STATUS_BUFFER_TOO_SMALL
;
4005 /* Store data size in the IRP */
4006 Irp
->IoStatus
.Information
= Length
;
4008 DPRINT("Data size: %lu\n", Length
);
4010 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
4012 AdapterBusInfo
->NumberOfBuses
= (UCHAR
)BusCount
;
4014 /* Point InquiryData to the corresponding place inside Buffer */
4015 InquiryData
= (PSCSI_INQUIRY_DATA
)(Buffer
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
4016 (BusCount
- 1) * sizeof(SCSI_BUS_DATA
));
4019 for (Bus
= 0; Bus
< BusCount
; Bus
++)
4021 BusData
= &AdapterBusInfo
->BusData
[Bus
];
4023 /* Calculate and save an offset of the inquiry data */
4024 BusData
->InquiryDataOffset
= (PUCHAR
)InquiryData
- Buffer
;
4026 /* Get a pointer to the LUN information structure */
4027 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
4029 /* Store Initiator Bus Id */
4030 BusData
->InitiatorBusId
=
4031 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->BusIdentifier
;
4033 /* Store LUN count */
4034 BusData
->NumberOfLogicalUnits
=
4035 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
4038 while (LunInfo
!= NULL
)
4040 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
4041 Bus
, LunInfo
->TargetId
, LunInfo
->Lun
);
4043 /* Fill InquiryData with values */
4044 InquiryData
->PathId
= LunInfo
->PathId
;
4045 InquiryData
->TargetId
= LunInfo
->TargetId
;
4046 InquiryData
->Lun
= LunInfo
->Lun
;
4047 InquiryData
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
4048 InquiryData
->DeviceClaimed
= LunInfo
->DeviceClaimed
;
4049 InquiryData
->NextInquiryDataOffset
=
4050 (PUCHAR
)InquiryData
+ InquiryDataSize
- Buffer
;
4052 /* Copy data in it */
4053 RtlCopyMemory(InquiryData
->InquiryData
,
4054 LunInfo
->InquiryData
,
4055 INQUIRYDATABUFFERSIZE
);
4057 /* Move to the next LUN */
4058 LunInfo
= LunInfo
->Next
;
4059 InquiryData
= (PSCSI_INQUIRY_DATA
) ((PCHAR
)InquiryData
+ InquiryDataSize
);
4062 /* Either mark the end, or set offset to 0 */
4063 if (BusData
->NumberOfLogicalUnits
!= 0)
4064 ((PSCSI_INQUIRY_DATA
) ((PCHAR
) InquiryData
- InquiryDataSize
))->NextInquiryDataOffset
= 0;
4066 BusData
->InquiryDataOffset
= 0;
4069 /* Finish with success */
4070 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4071 return STATUS_SUCCESS
;
4074 static PSCSI_REQUEST_BLOCK_INFO
4075 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4081 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4083 if (QueueTag
== SP_UNTAGGED
)
4085 /* Untagged request, get LU and return pointer to SrbInfo */
4086 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4091 /* Return NULL in case of error */
4095 /* Return the pointer to SrbInfo */
4096 return &LunExtension
->SrbInfo
;
4100 /* Make sure the tag is valid, if it is - return the data */
4101 if (QueueTag
> DeviceExtension
->SrbDataCount
|| QueueTag
< 1)
4104 return &DeviceExtension
->SrbInfo
[QueueTag
-1];
4109 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4110 IN PSCSI_REQUEST_BLOCK InitialSrb
)
4112 PSCSI_REQUEST_BLOCK Srb
;
4115 PIO_STACK_LOCATION IrpStack
;
4116 LARGE_INTEGER LargeInt
;
4119 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb
);
4122 Srb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
) + sizeof(PVOID
), TAG_SCSIPORT
);
4123 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
4126 LargeInt
.QuadPart
= (LONGLONG
) 1;
4127 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_READ
,
4128 DeviceExtension
->DeviceObject
,
4129 InitialSrb
->SenseInfoBuffer
,
4130 InitialSrb
->SenseInfoBufferLength
,
4134 IoSetCompletionRoutine(Irp
,
4135 (PIO_COMPLETION_ROUTINE
)SpiCompletionRoutine
,
4143 DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb
);
4147 IrpStack
= IoGetNextIrpStackLocation(Irp
);
4148 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
4150 /* Put Srb address into Irp... */
4151 IrpStack
->Parameters
.Others
.Argument1
= (PVOID
)Srb
;
4153 /* ...and vice versa */
4154 Srb
->OriginalRequest
= Irp
;
4157 Ptr
= (PVOID
*)(Srb
+1);
4160 /* Build CDB for REQUEST SENSE */
4162 Cdb
= (PCDB
)Srb
->Cdb
;
4164 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
4165 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= 0;
4166 Cdb
->CDB6INQUIRY
.Reserved1
= 0;
4167 Cdb
->CDB6INQUIRY
.PageCode
= 0;
4168 Cdb
->CDB6INQUIRY
.IReserved
= 0;
4169 Cdb
->CDB6INQUIRY
.AllocationLength
= (UCHAR
)InitialSrb
->SenseInfoBufferLength
;
4170 Cdb
->CDB6INQUIRY
.Control
= 0;
4173 Srb
->TargetId
= InitialSrb
->TargetId
;
4174 Srb
->Lun
= InitialSrb
->Lun
;
4175 Srb
->PathId
= InitialSrb
->PathId
;
4177 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4178 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
4180 /* Timeout will be 2 seconds */
4181 Srb
->TimeOutValue
= 2;
4183 /* No auto request sense */
4184 Srb
->SenseInfoBufferLength
= 0;
4185 Srb
->SenseInfoBuffer
= NULL
;
4187 /* Set necessary flags */
4188 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_BYPASS_FROZEN_QUEUE
|
4189 SRB_FLAGS_DISABLE_DISCONNECT
;
4191 /* Transfer disable synch transfer flag */
4192 if (InitialSrb
->SrbFlags
& SRB_FLAGS_DISABLE_SYNCH_TRANSFER
)
4193 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4195 Srb
->DataBuffer
= InitialSrb
->SenseInfoBuffer
;
4197 /* Fill the transfer length */
4198 Srb
->DataTransferLength
= InitialSrb
->SenseInfoBufferLength
;
4200 /* Clear statuses */
4201 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
4204 /* Call the driver */
4205 (VOID
)IoCallDriver(DeviceExtension
->DeviceObject
, Irp
);
4207 DPRINT("SpiSendRequestSense() done\n");
4214 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4215 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
4216 OUT PBOOLEAN NeedToCallStartIo
)
4218 PSCSI_REQUEST_BLOCK Srb
;
4219 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4222 ULONG SequenceNumber
;
4225 Irp
= Srb
->OriginalRequest
;
4227 /* Get Lun extension */
4228 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4233 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
&&
4234 DeviceExtension
->MapBuffers
&&
4237 /* MDL is shared if transfer is broken into smaller parts */
4238 Srb
->DataBuffer
= (PCCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
4239 ((PCCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
4241 /* In case of data going in, flush the buffers */
4242 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
4244 KeFlushIoBuffers(Irp
->MdlAddress
,
4250 /* Flush adapter if needed */
4251 if (SrbInfo
->BaseOfMapRegister
)
4253 /* TODO: Implement */
4257 /* Clear the request */
4258 SrbInfo
->Srb
= NULL
;
4260 /* If disconnect is disabled... */
4261 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
4263 /* Acquire the spinlock since we mess with flags */
4264 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4266 /* Set corresponding flag */
4267 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
4269 /* Clear the timer if needed */
4270 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
))
4271 DeviceExtension
->TimerCount
= -1;
4273 /* Spinlock is not needed anymore */
4274 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4276 if (!(DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
) &&
4277 !(DeviceExtension
->Flags
& SCSI_PORT_DEVICE_BUSY
) &&
4278 !(*NeedToCallStartIo
))
4280 /* We're not busy, but we have a request pending */
4281 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4285 /* Scatter/gather */
4286 if (Srb
->SrbFlags
& SRB_FLAGS_SGLIST_FROM_POOL
)
4288 /* TODO: Implement */
4292 /* Acquire spinlock (we're freeing SrbExtension) */
4293 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4295 /* Free it (if needed) */
4296 if (Srb
->SrbExtension
)
4298 if (Srb
->SenseInfoBuffer
!= NULL
&& DeviceExtension
->SupportsAutoSense
)
4300 ASSERT(Srb
->SenseInfoBuffer
== NULL
|| SrbInfo
->SaveSenseRequest
!= NULL
);
4302 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)
4304 /* Copy sense data to the buffer */
4305 RtlCopyMemory(SrbInfo
->SaveSenseRequest
,
4306 Srb
->SenseInfoBuffer
,
4307 Srb
->SenseInfoBufferLength
);
4310 /* And restore the pointer */
4311 Srb
->SenseInfoBuffer
= SrbInfo
->SaveSenseRequest
;
4314 /* Put it into the free srb extensions list */
4315 *((PVOID
*)Srb
->SrbExtension
) = DeviceExtension
->FreeSrbExtensions
;
4316 DeviceExtension
->FreeSrbExtensions
= Srb
->SrbExtension
;
4319 /* Save transfer length in the IRP */
4320 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
4322 SequenceNumber
= SrbInfo
->SequenceNumber
;
4323 SrbInfo
->SequenceNumber
= 0;
4325 /* Decrement the queue count */
4326 LunExtension
->QueueCount
--;
4328 /* Free Srb, if needed*/
4329 if (Srb
->QueueTag
!= SP_UNTAGGED
)
4331 /* Put it into the free list */
4332 SrbInfo
->Requests
.Blink
= NULL
;
4333 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
4334 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
4337 /* SrbInfo is not used anymore */
4340 if (DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
)
4342 /* Clear the flag */
4343 DeviceExtension
->Flags
&= ~SCSI_PORT_REQUEST_PENDING
;
4345 /* Note the caller about StartIo */
4346 *NeedToCallStartIo
= TRUE
;
4349 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
4351 /* Start the packet */
4352 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4354 if (!(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
) &&
4355 LunExtension
->RequestTimeout
== -1)
4357 /* Start the next packet */
4358 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4362 /* Release the spinlock */
4363 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4366 DPRINT("IoCompleting request IRP 0x%p\n", Irp
);
4368 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4370 /* Decrement number of active requests, and analyze the result */
4371 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4374 !DeviceExtension
->MapRegisters
&&
4375 DeviceExtension
->AdapterObject
!= NULL
)
4377 /* Nullify map registers */
4378 DeviceExtension
->MapRegisterBase
= NULL
;
4379 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4382 /* Exit, we're done */
4386 /* Decrement number of active requests, and analyze the result */
4387 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4390 !DeviceExtension
->MapRegisters
&&
4391 DeviceExtension
->AdapterObject
!= NULL
)
4393 /* Result is negative, so this is a slave, free map registers */
4394 DeviceExtension
->MapRegisterBase
= NULL
;
4395 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4398 /* Convert status */
4399 Irp
->IoStatus
.Status
= SpiStatusSrbToNt(Srb
->SrbStatus
);
4401 /* It's not a bypass, it's busy or the queue is full? */
4402 if ((Srb
->ScsiStatus
== SCSISTAT_BUSY
||
4403 Srb
->SrbStatus
== SRB_STATUS_BUSY
||
4404 Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
) &&
4405 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
))
4408 DPRINT("Busy SRB status %x\n", Srb
->SrbStatus
);
4410 /* Requeu, if needed */
4411 if (LunExtension
->Flags
& (LUNEX_FROZEN_QUEUE
| LUNEX_BUSY
))
4413 DPRINT("it's being requeued\n");
4415 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4416 Srb
->ScsiStatus
= 0;
4418 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4419 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
4422 /* It's a big f.ck up if we got here */
4423 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
4424 Srb
->ScsiStatus
= SCSISTAT_BUSY
;
4430 /* Release the spinlock */
4431 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4434 else if (LunExtension
->AttemptCount
++ < 20)
4436 /* LUN is still busy */
4437 Srb
->ScsiStatus
= 0;
4438 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4440 LunExtension
->BusyRequest
= Irp
;
4441 LunExtension
->Flags
|= LUNEX_BUSY
;
4443 /* Release the spinlock */
4444 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4449 /* Freeze the queue*/
4450 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4451 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4453 /* "Unfull" the queue */
4454 LunExtension
->Flags
&= ~LUNEX_FULL_QUEUE
;
4456 /* Release the spinlock */
4457 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4459 /* Return status that the device is not ready */
4460 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
4461 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4467 /* Start the next request, if LUN is idle, and this is sense request */
4468 if (((Srb
->ScsiStatus
!= SCSISTAT_CHECK_CONDITION
) ||
4469 (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) ||
4470 !Srb
->SenseInfoBuffer
|| !Srb
->SenseInfoBufferLength
)
4471 && (Srb
->SrbFlags
& SRB_FLAGS_NO_QUEUE_FREEZE
))
4473 if (LunExtension
->RequestTimeout
== -1)
4474 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4476 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4480 /* Freeze the queue */
4481 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4482 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4484 /* Do we need a request sense? */
4485 if (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4486 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
4487 Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
)
4489 /* If LUN is busy, we have to requeue it in order to allow request sense */
4490 if (LunExtension
->Flags
& LUNEX_BUSY
)
4492 DPRINT("Requeueing busy request to allow request sense\n");
4494 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4495 &LunExtension
->BusyRequest
->Tail
.Overlay
.DeviceQueueEntry
,
4498 /* We should never get here */
4501 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4502 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4507 /* Clear busy flags */
4508 LunExtension
->Flags
&= ~(LUNEX_FULL_QUEUE
| LUNEX_BUSY
);
4511 /* Release the spinlock */
4512 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4514 /* Send RequestSense */
4515 SpiSendRequestSense(DeviceExtension
, Srb
);
4521 /* Release the spinlock */
4522 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4525 /* Complete the request */
4526 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4531 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
4535 PSCSI_REQUEST_BLOCK Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
4536 PSCSI_REQUEST_BLOCK InitialSrb
;
4539 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp
);
4541 if ((Srb
->Function
== SRB_FUNCTION_RESET_BUS
) ||
4542 (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
))
4544 /* Deallocate SRB and IRP and exit */
4548 return STATUS_MORE_PROCESSING_REQUIRED
;
4551 /* Get a pointer to the SRB and IRP which were initially sent */
4552 InitialSrb
= *((PVOID
*)(Srb
+1));
4553 InitialIrp
= InitialSrb
->OriginalRequest
;
4555 if ((SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
) ||
4556 (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_DATA_OVERRUN
))
4558 /* Sense data is OK */
4559 InitialSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
4561 /* Set length to be the same */
4562 InitialSrb
->SenseInfoBufferLength
= (UCHAR
)Srb
->DataTransferLength
;
4565 /* Make sure initial SRB's queue is frozen */
4566 ASSERT(InitialSrb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
);
4568 /* Complete this request */
4569 IoCompleteRequest(InitialIrp
, IO_DISK_INCREMENT
);
4571 /* Deallocate everything (internal) */
4574 if (Irp
->MdlAddress
!= NULL
)
4576 MmUnlockPages(Irp
->MdlAddress
);
4577 IoFreeMdl(Irp
->MdlAddress
);
4578 Irp
->MdlAddress
= NULL
;
4582 return STATUS_MORE_PROCESSING_REQUIRED
;
4585 static BOOLEAN NTAPI
4586 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
4587 IN PVOID ServiceContext
)
4589 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4592 DPRINT("ScsiPortIsr() called!\n");
4594 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
4596 /* If interrupts are disabled - we don't expect any */
4597 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_DISABLE_INTERRUPTS
)
4600 /* Call miniport's HwInterrupt routine */
4601 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
4603 /* If flag of notification is set - queue a DPC */
4604 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4606 IoRequestDpc(DeviceExtension
->DeviceObject
,
4607 DeviceExtension
->CurrentIrp
,
4616 SpiSaveInterruptData(IN PVOID Context
)
4618 PSCSI_PORT_SAVE_INTERRUPT InterruptContext
= Context
;
4619 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4620 PSCSI_REQUEST_BLOCK Srb
;
4621 PSCSI_REQUEST_BLOCK_INFO SrbInfo
, NextSrbInfo
;
4622 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4625 /* Get pointer to the device extension */
4626 DeviceExtension
= InterruptContext
->DeviceExtension
;
4628 /* If we don't have anything pending - return */
4629 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
))
4632 /* Actually save the interrupt data */
4633 *InterruptContext
->InterruptData
= DeviceExtension
->InterruptData
;
4635 /* Clear the data stored in the device extension */
4636 DeviceExtension
->InterruptData
.Flags
&=
4637 (SCSI_PORT_RESET
| SCSI_PORT_RESET_REQUEST
| SCSI_PORT_DISABLE_INTERRUPTS
);
4638 DeviceExtension
->InterruptData
.CompletedAbort
= NULL
;
4639 DeviceExtension
->InterruptData
.ReadyLun
= NULL
;
4640 DeviceExtension
->InterruptData
.CompletedRequests
= NULL
;
4642 /* Loop through the list of completed requests */
4643 SrbInfo
= InterruptContext
->InterruptData
->CompletedRequests
;
4647 /* Make sure we have SRV */
4648 ASSERT(SrbInfo
->Srb
);
4650 /* Get SRB and LunExtension */
4653 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4658 /* We have to check special cases if request is unsuccessfull*/
4659 if (Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
)
4661 /* Check if we need request sense by a few conditions */
4662 if (Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
&&
4663 Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4664 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
))
4666 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
4668 /* It means: we tried to send REQUEST SENSE, but failed */
4670 Srb
->ScsiStatus
= 0;
4671 Srb
->SrbStatus
= SRB_STATUS_REQUEST_SENSE_FAILED
;
4675 /* Set the corresponding flag, so that REQUEST SENSE
4677 LunExtension
->Flags
|= LUNEX_NEED_REQUEST_SENSE
;
4682 /* Check for a full queue */
4683 if (Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
)
4685 /* TODO: Implement when it's encountered */
4690 /* Let's decide if we need to watch timeout or not */
4691 if (Srb
->QueueTag
== SP_UNTAGGED
)
4697 if (LunExtension
->SrbInfo
.Requests
.Flink
== &SrbInfo
->Requests
)
4702 /* Remove it from the queue */
4703 RemoveEntryList(&SrbInfo
->Requests
);
4708 /* We have to maintain timeout counter */
4709 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
))
4711 LunExtension
->RequestTimeout
= -1;
4715 NextSrbInfo
= CONTAINING_RECORD(LunExtension
->SrbInfo
.Requests
.Flink
,
4716 SCSI_REQUEST_BLOCK_INFO
,
4719 Srb
= NextSrbInfo
->Srb
;
4721 /* Update timeout counter */
4722 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
4726 SrbInfo
= SrbInfo
->CompletedRequests
;
4734 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4735 IN PSCSI_PORT_LUN_EXTENSION LunExtension
)
4737 PIO_STACK_LOCATION IrpStack
;
4739 PKDEVICE_QUEUE_ENTRY Entry
;
4740 PSCSI_REQUEST_BLOCK Srb
;
4743 /* If LUN is not active or queue is more than maximum allowed */
4744 if (LunExtension
->QueueCount
>= LunExtension
->MaxQueueCount
||
4745 !(LunExtension
->Flags
& SCSI_PORT_LU_ACTIVE
))
4747 /* Release the spinlock and exit */
4748 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4752 /* Check if we can get a next request */
4753 if (LunExtension
->Flags
&
4754 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_BUSY
|
4755 LUNEX_FULL_QUEUE
| LUNEX_FROZEN_QUEUE
| LUNEX_REQUEST_PENDING
))
4757 /* Pending requests can only be started if the queue is empty */
4758 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
) &&
4759 !(LunExtension
->Flags
&
4760 (LUNEX_BUSY
| LUNEX_FROZEN_QUEUE
| LUNEX_FULL_QUEUE
| LUNEX_NEED_REQUEST_SENSE
)))
4762 /* Make sure we have SRB */
4763 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
4765 /* Clear active and pending flags */
4766 LunExtension
->Flags
&= ~(LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
);
4768 /* Get next Irp, and clear pending requests list */
4769 NextIrp
= LunExtension
->PendingRequest
;
4770 LunExtension
->PendingRequest
= NULL
;
4772 /* Set attempt counter to zero */
4773 LunExtension
->AttemptCount
= 0;
4775 /* Release the spinlock */
4776 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4778 /* Start the next pending request */
4779 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4785 /* Release the spinlock, without clearing any flags and exit */
4786 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4792 /* Reset active flag */
4793 LunExtension
->Flags
&= ~SCSI_PORT_LU_ACTIVE
;
4795 /* Set attempt counter to zero */
4796 LunExtension
->AttemptCount
= 0;
4798 /* Remove packet from the device queue */
4799 Entry
= KeRemoveByKeyDeviceQueue(&LunExtension
->DeviceQueue
, LunExtension
->SortKey
);
4803 /* Get pointer to the next irp */
4804 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
4806 /* Get point to the SRB */
4807 IrpStack
= IoGetCurrentIrpStackLocation(NextIrp
);
4808 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
4811 LunExtension
->SortKey
= Srb
->QueueSortKey
;
4812 LunExtension
->SortKey
++;
4814 /* Release the spinlock */
4815 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4817 /* Start the next pending request */
4818 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4822 /* Release the spinlock */
4823 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4829 // ScsiPortDpcForIsr
4836 // IN PDEVICE_OBJECT DpcDeviceObject
4838 // IN PVOID DpcContext
4841 ScsiPortDpcForIsr(IN PKDPC Dpc
,
4842 IN PDEVICE_OBJECT DpcDeviceObject
,
4844 IN PVOID DpcContext
)
4846 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DpcDeviceObject
->DeviceExtension
;
4847 SCSI_PORT_INTERRUPT_DATA InterruptData
;
4848 SCSI_PORT_SAVE_INTERRUPT Context
;
4849 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4850 BOOLEAN NeedToStartIo
;
4851 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
4852 LARGE_INTEGER TimerValue
;
4854 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4855 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
4857 /* We need to acquire spinlock */
4858 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4860 RtlZeroMemory(&InterruptData
, sizeof(SCSI_PORT_INTERRUPT_DATA
));
4864 /* Interrupt structure must be snapshotted, and only then analyzed */
4865 Context
.InterruptData
= &InterruptData
;
4866 Context
.DeviceExtension
= DeviceExtension
;
4868 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
4869 SpiSaveInterruptData
,
4872 /* Nothing - just return (don't forget to release the spinlock */
4873 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4874 DPRINT("ScsiPortDpcForIsr() done\n");
4878 /* If flush of adapters is needed - do it */
4879 if (InterruptData
.Flags
& SCSI_PORT_FLUSH_ADAPTERS
)
4881 /* TODO: Implement */
4885 /* Check for IoMapTransfer */
4886 if (InterruptData
.Flags
& SCSI_PORT_MAP_TRANSFER
)
4888 /* TODO: Implement */
4892 /* Check if timer is needed */
4893 if (InterruptData
.Flags
& SCSI_PORT_TIMER_NEEDED
)
4895 /* Save the timer routine */
4896 DeviceExtension
->HwScsiTimer
= InterruptData
.HwScsiTimer
;
4898 if (InterruptData
.MiniportTimerValue
== 0)
4900 /* Cancel the timer */
4901 KeCancelTimer(&DeviceExtension
->MiniportTimer
);
4905 /* Convert timer value */
4906 TimerValue
.QuadPart
= Int32x32To64(InterruptData
.MiniportTimerValue
, -10);
4909 KeSetTimer(&DeviceExtension
->MiniportTimer
,
4911 &DeviceExtension
->MiniportTimerDpc
);
4915 /* If it's ready for the next request */
4916 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4918 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4919 if ((DeviceExtension
->Flags
&
4920 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
)) ==
4921 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
))
4923 /* Clear busy flag set by ScsiPortStartPacket() */
4924 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4926 if (!(InterruptData
.Flags
& SCSI_PORT_RESET
))
4928 /* Ready for next, and no reset is happening */
4929 DeviceExtension
->TimerCount
= -1;
4934 /* Not busy, but not ready for the next request */
4935 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4936 InterruptData
.Flags
&= ~SCSI_PORT_NEXT_REQUEST_READY
;
4941 if (InterruptData
.Flags
& SCSI_PORT_RESET_REPORTED
)
4943 /* Hold for a bit */
4944 DeviceExtension
->TimerCount
= 4;
4947 /* Any ready LUN? */
4948 if (InterruptData
.ReadyLun
!= NULL
)
4951 /* Process all LUNs from the list*/
4954 /* Remove it from the list first (as processed) */
4955 LunExtension
= InterruptData
.ReadyLun
;
4956 InterruptData
.ReadyLun
= LunExtension
->ReadyLun
;
4957 LunExtension
->ReadyLun
= NULL
;
4959 /* Get next request for this LUN */
4960 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4962 /* Still ready requests exist?
4963 If yes - get spinlock, if no - stop here */
4964 if (InterruptData
.ReadyLun
!= NULL
)
4965 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4972 /* Release the spinlock */
4973 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4976 /* If we ready for next packet, start it */
4977 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4978 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4980 NeedToStartIo
= FALSE
;
4982 /* Loop the completed request list */
4983 while (InterruptData
.CompletedRequests
)
4985 /* Remove the request */
4986 SrbInfo
= InterruptData
.CompletedRequests
;
4987 InterruptData
.CompletedRequests
= SrbInfo
->CompletedRequests
;
4988 SrbInfo
->CompletedRequests
= NULL
;
4991 SpiProcessCompletedRequest(DeviceExtension
,
4996 /* Loop abort request list */
4997 while (InterruptData
.CompletedAbort
)
4999 LunExtension
= InterruptData
.CompletedAbort
;
5001 /* Remove the request */
5002 InterruptData
.CompletedAbort
= LunExtension
->CompletedAbortRequests
;
5004 /* Get spinlock since we're going to change flags */
5005 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5007 /* TODO: Put SrbExtension to the list of free extensions */
5011 /* If we need - call StartIo routine */
5014 /* Make sure CurrentIrp is not null! */
5015 ASSERT(DpcDeviceObject
->CurrentIrp
!= NULL
);
5016 ScsiPortStartIo(DpcDeviceObject
, DpcDeviceObject
->CurrentIrp
);
5019 /* Everything has been done, check */
5020 if (InterruptData
.Flags
& SCSI_PORT_ENABLE_INT_REQUEST
)
5022 /* Synchronize using spinlock */
5023 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5025 /* Request an interrupt */
5026 DeviceExtension
->HwInterrupt(DeviceExtension
->MiniPortDeviceExtension
);
5028 ASSERT(DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
);
5030 /* Should interrupts be enabled again? */
5031 if (DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
)
5033 /* Clear this flag */
5034 DeviceExtension
->Flags
&= ~SCSI_PORT_DISABLE_INT_REQUESET
;
5036 /* Call a special routine to do this */
5039 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
5040 SpiEnableInterrupts
,
5045 /* If we need a notification again - loop */
5046 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5049 /* Release the spinlock */
5050 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5053 DPRINT("ScsiPortDpcForIsr() done\n");
5058 SpiProcessTimeout(PVOID ServiceContext
)
5060 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
5061 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
5064 DPRINT("SpiProcessTimeout() entered\n");
5066 DeviceExtension
->TimerCount
= -1;
5068 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
5070 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET
;
5072 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET_REQUEST
)
5074 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET_REQUEST
;
5075 ScsiPortStartPacket(ServiceContext
);
5082 DPRINT("Resetting the bus\n");
5084 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
5086 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
, Bus
);
5088 /* Reset flags and set reset timeout to 4 seconds */
5089 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
5090 DeviceExtension
->TimerCount
= 4;
5093 /* If miniport requested - request a dpc for it */
5094 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5095 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
5104 SpiResetBus(PVOID ServiceContext
)
5106 PRESETBUS_PARAMS ResetParams
= (PRESETBUS_PARAMS
)ServiceContext
;
5107 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5109 /* Perform the bus reset */
5110 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ResetParams
->DeviceExtension
;
5111 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
,
5112 ResetParams
->PathId
);
5114 /* Set flags and start the timer */
5115 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
5116 DeviceExtension
->TimerCount
= 4;
5118 /* If miniport requested - give him a DPC */
5119 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5120 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
5127 // This function handles timeouts and other time delayed processing
5132 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
5133 // IN PVOID Context the Controller extension for the
5134 // controller the device is on
5137 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
5140 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5141 PSCSI_PORT_LUN_EXTENSION LunExtension
;
5145 DPRINT("ScsiPortIoTimer()\n");
5147 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
5149 /* Protect with the spinlock */
5150 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5152 /* Check timeouts */
5153 if (DeviceExtension
->TimerCount
> 0)
5155 /* Decrease the timeout counter */
5156 DeviceExtension
->TimerCount
--;
5158 if (DeviceExtension
->TimerCount
== 0)
5160 /* Timeout, process it */
5161 if (KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
5163 DeviceExtension
->DeviceObject
))
5165 DPRINT("Error happened during processing timeout, but nothing critical\n");
5169 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5171 /* We should exit now, since timeout is processed */
5175 /* Per-Lun scanning of timeouts is needed... */
5176 for (Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
5178 LunExtension
= DeviceExtension
->LunExtensionList
[Lun
];
5180 while (LunExtension
)
5182 if (LunExtension
->Flags
& LUNEX_BUSY
)
5184 if (!(LunExtension
->Flags
&
5185 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_FROZEN_QUEUE
)))
5187 DPRINT("Retrying busy request\n");
5189 /* Clear flags, and retry busy request */
5190 LunExtension
->Flags
&= ~(LUNEX_BUSY
| LUNEX_FULL_QUEUE
);
5191 Irp
= LunExtension
->BusyRequest
;
5193 /* Clearing busy request */
5194 LunExtension
->BusyRequest
= NULL
;
5196 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5198 IoStartPacket(DeviceObject
, Irp
, (PULONG
)NULL
, NULL
);
5200 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5203 else if (LunExtension
->RequestTimeout
== 0)
5205 RESETBUS_PARAMS ResetParams
;
5207 LunExtension
->RequestTimeout
= -1;
5209 DPRINT("Request timed out, resetting bus\n");
5211 /* Pass params to the bus reset routine */
5212 ResetParams
.PathId
= LunExtension
->PathId
;
5213 ResetParams
.DeviceExtension
= DeviceExtension
;
5215 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
5219 DPRINT1("Reset failed\n");
5222 else if (LunExtension
->RequestTimeout
> 0)
5224 /* Decrement the timeout counter */
5225 LunExtension
->RequestTimeout
--;
5228 LunExtension
= LunExtension
->Next
;
5232 /* Release the spinlock */
5233 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5236 /**********************************************************************
5241 * Builds the registry device map of all device which are attached
5242 * to the given SCSI HBA port. The device map is located at:
5243 * \Registry\Machine\DeviceMap\Scsi
5253 * Name of registry driver service key.
5260 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5261 PUNICODE_STRING RegistryPath
)
5263 PSCSI_PORT_LUN_EXTENSION LunExtension
;
5264 OBJECT_ATTRIBUTES ObjectAttributes
;
5265 UNICODE_STRING KeyName
;
5266 UNICODE_STRING ValueName
;
5267 WCHAR NameBuffer
[64];
5270 HANDLE ScsiPortKey
= NULL
;
5271 HANDLE ScsiBusKey
= NULL
;
5272 HANDLE ScsiInitiatorKey
= NULL
;
5273 HANDLE ScsiTargetKey
= NULL
;
5274 HANDLE ScsiLunKey
= NULL
;
5277 ULONG CurrentTarget
;
5284 DPRINT("SpiBuildDeviceMap() called\n");
5286 if (DeviceExtension
== NULL
|| RegistryPath
== NULL
)
5288 DPRINT1("Invalid parameter\n");
5289 return(STATUS_INVALID_PARAMETER
);
5292 /* Open or create the 'Scsi' subkey */
5293 RtlInitUnicodeString(&KeyName
,
5294 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
5295 InitializeObjectAttributes(&ObjectAttributes
,
5297 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
5300 Status
= ZwCreateKey(&ScsiKey
,
5305 REG_OPTION_VOLATILE
,
5307 if (!NT_SUCCESS(Status
))
5309 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5313 /* Create new 'Scsi Port X' subkey */
5314 DPRINT("Scsi Port %lu\n",
5315 DeviceExtension
->PortNumber
);
5317 swprintf(NameBuffer
,
5319 DeviceExtension
->PortNumber
);
5320 RtlInitUnicodeString(&KeyName
,
5322 InitializeObjectAttributes(&ObjectAttributes
,
5327 Status
= ZwCreateKey(&ScsiPortKey
,
5332 REG_OPTION_VOLATILE
,
5335 if (!NT_SUCCESS(Status
))
5337 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5342 * Create port-specific values
5345 /* Set 'DMA Enabled' (REG_DWORD) value */
5346 UlongData
= (ULONG
)!DeviceExtension
->PortCapabilities
.AdapterUsesPio
;
5347 DPRINT(" DMA Enabled = %s\n", (UlongData
) ? "TRUE" : "FALSE");
5348 RtlInitUnicodeString(&ValueName
,
5350 Status
= ZwSetValueKey(ScsiPortKey
,
5356 if (!NT_SUCCESS(Status
))
5358 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status
);
5359 ZwClose(ScsiPortKey
);
5363 /* Set 'Driver' (REG_SZ) value */
5364 DriverName
= wcsrchr(RegistryPath
->Buffer
, L
'\\') + 1;
5365 RtlInitUnicodeString(&ValueName
,
5367 Status
= ZwSetValueKey(ScsiPortKey
,
5372 (wcslen(DriverName
) + 1) * sizeof(WCHAR
));
5373 if (!NT_SUCCESS(Status
))
5375 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status
);
5376 ZwClose(ScsiPortKey
);
5380 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
5381 UlongData
= (ULONG
)DeviceExtension
->PortConfig
->BusInterruptLevel
;
5382 DPRINT(" Interrupt = %lu\n", UlongData
);
5383 RtlInitUnicodeString(&ValueName
,
5385 Status
= ZwSetValueKey(ScsiPortKey
,
5391 if (!NT_SUCCESS(Status
))
5393 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status
);
5394 ZwClose(ScsiPortKey
);
5398 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
5399 UlongData
= ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension
->PortConfig
->AccessRanges
)[0].RangeStart
);
5400 DPRINT(" IOAddress = %lx\n", UlongData
);
5401 RtlInitUnicodeString(&ValueName
,
5403 Status
= ZwSetValueKey(ScsiPortKey
,
5409 if (!NT_SUCCESS(Status
))
5411 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status
);
5412 ZwClose(ScsiPortKey
);
5416 /* Enumerate buses */
5417 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
->NumberOfBuses
; BusNumber
++)
5419 /* Create 'Scsi Bus X' key */
5420 DPRINT(" Scsi Bus %lu\n", BusNumber
);
5421 swprintf(NameBuffer
,
5424 RtlInitUnicodeString(&KeyName
,
5426 InitializeObjectAttributes(&ObjectAttributes
,
5431 Status
= ZwCreateKey(&ScsiBusKey
,
5436 REG_OPTION_VOLATILE
,
5438 if (!NT_SUCCESS(Status
))
5440 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5444 /* Create 'Initiator Id X' key */
5445 DPRINT(" Initiator Id %u\n",
5446 DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5447 swprintf(NameBuffer
,
5449 (unsigned int)(UCHAR
)DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5450 RtlInitUnicodeString(&KeyName
,
5452 InitializeObjectAttributes(&ObjectAttributes
,
5457 Status
= ZwCreateKey(&ScsiInitiatorKey
,
5462 REG_OPTION_VOLATILE
,
5464 if (!NT_SUCCESS(Status
))
5466 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5470 /* FIXME: Are there any initiator values (??) */
5472 ZwClose(ScsiInitiatorKey
);
5473 ScsiInitiatorKey
= NULL
;
5476 /* Enumerate targets */
5477 CurrentTarget
= (ULONG
)-1;
5478 ScsiTargetKey
= NULL
;
5479 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
5481 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
5483 LunExtension
= SpiGetLunExtension(DeviceExtension
,
5487 if (LunExtension
!= NULL
)
5489 if (Target
!= CurrentTarget
)
5491 /* Close old target key */
5492 if (ScsiTargetKey
!= NULL
)
5494 ZwClose(ScsiTargetKey
);
5495 ScsiTargetKey
= NULL
;
5498 /* Create 'Target Id X' key */
5499 DPRINT(" Target Id %lu\n", Target
);
5500 swprintf(NameBuffer
,
5503 RtlInitUnicodeString(&KeyName
,
5505 InitializeObjectAttributes(&ObjectAttributes
,
5510 Status
= ZwCreateKey(&ScsiTargetKey
,
5515 REG_OPTION_VOLATILE
,
5517 if (!NT_SUCCESS(Status
))
5519 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5523 CurrentTarget
= Target
;
5526 /* Create 'Logical Unit Id X' key */
5527 DPRINT(" Logical Unit Id %lu\n", Lun
);
5528 swprintf(NameBuffer
,
5529 L
"Logical Unit Id %lu",
5531 RtlInitUnicodeString(&KeyName
,
5533 InitializeObjectAttributes(&ObjectAttributes
,
5538 Status
= ZwCreateKey(&ScsiLunKey
,
5543 REG_OPTION_VOLATILE
,
5545 if (!NT_SUCCESS(Status
))
5547 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5551 /* Set 'Identifier' (REG_SZ) value */
5552 swprintf(NameBuffer
,
5554 LunExtension
->InquiryData
.VendorId
,
5555 LunExtension
->InquiryData
.ProductId
,
5556 LunExtension
->InquiryData
.ProductRevisionLevel
);
5557 DPRINT(" Identifier = '%S'\n", NameBuffer
);
5558 RtlInitUnicodeString(&ValueName
,
5560 Status
= ZwSetValueKey(ScsiLunKey
,
5565 (wcslen(NameBuffer
) + 1) * sizeof(WCHAR
));
5566 if (!NT_SUCCESS(Status
))
5568 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status
);
5572 /* Set 'Type' (REG_SZ) value */
5573 switch (LunExtension
->InquiryData
.DeviceType
)
5576 TypeName
= L
"DiskPeripheral";
5579 TypeName
= L
"TapePeripheral";
5582 TypeName
= L
"PrinterPeripheral";
5585 TypeName
= L
"WormPeripheral";
5588 TypeName
= L
"CdRomPeripheral";
5591 TypeName
= L
"ScannerPeripheral";
5594 TypeName
= L
"OpticalDiskPeripheral";
5597 TypeName
= L
"MediumChangerPeripheral";
5600 TypeName
= L
"CommunicationPeripheral";
5603 TypeName
= L
"OtherPeripheral";
5606 DPRINT(" Type = '%S'\n", TypeName
);
5607 RtlInitUnicodeString(&ValueName
,
5609 Status
= ZwSetValueKey(ScsiLunKey
,
5614 (wcslen(TypeName
) + 1) * sizeof(WCHAR
));
5615 if (!NT_SUCCESS(Status
))
5617 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status
);
5621 ZwClose(ScsiLunKey
);
5626 /* Close old target key */
5627 if (ScsiTargetKey
!= NULL
)
5629 ZwClose(ScsiTargetKey
);
5630 ScsiTargetKey
= NULL
;
5634 ZwClose(ScsiBusKey
);
5639 if (ScsiLunKey
!= NULL
)
5640 ZwClose (ScsiLunKey
);
5642 if (ScsiInitiatorKey
!= NULL
)
5643 ZwClose (ScsiInitiatorKey
);
5645 if (ScsiTargetKey
!= NULL
)
5646 ZwClose (ScsiTargetKey
);
5648 if (ScsiBusKey
!= NULL
)
5649 ZwClose (ScsiBusKey
);
5651 if (ScsiPortKey
!= NULL
)
5652 ZwClose (ScsiPortKey
);
5654 DPRINT("SpiBuildDeviceMap() done\n");
5661 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
5662 IN PVOID DeviceObject
,
5663 IN PVOID SystemArgument1
,
5664 IN PVOID SystemArgument2
)
5666 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5668 DPRINT("Miniport timer DPC\n");
5670 DeviceExtension
= ((PDEVICE_OBJECT
)DeviceObject
)->DeviceExtension
;
5672 /* Acquire the spinlock */
5673 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5675 /* Call the timer routine */
5676 if (DeviceExtension
->HwScsiTimer
!= NULL
)
5678 DeviceExtension
->HwScsiTimer(&DeviceExtension
->MiniPortDeviceExtension
);
5681 /* Release the spinlock */
5682 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5684 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5686 ScsiPortDpcForIsr(NULL
,
5687 DeviceExtension
->DeviceObject
,
5694 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5695 PHW_INITIALIZATION_DATA HwInitData
,
5696 PCONFIGURATION_INFO InternalConfigInfo
,
5697 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5700 UNICODE_STRING UnicodeString
;
5701 OBJECT_ATTRIBUTES ObjectAttributes
;
5702 PCONFIGURATION_INFORMATION DdkConfigInformation
;
5703 HANDLE RootKey
, Key
;
5705 WCHAR DeviceBuffer
[16];
5706 WCHAR StrBuffer
[512];
5710 /* Zero out the struct if told so */
5713 /* First zero the portconfig */
5714 RtlZeroMemory(ConfigInfo
, sizeof(PORT_CONFIGURATION_INFORMATION
));
5716 /* Then access ranges */
5717 RtlZeroMemory(InternalConfigInfo
->AccessRanges
,
5718 HwInitData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
5720 /* Initialize the struct */
5721 ConfigInfo
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
5722 ConfigInfo
->AdapterInterfaceType
= HwInitData
->AdapterInterfaceType
;
5723 ConfigInfo
->InterruptMode
= Latched
;
5724 ConfigInfo
->DmaChannel
= SP_UNINITIALIZED_VALUE
;
5725 ConfigInfo
->DmaPort
= SP_UNINITIALIZED_VALUE
;
5726 ConfigInfo
->DmaChannel2
= SP_UNINITIALIZED_VALUE
;
5727 ConfigInfo
->DmaPort2
= SP_UNINITIALIZED_VALUE
;
5728 ConfigInfo
->MaximumTransferLength
= SP_UNINITIALIZED_VALUE
;
5729 ConfigInfo
->NumberOfAccessRanges
= HwInitData
->NumberOfAccessRanges
;
5730 ConfigInfo
->MaximumNumberOfTargets
= 8;
5732 /* Store parameters */
5733 ConfigInfo
->NeedPhysicalAddresses
= HwInitData
->NeedPhysicalAddresses
;
5734 ConfigInfo
->MapBuffers
= HwInitData
->MapBuffers
;
5735 ConfigInfo
->AutoRequestSense
= HwInitData
->AutoRequestSense
;
5736 ConfigInfo
->ReceiveEvent
= HwInitData
->ReceiveEvent
;
5737 ConfigInfo
->TaggedQueuing
= HwInitData
->TaggedQueuing
;
5738 ConfigInfo
->MultipleRequestPerLu
= HwInitData
->MultipleRequestPerLu
;
5740 /* Get the disk usage */
5741 DdkConfigInformation
= IoGetConfigurationInformation();
5742 ConfigInfo
->AtdiskPrimaryClaimed
= DdkConfigInformation
->AtDiskPrimaryAddressClaimed
;
5743 ConfigInfo
->AtdiskSecondaryClaimed
= DdkConfigInformation
->AtDiskSecondaryAddressClaimed
;
5745 /* Initiator bus id is not set */
5746 for (Bus
= 0; Bus
< 8; Bus
++)
5747 ConfigInfo
->InitiatorBusId
[Bus
] = (CCHAR
)SP_UNINITIALIZED_VALUE
;
5750 ConfigInfo
->NumberOfPhysicalBreaks
= 17;
5752 /* Clear this information */
5753 InternalConfigInfo
->DisableTaggedQueueing
= FALSE
;
5754 InternalConfigInfo
->DisableMultipleLun
= FALSE
;
5756 /* Store Bus Number */
5757 ConfigInfo
->SystemIoBusNumber
= InternalConfigInfo
->BusNumber
;
5761 if (ConfigInfo
->AdapterInterfaceType
== Internal
)
5763 /* Open registry key for HW database */
5764 InitializeObjectAttributes(&ObjectAttributes
,
5765 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
5766 OBJ_CASE_INSENSITIVE
,
5770 Status
= ZwOpenKey(&RootKey
,
5774 if (NT_SUCCESS(Status
))
5776 /* Create name for it */
5777 swprintf(StrBuffer
, L
"ScsiAdapter\\%lu",
5778 InternalConfigInfo
->AdapterNumber
);
5780 RtlInitUnicodeString(&UnicodeString
, StrBuffer
);
5782 /* Open device key */
5783 InitializeObjectAttributes(&ObjectAttributes
,
5785 OBJ_CASE_INSENSITIVE
,
5789 Status
= ZwOpenKey(&Key
,
5795 if (NT_SUCCESS(Status
))
5797 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5799 DPRINT("Hardware info found at %S\n", StrBuffer
);
5802 SpiParseDeviceInfo(DeviceExtension
,
5808 InternalConfigInfo
->BusNumber
= 0;
5812 /* Try the next adapter */
5813 InternalConfigInfo
->AdapterNumber
++;
5819 /* Info was not found, exit */
5820 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status
);
5821 return STATUS_DEVICE_DOES_NOT_EXIST
;
5826 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status
);
5830 /* Look at device params */
5832 if (InternalConfigInfo
->Parameter
)
5834 ExFreePool(InternalConfigInfo
->Parameter
);
5835 InternalConfigInfo
->Parameter
= NULL
;
5838 if (InternalConfigInfo
->ServiceKey
!= NULL
)
5840 swprintf(DeviceBuffer
, L
"Device%lu", InternalConfigInfo
->AdapterNumber
);
5841 RtlInitUnicodeString(&UnicodeString
, DeviceBuffer
);
5843 /* Open the service key */
5844 InitializeObjectAttributes(&ObjectAttributes
,
5846 OBJ_CASE_INSENSITIVE
,
5847 InternalConfigInfo
->ServiceKey
,
5850 Status
= ZwOpenKey(&Key
,
5855 /* Parse device key */
5856 if (InternalConfigInfo
->DeviceKey
!= NULL
)
5858 SpiParseDeviceInfo(DeviceExtension
,
5859 InternalConfigInfo
->DeviceKey
,
5865 /* Then parse hw info */
5868 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5870 SpiParseDeviceInfo(DeviceExtension
,
5881 /* Adapter not found, go try the next one */
5882 InternalConfigInfo
->AdapterNumber
++;
5891 /* Update the last adapter number */
5892 InternalConfigInfo
->LastAdapterNumber
= InternalConfigInfo
->AdapterNumber
;
5894 /* Do we have this kind of bus at all? */
5896 Status
= IoQueryDeviceDescription(&HwInitData
->AdapterInterfaceType
,
5897 &InternalConfigInfo
->BusNumber
,
5902 SpQueryDeviceCallout
,
5905 /* This bus was not found */
5908 INTERFACE_TYPE InterfaceType
= Eisa
;
5910 /* Check for EISA */
5911 if (HwInitData
->AdapterInterfaceType
== Isa
)
5913 Status
= IoQueryDeviceDescription(&InterfaceType
,
5914 &InternalConfigInfo
->BusNumber
,
5919 SpQueryDeviceCallout
,
5922 /* Return respectively */
5924 return STATUS_SUCCESS
;
5926 return STATUS_DEVICE_DOES_NOT_EXIST
;
5930 return STATUS_DEVICE_DOES_NOT_EXIST
;
5935 return STATUS_SUCCESS
;
5940 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5942 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5943 IN PCONFIGURATION_INFO InternalConfigInfo
,
5946 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
5947 PCM_FULL_RESOURCE_DESCRIPTOR FullResource
;
5948 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
5949 PCM_SCSI_DEVICE_DATA ScsiDeviceData
;
5950 ULONG Length
, Count
, Dma
= 0, Interrupt
= 0;
5951 ULONG Index
= 0, RangeCount
= 0;
5952 UNICODE_STRING UnicodeString
;
5953 ANSI_STRING AnsiString
;
5954 NTSTATUS Status
= STATUS_SUCCESS
;
5957 KeyValueInformation
= (PKEY_VALUE_FULL_INFORMATION
) Buffer
;
5959 /* Loop through all values in the device node */
5962 Status
= ZwEnumerateValueKey(Key
,
5964 KeyValueFullInformation
,
5969 if (!NT_SUCCESS(Status
))
5974 /* Length for DWORD is ok? */
5975 if (KeyValueInformation
->Type
== REG_DWORD
&&
5976 KeyValueInformation
->DataLength
!= sizeof(ULONG
))
5981 /* Get MaximumLogicalUnit */
5982 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumLogicalUnit",
5983 KeyValueInformation
->NameLength
/2) == 0)
5986 if (KeyValueInformation
->Type
!= REG_DWORD
)
5988 DPRINT("Bad data type for MaximumLogicalUnit\n");
5992 DeviceExtension
->MaxLunCount
= *((PUCHAR
)
5993 (Buffer
+ KeyValueInformation
->DataOffset
));
5995 /* Check / reset if needed */
5996 if (DeviceExtension
->MaxLunCount
> SCSI_MAXIMUM_LOGICAL_UNITS
)
5997 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
5999 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension
->MaxLunCount
);
6002 /* Get InitiatorTargetId */
6003 if (_wcsnicmp(KeyValueInformation
->Name
, L
"InitiatorTargetId",
6004 KeyValueInformation
->NameLength
/ 2) == 0)
6007 if (KeyValueInformation
->Type
!= REG_DWORD
)
6009 DPRINT("Bad data type for InitiatorTargetId\n");
6013 ConfigInfo
->InitiatorBusId
[0] = *((PUCHAR
)
6014 (Buffer
+ KeyValueInformation
->DataOffset
));
6016 /* Check / reset if needed */
6017 if (ConfigInfo
->InitiatorBusId
[0] > ConfigInfo
->MaximumNumberOfTargets
- 1)
6018 ConfigInfo
->InitiatorBusId
[0] = (CCHAR
)-1;
6020 DPRINT("InitiatorTargetId = %d\n", ConfigInfo
->InitiatorBusId
[0]);
6024 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ScsiDebug",
6025 KeyValueInformation
->NameLength
/2) == 0)
6027 DPRINT("ScsiDebug key not supported\n");
6030 /* Check for a breakpoint */
6031 if (_wcsnicmp(KeyValueInformation
->Name
, L
"BreakPointOnEntry",
6032 KeyValueInformation
->NameLength
/2) == 0)
6034 DPRINT1("Breakpoint on entry requested!\n");
6038 /* Get DisableSynchronousTransfers */
6039 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableSynchronousTransfers",
6040 KeyValueInformation
->NameLength
/2) == 0)
6042 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6043 DPRINT("Synch transfers disabled\n");
6046 /* Get DisableDisconnects */
6047 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableDisconnects",
6048 KeyValueInformation
->NameLength
/2) == 0)
6050 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
6051 DPRINT("Disconnects disabled\n");
6054 /* Get DisableTaggedQueuing */
6055 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableTaggedQueuing",
6056 KeyValueInformation
->NameLength
/2) == 0)
6058 InternalConfigInfo
->DisableTaggedQueueing
= TRUE
;
6059 DPRINT("Tagged queueing disabled\n");
6062 /* Get DisableMultipleRequests */
6063 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableMultipleRequests",
6064 KeyValueInformation
->NameLength
/2) == 0)
6066 InternalConfigInfo
->DisableMultipleLun
= TRUE
;
6067 DPRINT("Multiple requests disabled\n");
6070 /* Get DriverParameters */
6071 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DriverParameters",
6072 KeyValueInformation
->NameLength
/2) == 0)
6074 /* Skip if nothing */
6075 if (KeyValueInformation
->DataLength
== 0)
6078 /* If there was something previously allocated - free it */
6079 if (InternalConfigInfo
->Parameter
!= NULL
)
6080 ExFreePool(InternalConfigInfo
->Parameter
);
6083 InternalConfigInfo
->Parameter
= ExAllocatePoolWithTag(NonPagedPool
,
6084 KeyValueInformation
->DataLength
, TAG_SCSIPORT
);
6086 if (InternalConfigInfo
->Parameter
!= NULL
)
6088 if (KeyValueInformation
->Type
!= REG_SZ
)
6092 InternalConfigInfo
->Parameter
,
6093 (PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
,
6094 KeyValueInformation
->DataLength
);
6098 /* If it's a unicode string, convert it to ansi */
6099 UnicodeString
.Length
= (USHORT
)KeyValueInformation
->DataLength
;
6100 UnicodeString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
6101 UnicodeString
.Buffer
=
6102 (PWSTR
)((PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
6104 AnsiString
.Length
= 0;
6105 AnsiString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
6106 AnsiString
.Buffer
= (PCHAR
)InternalConfigInfo
->Parameter
;
6108 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
6112 /* In case of error, free the allocated space */
6113 if (!NT_SUCCESS(Status
))
6115 ExFreePool(InternalConfigInfo
->Parameter
);
6116 InternalConfigInfo
->Parameter
= NULL
;
6122 DPRINT("Found driver parameter\n");
6125 /* Get MaximumSGList */
6126 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumSGList",
6127 KeyValueInformation
->NameLength
/2) == 0)
6129 if (KeyValueInformation
->Type
!= REG_DWORD
)
6131 DPRINT("Bad data type for MaximumSGList\n");
6135 ConfigInfo
->NumberOfPhysicalBreaks
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
6138 if (ConfigInfo
->NumberOfPhysicalBreaks
> SCSI_MAXIMUM_PHYSICAL_BREAKS
)
6140 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MAXIMUM_PHYSICAL_BREAKS
;
6142 else if (ConfigInfo
->NumberOfPhysicalBreaks
< SCSI_MINIMUM_PHYSICAL_BREAKS
)
6144 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MINIMUM_PHYSICAL_BREAKS
;
6147 DPRINT("MaximumSGList = %d\n", ConfigInfo
->NumberOfPhysicalBreaks
);
6150 /* Get NumberOfRequests */
6151 if (_wcsnicmp(KeyValueInformation
->Name
, L
"NumberOfRequests",
6152 KeyValueInformation
->NameLength
/2) == 0)
6154 if (KeyValueInformation
->Type
!= REG_DWORD
)
6156 DPRINT("NumberOfRequests has wrong data type\n");
6160 DeviceExtension
->RequestsNumber
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
6163 if (DeviceExtension
->RequestsNumber
< 16)
6165 DeviceExtension
->RequestsNumber
= 16;
6167 else if (DeviceExtension
->RequestsNumber
> 512)
6169 DeviceExtension
->RequestsNumber
= 512;
6172 DPRINT("Number Of Requests = %d\n", DeviceExtension
->RequestsNumber
);
6175 /* Get resource list */
6176 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ResourceList",
6177 KeyValueInformation
->NameLength
/2) == 0 ||
6178 _wcsnicmp(KeyValueInformation
->Name
, L
"Configuration Data",
6179 KeyValueInformation
->NameLength
/2) == 0 )
6181 if (KeyValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
||
6182 KeyValueInformation
->DataLength
< sizeof(REG_FULL_RESOURCE_DESCRIPTOR
))
6184 DPRINT("Bad data type for ResourceList\n");
6189 DPRINT("Found ResourceList\n");
6192 FullResource
= (PCM_FULL_RESOURCE_DESCRIPTOR
)(Buffer
+ KeyValueInformation
->DataOffset
);
6194 /* Copy some info from it */
6195 InternalConfigInfo
->BusNumber
= FullResource
->BusNumber
;
6196 ConfigInfo
->SystemIoBusNumber
= FullResource
->BusNumber
;
6198 /* Loop through it */
6199 for (Count
= 0; Count
< FullResource
->PartialResourceList
.Count
; Count
++)
6201 /* Get partial descriptor */
6203 &FullResource
->PartialResourceList
.PartialDescriptors
[Count
];
6205 /* Check datalength */
6206 if ((ULONG
)((PCHAR
)(PartialDescriptor
+ 1) -
6207 (PCHAR
)FullResource
) > KeyValueInformation
->DataLength
)
6209 DPRINT("Resource data is of incorrect size\n");
6213 switch (PartialDescriptor
->Type
)
6215 case CmResourceTypePort
:
6216 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
6218 DPRINT("Too many access ranges\n");
6222 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= FALSE
;
6223 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Port
.Start
;
6224 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Port
.Length
;
6229 case CmResourceTypeMemory
:
6230 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
6232 DPRINT("Too many access ranges\n");
6236 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= TRUE
;
6237 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Memory
.Start
;
6238 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Memory
.Length
;
6243 case CmResourceTypeInterrupt
:
6247 ConfigInfo
->BusInterruptLevel
=
6248 PartialDescriptor
->u
.Interrupt
.Level
;
6250 ConfigInfo
->BusInterruptVector
=
6251 PartialDescriptor
->u
.Interrupt
.Vector
;
6253 ConfigInfo
->InterruptMode
= (PartialDescriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
) ? Latched
: LevelSensitive
;
6255 else if (Interrupt
== 1)
6257 ConfigInfo
->BusInterruptLevel2
=
6258 PartialDescriptor
->u
.Interrupt
.Level
;
6260 ConfigInfo
->BusInterruptVector2
=
6261 PartialDescriptor
->u
.Interrupt
.Vector
;
6263 ConfigInfo
->InterruptMode2
= (PartialDescriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
) ? Latched
: LevelSensitive
;
6269 case CmResourceTypeDma
:
6273 ConfigInfo
->DmaChannel
= PartialDescriptor
->u
.Dma
.Channel
;
6274 ConfigInfo
->DmaPort
= PartialDescriptor
->u
.Dma
.Port
;
6276 if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8
)
6277 ConfigInfo
->DmaWidth
= Width8Bits
;
6278 else if ((PartialDescriptor
->Flags
& CM_RESOURCE_DMA_16
) ||
6279 (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
6280 ConfigInfo
->DmaWidth
= Width16Bits
;
6281 else if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_32
)
6282 ConfigInfo
->DmaWidth
= Width32Bits
;
6286 ConfigInfo
->DmaChannel2
= PartialDescriptor
->u
.Dma
.Channel
;
6287 ConfigInfo
->DmaPort2
= PartialDescriptor
->u
.Dma
.Port
;
6289 if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8
)
6290 ConfigInfo
->DmaWidth2
= Width8Bits
;
6291 else if ((PartialDescriptor
->Flags
& CM_RESOURCE_DMA_16
) ||
6292 (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
6293 ConfigInfo
->DmaWidth2
= Width16Bits
;
6294 else if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_32
)
6295 ConfigInfo
->DmaWidth2
= Width32Bits
;
6301 case CmResourceTypeDeviceSpecific
:
6302 if (PartialDescriptor
->u
.DeviceSpecificData
.DataSize
<
6303 sizeof(CM_SCSI_DEVICE_DATA
) ||
6304 (PCHAR
) (PartialDescriptor
+ 1) - (PCHAR
)FullResource
+
6305 PartialDescriptor
->u
.DeviceSpecificData
.DataSize
>
6306 KeyValueInformation
->DataLength
)
6308 DPRINT("Resource data length is incorrect");
6312 /* Set only one field from it */
6313 ScsiDeviceData
= (PCM_SCSI_DEVICE_DATA
) (PartialDescriptor
+1);
6314 ConfigInfo
->InitiatorBusId
[0] = ScsiDeviceData
->HostIdentifier
;
6324 SpQueryDeviceCallout(IN PVOID Context
,
6325 IN PUNICODE_STRING PathName
,
6326 IN INTERFACE_TYPE BusType
,
6328 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
6329 IN CONFIGURATION_TYPE ControllerType
,
6330 IN ULONG ControllerNumber
,
6331 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
6332 IN CONFIGURATION_TYPE PeripheralType
,
6333 IN ULONG PeripheralNumber
,
6334 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
6336 PBOOLEAN Found
= (PBOOLEAN
)Context
;
6337 /* We just set our Found variable to TRUE */
6340 return STATUS_SUCCESS
;
6343 IO_ALLOCATION_ACTION
6345 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject
,
6347 IN PVOID MapRegisterBase
,
6351 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
6353 /* Guard access with the spinlock */
6354 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
6356 /* Save MapRegisterBase we've got here */
6357 DeviceExtension
->MapRegisterBase
= MapRegisterBase
;
6359 /* Start pending request */
6360 KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
6361 ScsiPortStartPacket
, DeviceObject
);
6363 /* Release spinlock we took */
6364 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
6371 SpiStatusSrbToNt(UCHAR SrbStatus
)
6373 switch (SRB_STATUS(SrbStatus
))
6375 case SRB_STATUS_TIMEOUT
:
6376 case SRB_STATUS_COMMAND_TIMEOUT
:
6377 return STATUS_IO_TIMEOUT
;
6379 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH
:
6380 case SRB_STATUS_BAD_FUNCTION
:
6381 return STATUS_INVALID_DEVICE_REQUEST
;
6383 case SRB_STATUS_NO_DEVICE
:
6384 case SRB_STATUS_INVALID_LUN
:
6385 case SRB_STATUS_INVALID_TARGET_ID
:
6386 case SRB_STATUS_NO_HBA
:
6387 return STATUS_DEVICE_DOES_NOT_EXIST
;
6389 case SRB_STATUS_DATA_OVERRUN
:
6390 return STATUS_BUFFER_OVERFLOW
;
6392 case SRB_STATUS_SELECTION_TIMEOUT
:
6393 return STATUS_DEVICE_NOT_CONNECTED
;
6396 return STATUS_IO_DEVICE_ERROR
;
6399 return STATUS_IO_DEVICE_ERROR
;
6403 #undef ScsiPortConvertPhysicalAddressToUlong
6408 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
6410 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
6411 return(Address
.u
.LowPart
);