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 /* TYPES *********************************************************************/
50 /* GLOBALS *******************************************************************/
53 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
54 IN PDEVICE_OBJECT DeviceObject
,
55 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
56 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
57 IN PUNICODE_STRING RegistryPath
,
59 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
);
62 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
65 static DRIVER_DISPATCH ScsiPortDispatchScsi
;
67 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
71 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
74 static DRIVER_STARTIO ScsiPortStartIo
;
76 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
80 ScsiPortStartPacket(IN OUT PVOID Context
);
84 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
85 PVOID MapRegisterBase
, PVOID Context
);
87 static PSCSI_PORT_LUN_EXTENSION
88 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
90 static PSCSI_PORT_LUN_EXTENSION
91 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
96 static PSCSI_REQUEST_BLOCK_INFO
97 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
98 PSCSI_PORT_LUN_EXTENSION LunExtension
,
99 PSCSI_REQUEST_BLOCK Srb
);
102 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
103 IN PSCSI_LUN_INFO LunInfo
);
106 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
109 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
112 static PSCSI_REQUEST_BLOCK_INFO
113 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
120 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
121 IN PVOID ServiceContext
);
124 ScsiPortDpcForIsr(IN PKDPC Dpc
,
125 IN PDEVICE_OBJECT DpcDeviceObject
,
127 IN PVOID DpcContext
);
130 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
135 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject
,
137 IN PVOID MapRegisterBase
,
141 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
142 PUNICODE_STRING RegistryPath
);
145 SpiStatusSrbToNt(UCHAR SrbStatus
);
148 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
149 IN PSCSI_REQUEST_BLOCK Srb
);
151 static IO_COMPLETION_ROUTINE SpiCompletionRoutine
;
153 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
159 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
160 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
161 OUT PBOOLEAN NeedToCallStartIo
);
164 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
165 IN PSCSI_PORT_LUN_EXTENSION LunExtension
);
168 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
169 IN PVOID DeviceObject
,
170 IN PVOID SystemArgument1
,
171 IN PVOID SystemArgument2
);
174 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
175 PHW_INITIALIZATION_DATA HwInitData
,
176 PCONFIGURATION_INFO InternalConfigInfo
,
177 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
181 SpQueryDeviceCallout(IN PVOID Context
,
182 IN PUNICODE_STRING PathName
,
183 IN INTERFACE_TYPE BusType
,
185 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
186 IN CONFIGURATION_TYPE ControllerType
,
187 IN ULONG ControllerNumber
,
188 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
189 IN CONFIGURATION_TYPE PeripheralType
,
190 IN ULONG PeripheralNumber
,
191 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
);
194 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
196 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
197 IN PCONFIGURATION_INFO InternalConfigInfo
,
201 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
202 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
203 IN PPORT_CONFIGURATION_INFORMATION PortConfig
);
205 static PCM_RESOURCE_LIST
206 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
207 PPORT_CONFIGURATION_INFORMATION PortConfig
);
210 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
213 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
217 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
);
221 /* FUNCTIONS *****************************************************************/
223 /**********************************************************************
228 * This function initializes the driver.
235 * System allocated Driver Object for this driver.
238 * Name of registry driver service key.
245 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
246 IN PUNICODE_STRING RegistryPath
)
248 DPRINT("ScsiPort Driver %s\n", VERSION
);
249 return(STATUS_SUCCESS
);
253 /**********************************************************************
258 * Prints debugging messages.
265 * Debug level of the given message.
268 * Pointer to printf()-compatible format string.
271 Additional output data (see printf()).
280 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
281 IN PCHAR DebugMessage
,
287 if (DebugPrintLevel
> InternalDebugLevel
)
290 va_start(ap
, DebugMessage
);
291 vsprintf(Buffer
, DebugMessage
, ap
);
297 /* An internal helper function for ScsiPortCompleteRequest */
300 SpiCompleteRequest(IN PVOID HwDeviceExtension
,
301 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
304 PSCSI_REQUEST_BLOCK Srb
;
306 /* Get current SRB */
309 /* Return if there is no SRB or it is not active */
310 if (!Srb
|| !(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
)) return;
313 Srb
->SrbStatus
= SrbStatus
;
315 /* Set data transfered to 0 */
316 Srb
->DataTransferLength
= 0;
319 ScsiPortNotification(RequestComplete
,
328 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
334 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
335 PSCSI_PORT_LUN_EXTENSION LunExtension
;
336 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
337 PLIST_ENTRY ListEntry
;
341 DPRINT("ScsiPortCompleteRequest() called\n");
343 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
344 SCSI_PORT_DEVICE_EXTENSION
,
345 MiniPortDeviceExtension
);
347 /* Go through all buses */
348 for (BusNumber
= 0; BusNumber
< 8; BusNumber
++)
350 /* Go through all targets */
351 for (Target
= 0; Target
< DeviceExtension
->MaxTargedIds
; Target
++)
353 /* Get logical unit list head */
354 LunExtension
= DeviceExtension
->LunExtensionList
[Target
% 8];
356 /* Go through all logical units */
359 /* Now match what caller asked with what we are at now */
360 if ((PathId
== SP_UNTAGGED
|| PathId
== LunExtension
->PathId
) &&
361 (TargetId
== SP_UNTAGGED
|| TargetId
== LunExtension
->TargetId
) &&
362 (Lun
== SP_UNTAGGED
|| Lun
== LunExtension
->Lun
))
364 /* Yes, that's what caller asked for. Complete abort requests */
365 if (LunExtension
->CompletedAbortRequests
)
367 /* TODO: Save SrbStatus in this request */
368 DPRINT1("Completing abort request without setting SrbStatus!\n");
370 /* Issue a notification request */
371 ScsiPortNotification(RequestComplete
,
373 LunExtension
->CompletedAbortRequests
);
376 /* Complete the request using our helper */
377 SpiCompleteRequest(HwDeviceExtension
,
378 &LunExtension
->SrbInfo
,
381 /* Go through the queue and complete everything there too */
382 ListEntry
= LunExtension
->SrbInfo
.Requests
.Flink
;
383 while (ListEntry
!= &LunExtension
->SrbInfo
.Requests
)
385 /* Get the actual SRB info entry */
386 SrbInfo
= CONTAINING_RECORD(ListEntry
,
387 SCSI_REQUEST_BLOCK_INFO
,
391 SpiCompleteRequest(HwDeviceExtension
,
395 /* Advance to the next request in queue */
396 ListEntry
= SrbInfo
->Requests
.Flink
;
400 /* Advance to the next one */
401 LunExtension
= LunExtension
->Next
;
411 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
413 DPRINT("ScsiPortFlushDma()\n");
422 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
423 IN PVOID MappedAddress
)
425 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
426 PMAPPED_ADDRESS NextMa
, LastMa
;
428 //DPRINT("ScsiPortFreeDeviceBase() called\n");
430 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
431 SCSI_PORT_DEVICE_EXTENSION
,
432 MiniPortDeviceExtension
);
434 /* Initialize our pointers */
435 NextMa
= DeviceExtension
->MappedAddressList
;
440 if (NextMa
->MappedAddress
== MappedAddress
)
443 MmUnmapIoSpace(MappedAddress
, NextMa
->NumberOfBytes
);
445 /* Remove it from the list */
446 if (NextMa
== DeviceExtension
->MappedAddressList
)
448 /* Remove the first entry */
449 DeviceExtension
->MappedAddressList
= NextMa
->NextMappedAddress
;
453 LastMa
->NextMappedAddress
= NextMa
->NextMappedAddress
;
456 /* Free the resources and quit */
464 NextMa
= NextMa
->NextMappedAddress
;
474 ScsiPortGetBusData(IN PVOID DeviceExtension
,
475 IN ULONG BusDataType
,
476 IN ULONG SystemIoBusNumber
,
481 DPRINT("ScsiPortGetBusData()\n");
485 /* If Length is non-zero, just forward the call to
486 HalGetBusData() function */
487 return HalGetBusData(BusDataType
,
494 /* We have a more complex case here */
503 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
504 IN ULONG BusDataType
,
505 IN ULONG SystemIoBusNumber
,
511 DPRINT("ScsiPortSetBusDataByOffset()\n");
512 return HalSetBusDataByOffset(BusDataType
,
524 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
525 IN INTERFACE_TYPE BusType
,
526 IN ULONG SystemIoBusNumber
,
527 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
528 IN ULONG NumberOfBytes
,
529 IN BOOLEAN InIoSpace
)
531 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
532 PHYSICAL_ADDRESS TranslatedAddress
;
533 PMAPPED_ADDRESS DeviceBase
;
537 //DPRINT ("ScsiPortGetDeviceBase() called\n");
539 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
540 SCSI_PORT_DEVICE_EXTENSION
,
541 MiniPortDeviceExtension
);
543 AddressSpace
= (ULONG
)InIoSpace
;
544 if (HalTranslateBusAddress(BusType
,
548 &TranslatedAddress
) == FALSE
)
554 if (AddressSpace
!= 0)
555 return((PVOID
)(ULONG_PTR
)TranslatedAddress
.QuadPart
);
557 MappedAddress
= MmMapIoSpace(TranslatedAddress
,
561 DeviceBase
= ExAllocatePoolWithTag(NonPagedPool
,
562 sizeof(MAPPED_ADDRESS
), TAG_SCSIPORT
);
564 if (DeviceBase
== NULL
)
565 return MappedAddress
;
567 DeviceBase
->MappedAddress
= MappedAddress
;
568 DeviceBase
->NumberOfBytes
= NumberOfBytes
;
569 DeviceBase
->IoAddress
= IoAddress
;
570 DeviceBase
->BusNumber
= SystemIoBusNumber
;
572 /* Link it to the Device Extension list */
573 DeviceBase
->NextMappedAddress
= DeviceExtension
->MappedAddressList
;
574 DeviceExtension
->MappedAddressList
= DeviceBase
;
576 return MappedAddress
;
583 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
590 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
591 PSCSI_PORT_LUN_EXTENSION LunExtension
;
594 DPRINT("ScsiPortGetLogicalUnit() called\n");
596 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
597 SCSI_PORT_DEVICE_EXTENSION
,
598 MiniPortDeviceExtension
);
599 if (IsListEmpty(&DeviceExtension
->LunExtensionListHead
))
602 Entry
= DeviceExtension
->LunExtensionListHead
.Flink
;
603 while (Entry
!= &DeviceExtension
->LunExtensionListHead
)
605 LunExtension
= CONTAINING_RECORD(Entry
,
606 SCSI_PORT_LUN_EXTENSION
,
608 if (LunExtension
->PathId
== PathId
&&
609 LunExtension
->TargetId
== TargetId
&&
610 LunExtension
->Lun
== Lun
)
612 return (PVOID
)&LunExtension
->MiniportLunExtension
;
615 Entry
= Entry
->Flink
;
625 SCSI_PHYSICAL_ADDRESS NTAPI
626 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
627 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
628 IN PVOID VirtualAddress
,
631 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
632 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
633 ULONG BufferLength
= 0;
635 PSCSI_SG_ADDRESS SGList
;
636 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
638 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
639 HwDeviceExtension
, Srb
, VirtualAddress
, Length
);
641 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
642 SCSI_PORT_DEVICE_EXTENSION
,
643 MiniPortDeviceExtension
);
645 if (Srb
== NULL
|| Srb
->SenseInfoBuffer
== VirtualAddress
)
647 /* Simply look it up in the allocated common buffer */
648 Offset
= (PUCHAR
)VirtualAddress
- (PUCHAR
)DeviceExtension
->SrbExtensionBuffer
;
650 BufferLength
= DeviceExtension
->CommonBufferLength
- Offset
;
651 PhysicalAddress
.QuadPart
= DeviceExtension
->PhysicalAddress
.QuadPart
+ Offset
;
653 else if (DeviceExtension
->MapRegisters
)
655 /* Scatter-gather list must be used */
656 SrbInfo
= SpiGetSrbData(DeviceExtension
,
662 SGList
= SrbInfo
->ScatterGather
;
664 /* Find needed item in the SG list */
665 Offset
= (PCHAR
)VirtualAddress
- (PCHAR
)Srb
->DataBuffer
;
666 while (Offset
>= SGList
->Length
)
668 Offset
-= SGList
->Length
;
672 /* We're done, store length and physical address */
673 BufferLength
= SGList
->Length
- Offset
;
674 PhysicalAddress
.QuadPart
= SGList
->PhysicalAddress
.QuadPart
+ Offset
;
680 PhysicalAddress
.QuadPart
= (LONGLONG
)(SP_UNINITIALIZED_VALUE
);
683 *Length
= BufferLength
;
684 return PhysicalAddress
;
691 PSCSI_REQUEST_BLOCK NTAPI
692 ScsiPortGetSrb(IN PVOID DeviceExtension
,
698 DPRINT1("ScsiPortGetSrb() unimplemented\n");
708 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
709 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
710 IN ULONG NumberOfBytes
)
712 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
713 DEVICE_DESCRIPTION DeviceDescription
;
714 ULONG MapRegistersCount
;
717 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
718 HwDeviceExtension
, ConfigInfo
, NumberOfBytes
);
720 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
721 SCSI_PORT_DEVICE_EXTENSION
,
722 MiniPortDeviceExtension
);
724 /* Check for allocated common DMA buffer */
725 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
)
727 DPRINT1("The HBA has already got a common DMA buffer!\n");
731 /* Check for DMA adapter object */
732 if (DeviceExtension
->AdapterObject
== NULL
)
734 /* Initialize DMA adapter description */
735 RtlZeroMemory(&DeviceDescription
, sizeof(DEVICE_DESCRIPTION
));
737 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
738 DeviceDescription
.Master
= ConfigInfo
->Master
;
739 DeviceDescription
.ScatterGather
= ConfigInfo
->ScatterGather
;
740 DeviceDescription
.DemandMode
= ConfigInfo
->DemandMode
;
741 DeviceDescription
.Dma32BitAddresses
= ConfigInfo
->Dma32BitAddresses
;
742 DeviceDescription
.BusNumber
= ConfigInfo
->SystemIoBusNumber
;
743 DeviceDescription
.DmaChannel
= ConfigInfo
->DmaChannel
;
744 DeviceDescription
.InterfaceType
= ConfigInfo
->AdapterInterfaceType
;
745 DeviceDescription
.DmaWidth
= ConfigInfo
->DmaWidth
;
746 DeviceDescription
.DmaSpeed
= ConfigInfo
->DmaSpeed
;
747 DeviceDescription
.MaximumLength
= ConfigInfo
->MaximumTransferLength
;
748 DeviceDescription
.DmaPort
= ConfigInfo
->DmaPort
;
750 /* Get a DMA adapter object */
751 DeviceExtension
->AdapterObject
=
752 HalGetAdapter(&DeviceDescription
, &MapRegistersCount
);
754 /* Fail in case of error */
755 if (DeviceExtension
->AdapterObject
== NULL
)
757 DPRINT1("HalGetAdapter() failed\n");
761 /* Set number of physical breaks */
762 if (ConfigInfo
->NumberOfPhysicalBreaks
!= 0 &&
763 MapRegistersCount
> ConfigInfo
->NumberOfPhysicalBreaks
)
765 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
=
766 ConfigInfo
->NumberOfPhysicalBreaks
;
770 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
= MapRegistersCount
;
774 /* Update auto request sense feature */
775 DeviceExtension
->SupportsAutoSense
= ConfigInfo
->AutoRequestSense
;
777 /* Update Srb extension size */
778 if (DeviceExtension
->SrbExtensionSize
!= ConfigInfo
->SrbExtensionSize
)
779 DeviceExtension
->SrbExtensionSize
= ConfigInfo
->SrbExtensionSize
;
781 /* Update Srb extension alloc flag */
782 if (ConfigInfo
->AutoRequestSense
|| DeviceExtension
->SrbExtensionSize
)
783 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
785 /* Allocate a common DMA buffer */
786 Status
= SpiAllocateCommonBuffer(DeviceExtension
, NumberOfBytes
);
788 if (!NT_SUCCESS(Status
))
790 DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status
);
794 return DeviceExtension
->NonCachedExtension
;
798 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
)
800 PVOID
*SrbExtension
, CommonBuffer
;
801 ULONG CommonBufferLength
, BufSize
;
803 /* If size is 0, set it to 16 */
804 if (!DeviceExtension
->SrbExtensionSize
)
805 DeviceExtension
->SrbExtensionSize
= 16;
808 BufSize
= DeviceExtension
->SrbExtensionSize
;
810 /* Add autosense data size if needed */
811 if (DeviceExtension
->SupportsAutoSense
)
812 BufSize
+= sizeof(SENSE_DATA
);
816 BufSize
= (BufSize
+ sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
818 /* Sum up into the total common buffer length, and round it to page size */
820 ROUND_TO_PAGES(NonCachedSize
+ BufSize
* DeviceExtension
->RequestsNumber
);
823 if (!DeviceExtension
->AdapterObject
)
825 /* From nonpaged pool if there is no DMA */
826 CommonBuffer
= ExAllocatePoolWithTag(NonPagedPool
, CommonBufferLength
, TAG_SCSIPORT
);
830 /* Perform a full request since we have a DMA adapter*/
831 CommonBuffer
= HalAllocateCommonBuffer(DeviceExtension
->AdapterObject
,
833 &DeviceExtension
->PhysicalAddress
,
837 /* Fail in case of error */
839 return STATUS_INSUFFICIENT_RESOURCES
;
842 RtlZeroMemory(CommonBuffer
, CommonBufferLength
);
844 /* Store its size in Device Extension */
845 DeviceExtension
->CommonBufferLength
= CommonBufferLength
;
847 /* SrbExtension buffer is located at the beginning of the buffer */
848 DeviceExtension
->SrbExtensionBuffer
= CommonBuffer
;
850 /* Non-cached extension buffer is located at the end of
854 CommonBufferLength
-= NonCachedSize
;
855 DeviceExtension
->NonCachedExtension
= (PUCHAR
)CommonBuffer
+ CommonBufferLength
;
859 DeviceExtension
->NonCachedExtension
= NULL
;
862 if (DeviceExtension
->NeedSrbExtensionAlloc
)
864 /* Look up how many SRB data structures we need */
865 DeviceExtension
->SrbDataCount
= CommonBufferLength
/ BufSize
;
867 /* Initialize the free SRB extensions list */
868 SrbExtension
= (PVOID
*)CommonBuffer
;
869 DeviceExtension
->FreeSrbExtensions
= SrbExtension
;
871 /* Fill the remainding pointers (if we have more than 1 SRB) */
872 while (CommonBufferLength
>= 2 * BufSize
)
874 *SrbExtension
= (PVOID
*)((PCHAR
)SrbExtension
+ BufSize
);
875 SrbExtension
= *SrbExtension
;
877 CommonBufferLength
-= BufSize
;
881 return STATUS_SUCCESS
;
890 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
891 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
893 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
896 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
897 HwDeviceExtension
, PhysicalAddress
.QuadPart
);
899 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
900 SCSI_PORT_DEVICE_EXTENSION
,
901 MiniPortDeviceExtension
);
903 if (DeviceExtension
->PhysicalAddress
.QuadPart
> PhysicalAddress
.QuadPart
)
906 Offset
= (ULONG
)(PhysicalAddress
.QuadPart
- DeviceExtension
->PhysicalAddress
.QuadPart
);
908 if (Offset
>= DeviceExtension
->CommonBufferLength
)
911 return (PVOID
)((ULONG_PTR
)DeviceExtension
->SrbExtensionBuffer
+ Offset
);
915 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo
, PUNICODE_STRING RegistryPath
)
917 OBJECT_ATTRIBUTES ObjectAttributes
;
918 UNICODE_STRING KeyName
;
921 /* Open the service key */
922 InitializeObjectAttributes(&ObjectAttributes
,
924 OBJ_CASE_INSENSITIVE
,
928 Status
= ZwOpenKey(&ConfigInfo
->ServiceKey
,
932 if (!NT_SUCCESS(Status
))
934 DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath
, Status
);
935 ConfigInfo
->ServiceKey
= NULL
;
938 /* If we could open driver's service key, then proceed to the Parameters key */
939 if (ConfigInfo
->ServiceKey
!= NULL
)
941 RtlInitUnicodeString(&KeyName
, L
"Parameters");
942 InitializeObjectAttributes(&ObjectAttributes
,
944 OBJ_CASE_INSENSITIVE
,
945 ConfigInfo
->ServiceKey
,
946 (PSECURITY_DESCRIPTOR
) NULL
);
949 Status
= ZwOpenKey(&ConfigInfo
->DeviceKey
,
953 if (NT_SUCCESS(Status
))
955 /* Yes, Parameters key exist, and it must be used instead of
957 ZwClose(ConfigInfo
->ServiceKey
);
958 ConfigInfo
->ServiceKey
= ConfigInfo
->DeviceKey
;
959 ConfigInfo
->DeviceKey
= NULL
;
963 if (ConfigInfo
->ServiceKey
!= NULL
)
965 /* Open the Device key */
966 RtlInitUnicodeString(&KeyName
, L
"Device");
967 InitializeObjectAttributes(&ObjectAttributes
,
969 OBJ_CASE_INSENSITIVE
,
970 ConfigInfo
->ServiceKey
,
973 /* We don't check for failure here - not needed */
974 ZwOpenKey(&ConfigInfo
->DeviceKey
,
981 /**********************************************************************
986 * Initializes SCSI port driver specific data.
993 * Pointer to the miniport driver's driver object.
996 * Pointer to the miniport driver's registry path.
998 * HwInitializationData
999 * Pointer to port driver specific configuration data.
1002 Miniport driver specific context.
1011 ScsiPortInitialize(IN PVOID Argument1
,
1013 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
1016 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
1017 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
1018 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
1019 PCONFIGURATION_INFORMATION SystemConfig
;
1020 PPORT_CONFIGURATION_INFORMATION PortConfig
;
1021 PORT_CONFIGURATION_INFORMATION InitialPortConfig
;
1022 CONFIGURATION_INFO ConfigInfo
;
1023 ULONG DeviceExtensionSize
;
1024 ULONG PortConfigSize
;
1026 BOOLEAN DeviceFound
= FALSE
;
1027 BOOLEAN FirstConfigCall
= TRUE
;
1031 ULONG BusNumber
= 0;
1032 PCI_SLOT_NUMBER SlotNumber
;
1034 PDEVICE_OBJECT PortDeviceObject
;
1035 WCHAR NameBuffer
[80];
1036 UNICODE_STRING DeviceName
;
1037 WCHAR DosNameBuffer
[80];
1038 UNICODE_STRING DosDeviceName
;
1039 PIO_SCSI_CAPABILITIES PortCapabilities
;
1044 PCM_RESOURCE_LIST ResourceList
;
1048 DPRINT ("ScsiPortInitialize() called!\n");
1050 /* Check params for validity */
1051 if ((HwInitializationData
->HwInitialize
== NULL
) ||
1052 (HwInitializationData
->HwStartIo
== NULL
) ||
1053 (HwInitializationData
->HwInterrupt
== NULL
) ||
1054 (HwInitializationData
->HwFindAdapter
== NULL
) ||
1055 (HwInitializationData
->HwResetBus
== NULL
))
1057 return STATUS_INVALID_PARAMETER
;
1061 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
1062 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
1063 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
1064 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
1065 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
1066 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
1068 /* Obtain configuration information */
1069 SystemConfig
= IoGetConfigurationInformation();
1071 /* Zero the internal configuration info structure */
1072 RtlZeroMemory(&ConfigInfo
, sizeof(CONFIGURATION_INFO
));
1074 /* Zero starting slot number */
1075 SlotNumber
.u
.AsULONG
= 0;
1077 /* Allocate space for access ranges */
1078 if (HwInitializationData
->NumberOfAccessRanges
)
1080 ConfigInfo
.AccessRanges
=
1081 ExAllocatePoolWithTag(PagedPool
,
1082 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
), TAG_SCSIPORT
);
1084 /* Fail if failed */
1085 if (ConfigInfo
.AccessRanges
== NULL
)
1086 return STATUS_INSUFFICIENT_RESOURCES
;
1089 /* Open registry keys */
1090 SpiInitOpenKeys(&ConfigInfo
, (PUNICODE_STRING
)Argument2
);
1092 /* Last adapter number = not known */
1093 ConfigInfo
.LastAdapterNumber
= SP_UNINITIALIZED_VALUE
;
1095 /* Calculate sizes of DeviceExtension and PortConfig */
1096 DeviceExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
1097 HwInitializationData
->DeviceExtensionSize
;
1099 MaxBus
= (HwInitializationData
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
1100 DPRINT("MaxBus: %lu\n", MaxBus
);
1104 /* Create a unicode device name */
1105 swprintf(NameBuffer
,
1106 L
"\\Device\\ScsiPort%lu",
1107 SystemConfig
->ScsiPortCount
);
1108 RtlInitUnicodeString(&DeviceName
, NameBuffer
);
1110 DPRINT("Creating device: %wZ\n", &DeviceName
);
1112 /* Create the port device */
1113 Status
= IoCreateDevice(DriverObject
,
1114 DeviceExtensionSize
,
1116 FILE_DEVICE_CONTROLLER
,
1121 if (!NT_SUCCESS(Status
))
1123 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
1124 PortDeviceObject
= NULL
;
1128 DPRINT ("Created device: %wZ (%p)\n", &DeviceName
, PortDeviceObject
);
1130 /* Set the buffering strategy here... */
1131 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1132 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
; /* FIXME: Is this really needed? */
1134 /* Fill Device Extension */
1135 DeviceExtension
= PortDeviceObject
->DeviceExtension
;
1136 DeviceExtension
->Length
= DeviceExtensionSize
;
1137 DeviceExtension
->DeviceObject
= PortDeviceObject
;
1138 DeviceExtension
->PortNumber
= SystemConfig
->ScsiPortCount
;
1140 /* Driver's routines... */
1141 DeviceExtension
->HwInitialize
= HwInitializationData
->HwInitialize
;
1142 DeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
1143 DeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
1144 DeviceExtension
->HwResetBus
= HwInitializationData
->HwResetBus
;
1145 DeviceExtension
->HwDmaStarted
= HwInitializationData
->HwDmaStarted
;
1147 /* Extensions sizes */
1148 DeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
1149 DeviceExtension
->LunExtensionSize
= HwInitializationData
->SpecificLuExtensionSize
;
1150 DeviceExtension
->SrbExtensionSize
= HwInitializationData
->SrbExtensionSize
;
1152 /* Round Srb extension size to the quadword */
1153 DeviceExtension
->SrbExtensionSize
=
1154 ~(sizeof(LONGLONG
) - 1) & (DeviceExtension
->SrbExtensionSize
+
1155 sizeof(LONGLONG
) - 1);
1157 /* Fill some numbers (bus count, lun count, etc) */
1158 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
1159 DeviceExtension
->RequestsNumber
= 16;
1161 /* Initialize the spin lock in the controller extension */
1162 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1163 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
1165 /* Initialize the DPC object */
1166 IoInitializeDpcRequest(PortDeviceObject
,
1169 /* Initialize the device timer */
1170 DeviceExtension
->TimerCount
= -1;
1171 IoInitializeTimer(PortDeviceObject
,
1175 /* Initialize miniport timer */
1176 KeInitializeTimer(&DeviceExtension
->MiniportTimer
);
1177 KeInitializeDpc(&DeviceExtension
->MiniportTimerDpc
,
1178 SpiMiniportTimerDpc
,
1183 Status
= SpiCreatePortConfig(DeviceExtension
,
1184 HwInitializationData
,
1189 if (!NT_SUCCESS(Status
))
1191 DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status
);
1195 /* Allocate and initialize port configuration info */
1196 PortConfigSize
= (sizeof(PORT_CONFIGURATION_INFORMATION
) +
1197 HwInitializationData
->NumberOfAccessRanges
*
1198 sizeof(ACCESS_RANGE
) + 7) & ~7;
1199 DeviceExtension
->PortConfig
= ExAllocatePoolWithTag(NonPagedPool
, PortConfigSize
, TAG_SCSIPORT
);
1201 /* Fail if failed */
1202 if (DeviceExtension
->PortConfig
== NULL
)
1204 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1208 PortConfig
= DeviceExtension
->PortConfig
;
1210 /* Copy information here */
1211 RtlCopyMemory(PortConfig
,
1213 sizeof(PORT_CONFIGURATION_INFORMATION
));
1216 /* Copy extension sizes into the PortConfig */
1217 PortConfig
->SpecificLuExtensionSize
= DeviceExtension
->LunExtensionSize
;
1218 PortConfig
->SrbExtensionSize
= DeviceExtension
->SrbExtensionSize
;
1220 /* Initialize Access ranges */
1221 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1223 PortConfig
->AccessRanges
= (PVOID
)(PortConfig
+1);
1225 /* Align to LONGLONG */
1226 PortConfig
->AccessRanges
= (PVOID
)((ULONG_PTR
)(PortConfig
->AccessRanges
) + 7);
1227 PortConfig
->AccessRanges
= (PVOID
)((ULONG_PTR
)(PortConfig
->AccessRanges
) & ~7);
1230 RtlCopyMemory(PortConfig
->AccessRanges
,
1231 ConfigInfo
.AccessRanges
,
1232 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
1235 /* Search for matching PCI device */
1236 if ((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1237 (HwInitializationData
->VendorIdLength
> 0) &&
1238 (HwInitializationData
->VendorId
!= NULL
) &&
1239 (HwInitializationData
->DeviceIdLength
> 0) &&
1240 (HwInitializationData
->DeviceId
!= NULL
))
1242 PortConfig
->BusInterruptLevel
= 0;
1244 /* Get PCI device data */
1245 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1246 HwInitializationData
->VendorIdLength
,
1247 HwInitializationData
->VendorId
,
1248 HwInitializationData
->DeviceIdLength
,
1249 HwInitializationData
->DeviceId
);
1251 if (!SpiGetPciConfigData(DriverObject
,
1253 HwInitializationData
,
1256 ConfigInfo
.BusNumber
,
1259 /* Continue to the next bus, nothing here */
1260 ConfigInfo
.BusNumber
++;
1261 DeviceExtension
->PortConfig
= NULL
;
1262 ExFreePool(PortConfig
);
1264 goto CreatePortConfig
;
1267 if (!PortConfig
->BusInterruptLevel
)
1269 /* Bypass this slot, because no interrupt was assigned */
1270 DeviceExtension
->PortConfig
= NULL
;
1271 ExFreePool(PortConfig
);
1272 goto CreatePortConfig
;
1277 DPRINT("Non-pci bus\n");
1280 /* Note: HwFindAdapter is called once for each bus */
1282 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
1283 Result
= (HwInitializationData
->HwFindAdapter
)(&DeviceExtension
->MiniPortDeviceExtension
,
1285 0, /* BusInformation */
1286 ConfigInfo
.Parameter
, /* ArgumentString */
1290 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1291 Result
, (Again
) ? "True" : "False");
1293 /* Free MapRegisterBase, it's not needed anymore */
1294 if (DeviceExtension
->MapRegisterBase
!= NULL
)
1296 ExFreePool(DeviceExtension
->MapRegisterBase
);
1297 DeviceExtension
->MapRegisterBase
= NULL
;
1300 /* If result is nothing good... */
1301 if (Result
!= SP_RETURN_FOUND
)
1303 DPRINT("HwFindAdapter() Result: %lu\n", Result
);
1305 if (Result
== SP_RETURN_NOT_FOUND
)
1307 /* We can continue on the next bus */
1308 ConfigInfo
.BusNumber
++;
1311 DeviceExtension
->PortConfig
= NULL
;
1312 ExFreePool(PortConfig
);
1313 goto CreatePortConfig
;
1316 /* Otherwise, break */
1317 Status
= STATUS_INTERNAL_ERROR
;
1321 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1322 PortConfig
->BusInterruptVector
, PortConfig
->InitiatorBusId
[0]);
1324 /* If the SRB extension size was updated */
1325 if (!DeviceExtension
->NonCachedExtension
&&
1326 (PortConfig
->SrbExtensionSize
!= DeviceExtension
->SrbExtensionSize
))
1328 /* Set it (rounding to LONGLONG again) */
1329 DeviceExtension
->SrbExtensionSize
=
1330 (PortConfig
->SrbExtensionSize
+
1331 sizeof(LONGLONG
)) & ~(sizeof(LONGLONG
) - 1);
1334 /* The same with LUN extension size */
1335 if (PortConfig
->SpecificLuExtensionSize
!= DeviceExtension
->LunExtensionSize
)
1336 DeviceExtension
->LunExtensionSize
= PortConfig
->SpecificLuExtensionSize
;
1339 if (!((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1340 (HwInitializationData
->VendorIdLength
> 0) &&
1341 (HwInitializationData
->VendorId
!= NULL
) &&
1342 (HwInitializationData
->DeviceIdLength
> 0) &&
1343 (HwInitializationData
->DeviceId
!= NULL
)))
1345 /* Construct a resource list */
1346 ResourceList
= SpiConfigToResource(DeviceExtension
,
1351 UNICODE_STRING UnicodeString
;
1352 RtlInitUnicodeString(&UnicodeString
, L
"ScsiAdapter");
1353 DPRINT("Reporting resources\n");
1354 Status
= IoReportResourceUsage(&UnicodeString
,
1360 FIELD_OFFSET(CM_RESOURCE_LIST
,
1361 List
[0].PartialResourceList
.PartialDescriptors
) +
1362 ResourceList
->List
[0].PartialResourceList
.Count
1363 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
1366 ExFreePool(ResourceList
);
1368 /* In case of a failure or a conflict, break */
1369 if (Conflict
|| (!NT_SUCCESS(Status
)))
1372 Status
= STATUS_CONFLICTING_ADDRESSES
;
1378 /* Reset the Conflict var */
1381 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1382 if (PortConfig
->MaximumNumberOfTargets
> SCSI_MAXIMUM_TARGETS_PER_BUS
)
1383 DeviceExtension
->MaxTargedIds
= SCSI_MAXIMUM_TARGETS_PER_BUS
;
1385 DeviceExtension
->MaxTargedIds
= PortConfig
->MaximumNumberOfTargets
;
1387 DeviceExtension
->BusNum
= PortConfig
->NumberOfBuses
;
1388 DeviceExtension
->CachesData
= PortConfig
->CachesData
;
1389 DeviceExtension
->ReceiveEvent
= PortConfig
->ReceiveEvent
;
1390 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->TaggedQueuing
;
1391 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
;
1393 /* If something was disabled via registry - apply it */
1394 if (ConfigInfo
.DisableMultipleLun
)
1395 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1397 if (ConfigInfo
.DisableTaggedQueueing
)
1398 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1400 /* Check if we need to alloc SRB data */
1401 if (DeviceExtension
->SupportsTaggedQueuing
||
1402 DeviceExtension
->MultipleReqsPerLun
)
1404 DeviceExtension
->NeedSrbDataAlloc
= TRUE
;
1408 DeviceExtension
->NeedSrbDataAlloc
= FALSE
;
1411 /* Get a pointer to the port capabilities */
1412 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1414 /* Copy one field there */
1415 DeviceExtension
->MapBuffers
= PortConfig
->MapBuffers
;
1416 PortCapabilities
->AdapterUsesPio
= PortConfig
->MapBuffers
;
1418 if (DeviceExtension
->AdapterObject
== NULL
&&
1419 (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
|| PortConfig
->Master
))
1421 DPRINT1("DMA is not supported yet\n");
1425 if (DeviceExtension
->SrbExtensionBuffer
== NULL
&&
1426 (DeviceExtension
->SrbExtensionSize
!= 0 ||
1427 PortConfig
->AutoRequestSense
))
1429 DeviceExtension
->SupportsAutoSense
= PortConfig
->AutoRequestSense
;
1430 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
1432 /* Allocate common buffer */
1433 Status
= SpiAllocateCommonBuffer(DeviceExtension
, 0);
1435 /* Check for failure */
1436 if (!NT_SUCCESS(Status
))
1440 /* Allocate SrbData, if needed */
1441 if (DeviceExtension
->NeedSrbDataAlloc
)
1444 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1446 if (DeviceExtension
->SrbDataCount
!= 0)
1447 Count
= DeviceExtension
->SrbDataCount
;
1449 Count
= DeviceExtension
->RequestsNumber
* 2;
1451 /* Allocate the data */
1452 SrbData
= ExAllocatePoolWithTag(NonPagedPool
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
), TAG_SCSIPORT
);
1453 if (SrbData
== NULL
)
1454 return STATUS_INSUFFICIENT_RESOURCES
;
1456 RtlZeroMemory(SrbData
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
));
1458 DeviceExtension
->SrbInfo
= SrbData
;
1459 DeviceExtension
->FreeSrbInfo
= SrbData
;
1460 DeviceExtension
->SrbDataCount
= Count
;
1462 /* Link it to the list */
1465 SrbData
->Requests
.Flink
= (PLIST_ENTRY
)(SrbData
+ 1);
1470 /* Mark the last entry of the list */
1472 SrbData
->Requests
.Flink
= NULL
;
1475 /* Initialize port capabilities */
1476 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1477 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1478 PortCapabilities
->MaximumTransferLength
= PortConfig
->MaximumTransferLength
;
1480 if (PortConfig
->ReceiveEvent
)
1481 PortCapabilities
->SupportedAsynchronousEvents
|= SRBEV_SCSI_ASYNC_NOTIFICATION
;
1483 PortCapabilities
->TaggedQueuing
= DeviceExtension
->SupportsTaggedQueuing
;
1484 PortCapabilities
->AdapterScansDown
= PortConfig
->AdapterScansDown
;
1486 if (PortConfig
->AlignmentMask
> PortDeviceObject
->AlignmentRequirement
)
1487 PortDeviceObject
->AlignmentRequirement
= PortConfig
->AlignmentMask
;
1489 PortCapabilities
->AlignmentMask
= PortDeviceObject
->AlignmentRequirement
;
1491 if (PortCapabilities
->MaximumPhysicalPages
== 0)
1493 PortCapabilities
->MaximumPhysicalPages
=
1494 BYTES_TO_PAGES(PortCapabilities
->MaximumTransferLength
);
1496 /* Apply miniport's limits */
1497 if (PortConfig
->NumberOfPhysicalBreaks
< PortCapabilities
->MaximumPhysicalPages
)
1499 PortCapabilities
->MaximumPhysicalPages
= PortConfig
->NumberOfPhysicalBreaks
;
1503 /* Deal with interrupts */
1504 if (DeviceExtension
->HwInterrupt
== NULL
||
1505 (PortConfig
->BusInterruptLevel
== 0 && PortConfig
->BusInterruptVector
== 0))
1508 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1510 /* FIXME: Use synchronization routine */
1511 ASSERT("No interrupts branch requires changes in synchronization\n");
1513 DeviceExtension
->Interrupt
= (PVOID
)DeviceExtension
;
1514 DPRINT("No interrupts\n");
1519 /* Are 2 interrupts needed? */
1520 if (DeviceExtension
->HwInterrupt
!= NULL
&&
1521 (PortConfig
->BusInterruptLevel
!= 0 || PortConfig
->BusInterruptVector
!= 0) &&
1522 (PortConfig
->BusInterruptLevel2
!= 0 || PortConfig
->BusInterruptVector2
!= 0))
1524 DPRINT1("2 interrupts requested! Not yet supported\n");
1529 BOOLEAN InterruptShareable
;
1531 /* No, only 1 interrupt */
1532 DPRINT("1 interrupt, IRQ is %d\n", PortConfig
->BusInterruptLevel
);
1534 DeviceExtension
->InterruptLevel
= PortConfig
->BusInterruptLevel
;
1536 /* Register an interrupt handler for this device */
1537 MappedIrq
= HalGetInterruptVector(PortConfig
->AdapterInterfaceType
,
1538 PortConfig
->SystemIoBusNumber
,
1539 PortConfig
->BusInterruptLevel
,
1540 PortConfig
->BusInterruptVector
,
1544 /* Determing IRQ sharability as usual */
1545 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1546 PortConfig
->InterruptMode
== LevelSensitive
)
1548 InterruptShareable
= TRUE
;
1552 InterruptShareable
= FALSE
;
1555 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
,
1556 (PKSERVICE_ROUTINE
)ScsiPortIsr
,
1562 PortConfig
->InterruptMode
,
1567 if (!(NT_SUCCESS(Status
)))
1569 DPRINT1("Could not connect interrupt %d\n",
1570 PortConfig
->BusInterruptVector
);
1571 DeviceExtension
->Interrupt
= NULL
;
1578 /* Save IoAddress (from access ranges) */
1579 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1581 DeviceExtension
->IoAddress
=
1582 ((*(PortConfig
->AccessRanges
))[0]).RangeStart
.LowPart
;
1584 DPRINT("Io Address %x\n", DeviceExtension
->IoAddress
);
1587 /* Set flag that it's allowed to disconnect during this command */
1588 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
1590 /* Initialize counter of active requests (-1 means there are none) */
1591 DeviceExtension
->ActiveRequestCounter
= -1;
1593 /* Analyze what we have about DMA */
1594 if (DeviceExtension
->AdapterObject
!= NULL
&&
1595 PortConfig
->Master
&&
1596 PortConfig
->NeedPhysicalAddresses
)
1598 DeviceExtension
->MapRegisters
= TRUE
;
1602 DeviceExtension
->MapRegisters
= FALSE
;
1605 /* Call HwInitialize at DISPATCH_LEVEL */
1606 KeRaiseIrql(DISPATCH_LEVEL
, &Dirql
);
1608 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1609 DeviceExtension
->HwInitialize
,
1610 DeviceExtension
->MiniPortDeviceExtension
))
1612 DPRINT1("HwInitialize() failed!\n");
1614 Status
= STATUS_ADAPTER_HARDWARE_ERROR
;
1618 /* Check if a notification is needed */
1619 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
1621 /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1622 ScsiPortDpcForIsr(NULL
,
1623 DeviceExtension
->DeviceObject
,
1628 /* Lower irql back to what it was */
1631 /* Start our timer */
1632 IoStartTimer(PortDeviceObject
);
1634 /* Initialize bus scanning information */
1635 DeviceExtension
->BusesConfig
= ExAllocatePoolWithTag(PagedPool
,
1636 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1637 + sizeof(ULONG
), TAG_SCSIPORT
);
1639 if (!DeviceExtension
->BusesConfig
)
1641 DPRINT1("Out of resources!\n");
1642 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1647 RtlZeroMemory(DeviceExtension
->BusesConfig
,
1648 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1651 /* Store number of buses there */
1652 DeviceExtension
->BusesConfig
->NumberOfBuses
= (UCHAR
)DeviceExtension
->BusNum
;
1654 /* Scan the adapter for devices */
1655 SpiScanAdapter(DeviceExtension
);
1657 /* Build the registry device map */
1658 SpiBuildDeviceMap(DeviceExtension
,
1659 (PUNICODE_STRING
)Argument2
);
1661 /* Create the dos device link */
1662 swprintf(DosNameBuffer
,
1664 SystemConfig
->ScsiPortCount
);
1665 RtlInitUnicodeString(&DosDeviceName
, DosNameBuffer
);
1666 IoCreateSymbolicLink(&DosDeviceName
, &DeviceName
);
1668 /* Increase the port count */
1669 SystemConfig
->ScsiPortCount
++;
1670 FirstConfigCall
= FALSE
;
1672 /* Increase adapter number and bus number respectively */
1673 ConfigInfo
.AdapterNumber
++;
1676 ConfigInfo
.BusNumber
++;
1678 DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber
, MaxBus
);
1683 /* Clean up the mess */
1684 SpiCleanupAfterInit(DeviceExtension
);
1686 /* Close registry keys */
1687 if (ConfigInfo
.ServiceKey
!= NULL
)
1688 ZwClose(ConfigInfo
.ServiceKey
);
1690 if (ConfigInfo
.DeviceKey
!= NULL
)
1691 ZwClose(ConfigInfo
.DeviceKey
);
1693 if (ConfigInfo
.BusKey
!= NULL
)
1694 ZwClose(ConfigInfo
.BusKey
);
1696 if (ConfigInfo
.AccessRanges
!= NULL
)
1697 ExFreePool(ConfigInfo
.AccessRanges
);
1699 if (ConfigInfo
.Parameter
!= NULL
)
1700 ExFreePool(ConfigInfo
.Parameter
);
1702 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1703 Status
, DeviceFound
);
1705 return (DeviceFound
== FALSE
) ? Status
: STATUS_SUCCESS
;
1709 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1711 PSCSI_LUN_INFO LunInfo
;
1715 /* Check if we have something to clean up */
1716 if (DeviceExtension
== NULL
)
1719 /* Stop the timer and disconnect the interrupt */
1720 if (DeviceExtension
->Interrupt
)
1722 IoStopTimer(DeviceExtension
->DeviceObject
);
1723 IoDisconnectInterrupt(DeviceExtension
->Interrupt
);
1726 /* Delete ConfigInfo */
1727 if (DeviceExtension
->BusesConfig
)
1729 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
1731 if (!DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
])
1734 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
1738 /* Free current, but save pointer to the next one */
1739 Ptr
= LunInfo
->Next
;
1740 ExFreePool(LunInfo
);
1744 ExFreePool(DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]);
1747 ExFreePool(DeviceExtension
->BusesConfig
);
1750 /* Free PortConfig */
1751 if (DeviceExtension
->PortConfig
)
1752 ExFreePool(DeviceExtension
->PortConfig
);
1755 for(Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
1757 while (DeviceExtension
->LunExtensionList
[Lun
])
1759 Ptr
= DeviceExtension
->LunExtensionList
[Lun
];
1760 DeviceExtension
->LunExtensionList
[Lun
] = DeviceExtension
->LunExtensionList
[Lun
]->Next
;
1766 /* Free common buffer (if it exists) */
1767 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
&&
1768 DeviceExtension
->CommonBufferLength
!= 0)
1770 if (!DeviceExtension
->AdapterObject
)
1772 ExFreePool(DeviceExtension
->SrbExtensionBuffer
);
1776 HalFreeCommonBuffer(DeviceExtension
->AdapterObject
,
1777 DeviceExtension
->CommonBufferLength
,
1778 DeviceExtension
->PhysicalAddress
,
1779 DeviceExtension
->SrbExtensionBuffer
,
1785 if (DeviceExtension
->SrbInfo
!= NULL
)
1786 ExFreePool(DeviceExtension
->SrbInfo
);
1788 /* Unmap mapped addresses */
1789 while (DeviceExtension
->MappedAddressList
!= NULL
)
1791 MmUnmapIoSpace(DeviceExtension
->MappedAddressList
->MappedAddress
,
1792 DeviceExtension
->MappedAddressList
->NumberOfBytes
);
1794 Ptr
= DeviceExtension
->MappedAddressList
;
1795 DeviceExtension
->MappedAddressList
= DeviceExtension
->MappedAddressList
->NextMappedAddress
;
1800 /* Finally delete the device object */
1801 DPRINT("Deleting device %p\n", DeviceExtension
->DeviceObject
);
1802 IoDeleteDevice(DeviceExtension
->DeviceObject
);
1809 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
1810 IN PSCSI_REQUEST_BLOCK Srb
,
1811 IN PVOID LogicalAddress
,
1814 DPRINT1("ScsiPortIoMapTransfer()\n");
1822 ScsiPortLogError(IN PVOID HwDeviceExtension
,
1823 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
1830 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1832 DPRINT1("ScsiPortLogError() called\n");
1834 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1835 SCSI_PORT_DEVICE_EXTENSION
,
1836 MiniPortDeviceExtension
);
1839 DPRINT("ScsiPortLogError() done\n");
1846 ScsiPortMoveMemory(OUT PVOID Destination
,
1850 RtlMoveMemory(Destination
,
1860 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
1861 IN PVOID HwDeviceExtension
,
1864 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1867 DPRINT("ScsiPortNotification() called\n");
1869 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1870 SCSI_PORT_DEVICE_EXTENSION
,
1871 MiniPortDeviceExtension
);
1873 DPRINT("DeviceExtension %p\n", DeviceExtension
);
1875 va_start(ap
, HwDeviceExtension
);
1877 switch (NotificationType
)
1879 case RequestComplete
:
1881 PSCSI_REQUEST_BLOCK Srb
;
1882 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1884 Srb
= (PSCSI_REQUEST_BLOCK
) va_arg (ap
, PSCSI_REQUEST_BLOCK
);
1886 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb
);
1888 /* Make sure Srb is allright */
1889 ASSERT(Srb
->SrbStatus
!= SRB_STATUS_PENDING
);
1890 ASSERT(Srb
->Function
!= SRB_FUNCTION_EXECUTE_SCSI
|| Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
|| Srb
->ScsiStatus
== SCSISTAT_GOOD
);
1892 if (!(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
1894 /* It's been already completed */
1899 /* It's not active anymore */
1900 Srb
->SrbFlags
&= ~SRB_FLAGS_IS_ACTIVE
;
1902 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
1904 /* TODO: Treat it specially */
1909 /* Get the SRB data */
1910 SrbData
= SpiGetSrbData(DeviceExtension
,
1916 /* Make sure there are no CompletedRequests and there is a Srb */
1917 ASSERT(SrbData
->CompletedRequests
== NULL
&& SrbData
->Srb
!= NULL
);
1919 /* If it's a read/write request, make sure it has data inside it */
1920 if ((Srb
->SrbStatus
== SRB_STATUS_SUCCESS
) &&
1921 ((Srb
->Cdb
[0] == SCSIOP_READ
) || (Srb
->Cdb
[0] == SCSIOP_WRITE
)))
1923 ASSERT(Srb
->DataTransferLength
);
1926 SrbData
->CompletedRequests
= DeviceExtension
->InterruptData
.CompletedRequests
;
1927 DeviceExtension
->InterruptData
.CompletedRequests
= SrbData
;
1933 DPRINT("Notify: NextRequest\n");
1934 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1942 PSCSI_PORT_LUN_EXTENSION LunExtension
;
1944 PathId
= (UCHAR
) va_arg (ap
, int);
1945 TargetId
= (UCHAR
) va_arg (ap
, int);
1946 Lun
= (UCHAR
) va_arg (ap
, int);
1948 DPRINT("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1949 PathId
, TargetId
, Lun
);
1951 /* Mark it in the flags field */
1952 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1954 /* Get the LUN extension */
1955 LunExtension
= SpiGetLunExtension(DeviceExtension
,
1960 /* If returned LunExtension is NULL, break out */
1961 if (!LunExtension
) break;
1963 /* This request should not be processed if */
1964 if ((LunExtension
->ReadyLun
) ||
1965 (LunExtension
->SrbInfo
.Srb
))
1967 /* Nothing to do here */
1971 /* Add this LUN to the list */
1972 LunExtension
->ReadyLun
= DeviceExtension
->InterruptData
.ReadyLun
;
1973 DeviceExtension
->InterruptData
.ReadyLun
= LunExtension
;
1978 DPRINT("Notify: ResetDetected\n");
1979 /* Add RESET flags */
1980 DeviceExtension
->InterruptData
.Flags
|=
1981 SCSI_PORT_RESET
| SCSI_PORT_RESET_REPORTED
;
1984 case CallDisableInterrupts
:
1985 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
1988 case CallEnableInterrupts
:
1989 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
1992 case RequestTimerCall
:
1993 DPRINT1("UNIMPLEMENTED SCSI Notification called: RequestTimerCall!\n");
1996 case BusChangeDetected
:
1997 DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
2001 DPRINT1 ("Unsupported notification from WMI: %lu\n", NotificationType
);
2007 /* Request a DPC after we're done with the interrupt */
2008 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NOTIFICATION_NEEDED
;
2015 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
2016 IN INTERFACE_TYPE BusType
,
2017 IN ULONG SystemIoBusNumber
,
2018 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
2019 IN ULONG NumberOfBytes
,
2020 IN BOOLEAN InIoSpace
)
2022 DPRINT("ScsiPortValidateRange()\n");
2027 /* INTERNAL FUNCTIONS ********************************************************/
2030 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
2031 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
2032 IN PPORT_CONFIGURATION_INFORMATION PortConfig
)
2034 PACCESS_RANGE AccessRange
;
2035 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData
;
2041 /* Loop through all entries */
2042 for (Index
= 0; Index
< ResourceDescriptor
->PartialResourceList
.Count
; Index
++)
2044 PartialData
= &ResourceDescriptor
->PartialResourceList
.PartialDescriptors
[Index
];
2046 switch (PartialData
->Type
)
2048 case CmResourceTypePort
:
2049 /* Copy access ranges */
2050 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
2052 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
2054 AccessRange
->RangeStart
= PartialData
->u
.Port
.Start
;
2055 AccessRange
->RangeLength
= PartialData
->u
.Port
.Length
;
2057 AccessRange
->RangeInMemory
= FALSE
;
2062 case CmResourceTypeMemory
:
2063 /* Copy access ranges */
2064 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
2066 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
2068 AccessRange
->RangeStart
= PartialData
->u
.Memory
.Start
;
2069 AccessRange
->RangeLength
= PartialData
->u
.Memory
.Length
;
2071 AccessRange
->RangeInMemory
= TRUE
;
2076 case CmResourceTypeInterrupt
:
2077 /* Copy interrupt data */
2078 PortConfig
->BusInterruptLevel
= PartialData
->u
.Interrupt
.Level
;
2079 PortConfig
->BusInterruptVector
= PartialData
->u
.Interrupt
.Vector
;
2081 /* Set interrupt mode accordingly to the resource */
2082 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
2084 PortConfig
->InterruptMode
= Latched
;
2086 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
2088 PortConfig
->InterruptMode
= LevelSensitive
;
2092 case CmResourceTypeDma
:
2093 PortConfig
->DmaChannel
= PartialData
->u
.Dma
.Channel
;
2094 PortConfig
->DmaPort
= PartialData
->u
.Dma
.Port
;
2100 static PCM_RESOURCE_LIST
2101 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2102 PPORT_CONFIGURATION_INFORMATION PortConfig
)
2104 PCONFIGURATION_INFORMATION ConfigInfo
;
2105 PCM_RESOURCE_LIST ResourceList
;
2106 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
2107 PACCESS_RANGE AccessRange
;
2109 ULONG ListLength
= 0, i
, FullSize
;
2112 /* Get current Atdisk usage from the system */
2113 ConfigInfo
= IoGetConfigurationInformation();
2115 if (PortConfig
->AtdiskPrimaryClaimed
)
2116 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
2118 if (PortConfig
->AtdiskSecondaryClaimed
)
2119 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
2121 /* Do we use DMA? */
2122 if (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
||
2123 PortConfig
->DmaPort
!= SP_UNINITIALIZED_VALUE
)
2133 /* How many interrupts to we have? */
2134 if (DeviceExtension
->HwInterrupt
== NULL
||
2135 (PortConfig
->BusInterruptLevel
== 0 &&
2136 PortConfig
->BusInterruptVector
== 0))
2146 if (DeviceExtension
->HwInterrupt
!= NULL
&&
2147 (PortConfig
->BusInterruptLevel2
!= 0 ||
2148 PortConfig
->BusInterruptVector2
!= 0))
2154 /* How many access ranges do we use? */
2155 AccessRange
= &((*(PortConfig
->AccessRanges
))[0]);
2156 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2158 if (AccessRange
->RangeLength
!= 0)
2164 /* Allocate the resource list, since we know its size now */
2165 FullSize
= sizeof(CM_RESOURCE_LIST
) + (ListLength
- 1) *
2166 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
2168 ResourceList
= (PCM_RESOURCE_LIST
)ExAllocatePoolWithTag(PagedPool
, FullSize
, TAG_SCSIPORT
);
2174 RtlZeroMemory(ResourceList
, FullSize
);
2177 ResourceList
->Count
= 1;
2178 ResourceList
->List
[0].InterfaceType
= PortConfig
->AdapterInterfaceType
;
2179 ResourceList
->List
[0].BusNumber
= PortConfig
->SystemIoBusNumber
;
2180 ResourceList
->List
[0].PartialResourceList
.Count
= ListLength
;
2181 ResourceDescriptor
= ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
;
2183 /* Copy access ranges array over */
2184 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2186 AccessRange
= &((*(PortConfig
->AccessRanges
))[i
]);
2188 /* If the range is empty - skip it */
2189 if (AccessRange
->RangeLength
== 0)
2192 if (AccessRange
->RangeInMemory
)
2194 ResourceDescriptor
->Type
= CmResourceTypeMemory
;
2195 ResourceDescriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
;
2199 ResourceDescriptor
->Type
= CmResourceTypePort
;
2200 ResourceDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
2203 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2205 ResourceDescriptor
->u
.Memory
.Start
= AccessRange
->RangeStart
;
2206 ResourceDescriptor
->u
.Memory
.Length
= AccessRange
->RangeLength
;
2208 ResourceDescriptor
++;
2211 /* If we use interrupt(s), copy them */
2214 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2216 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2217 PortConfig
->InterruptMode
== LevelSensitive
)
2219 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2220 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2224 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2225 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2228 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
2229 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
2230 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2232 ResourceDescriptor
++;
2236 /* Copy 2nd interrupt
2237 FIXME: Stupid code duplication, remove */
2240 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2242 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2243 PortConfig
->InterruptMode
== LevelSensitive
)
2245 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2246 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2250 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2251 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2254 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
2255 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
2256 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2258 ResourceDescriptor
++;
2264 ResourceDescriptor
->Type
= CmResourceTypeDma
;
2265 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2266 ResourceDescriptor
->u
.Dma
.Channel
= PortConfig
->DmaChannel
;
2267 ResourceDescriptor
->u
.Dma
.Port
= PortConfig
->DmaPort
;
2268 ResourceDescriptor
->Flags
= 0;
2270 if (PortConfig
->DmaChannel
== SP_UNINITIALIZED_VALUE
)
2271 ResourceDescriptor
->u
.Dma
.Channel
= 0;
2273 if (PortConfig
->DmaPort
== SP_UNINITIALIZED_VALUE
)
2274 ResourceDescriptor
->u
.Dma
.Port
= 0;
2277 return ResourceList
;
2282 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
2283 IN PDEVICE_OBJECT DeviceObject
,
2284 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
2285 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
2286 IN PUNICODE_STRING RegistryPath
,
2288 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
)
2290 PCI_COMMON_CONFIG PciConfig
;
2291 PCI_SLOT_NUMBER SlotNumber
;
2294 ULONG FunctionNumber
;
2295 CHAR VendorIdString
[8];
2296 CHAR DeviceIdString
[8];
2297 UNICODE_STRING UnicodeStr
;
2298 PCM_RESOURCE_LIST ResourceList
;
2301 DPRINT ("SpiGetPciConfiguration() called\n");
2303 RtlZeroMemory(&ResourceList
, sizeof(PCM_RESOURCE_LIST
));
2304 SlotNumber
.u
.AsULONG
= 0;
2306 /* Loop through all devices */
2307 for (DeviceNumber
= NextSlotNumber
->u
.bits
.DeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
2309 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
2311 /* Loop through all functions */
2312 for (FunctionNumber
= NextSlotNumber
->u
.bits
.FunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
2314 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
2316 /* Get PCI config bytes */
2317 DataSize
= HalGetBusData(PCIConfiguration
,
2319 SlotNumber
.u
.AsULONG
,
2323 /* If result of HalGetBusData is 0, then the bus is wrong */
2327 /* If result is PCI_INVALID_VENDORID, then this device has no more
2329 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
2332 sprintf (VendorIdString
, "%04hx", PciConfig
.VendorID
);
2333 sprintf (DeviceIdString
, "%04hx", PciConfig
.DeviceID
);
2335 if (_strnicmp(VendorIdString
, HwInitializationData
->VendorId
, HwInitializationData
->VendorIdLength
) ||
2336 _strnicmp(DeviceIdString
, HwInitializationData
->DeviceId
, HwInitializationData
->DeviceIdLength
))
2338 /* It is not our device */
2342 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2346 SlotNumber
.u
.bits
.DeviceNumber
,
2347 SlotNumber
.u
.bits
.FunctionNumber
);
2350 RtlInitUnicodeString(&UnicodeStr
, L
"ScsiAdapter");
2351 Status
= HalAssignSlotResources(RegistryPath
,
2357 SlotNumber
.u
.AsULONG
,
2360 if (!NT_SUCCESS(Status
))
2363 /* Create configuration information */
2364 SpiResourceToConfig(HwInitializationData
,
2368 /* Free the resource list */
2369 ExFreePool(ResourceList
);
2371 /* Set dev & fn numbers */
2372 NextSlotNumber
->u
.bits
.DeviceNumber
= DeviceNumber
;
2373 NextSlotNumber
->u
.bits
.FunctionNumber
= FunctionNumber
+ 1;
2375 /* Save the slot number */
2376 PortConfig
->SlotNumber
= SlotNumber
.u
.AsULONG
;
2380 NextSlotNumber
->u
.bits
.FunctionNumber
= 0;
2383 NextSlotNumber
->u
.bits
.DeviceNumber
= 0;
2384 DPRINT ("No device found\n");
2391 /**********************************************************************
2393 * ScsiPortCreateClose
2396 * Answer requests for Create/Close calls: a null operation.
2403 * Pointer to a device object.
2406 * Pointer to an IRP.
2412 static NTSTATUS NTAPI
2413 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
2416 DPRINT("ScsiPortCreateClose()\n");
2418 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2419 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2421 return STATUS_SUCCESS
;
2425 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2428 PSCSI_LUN_INFO LunInfo
;
2429 PIO_STACK_LOCATION IrpStack
;
2430 PDEVICE_OBJECT DeviceObject
;
2431 PSCSI_REQUEST_BLOCK Srb
;
2434 /* Get pointer to the SRB */
2435 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2436 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
2438 /* Check if PathId matches number of buses */
2439 if (DeviceExtension
->BusesConfig
== NULL
||
2440 DeviceExtension
->BusesConfig
->NumberOfBuses
<= Srb
->PathId
)
2442 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2443 return STATUS_DEVICE_DOES_NOT_EXIST
;
2446 /* Get pointer to LunInfo */
2447 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Srb
->PathId
]->LunInfo
;
2449 /* Find matching LunInfo */
2452 if (LunInfo
->PathId
== Srb
->PathId
&&
2453 LunInfo
->TargetId
== Srb
->TargetId
&&
2454 LunInfo
->Lun
== Srb
->Lun
)
2459 LunInfo
= LunInfo
->Next
;
2462 /* If we couldn't find it - exit */
2463 if (LunInfo
== NULL
)
2464 return STATUS_DEVICE_DOES_NOT_EXIST
;
2468 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2470 /* Release, if asked */
2471 if (Srb
->Function
== SRB_FUNCTION_RELEASE_DEVICE
)
2473 LunInfo
->DeviceClaimed
= FALSE
;
2474 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2475 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2477 return STATUS_SUCCESS
;
2480 /* Attach, if not already claimed */
2481 if (LunInfo
->DeviceClaimed
)
2483 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2484 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
2486 return STATUS_DEVICE_BUSY
;
2489 /* Save the device object */
2490 DeviceObject
= LunInfo
->DeviceObject
;
2492 if (Srb
->Function
== SRB_FUNCTION_CLAIM_DEVICE
)
2493 LunInfo
->DeviceClaimed
= TRUE
;
2495 if (Srb
->Function
== SRB_FUNCTION_ATTACH_DEVICE
)
2496 LunInfo
->DeviceObject
= Srb
->DataBuffer
;
2498 Srb
->DataBuffer
= DeviceObject
;
2500 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2501 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2503 return STATUS_SUCCESS
;
2507 /**********************************************************************
2509 * ScsiPortDispatchScsi
2512 * Answer requests for SCSI calls
2518 * Standard dispatch arguments
2524 static NTSTATUS NTAPI
2525 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
2528 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2529 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2530 PIO_STACK_LOCATION Stack
;
2531 PSCSI_REQUEST_BLOCK Srb
;
2533 NTSTATUS Status
= STATUS_SUCCESS
;
2534 PIRP NextIrp
, IrpList
;
2535 PKDEVICE_QUEUE_ENTRY Entry
;
2537 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2540 DeviceExtension
= DeviceObject
->DeviceExtension
;
2541 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2543 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2546 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2547 Status
= STATUS_UNSUCCESSFUL
;
2549 Irp
->IoStatus
.Status
= Status
;
2550 Irp
->IoStatus
.Information
= 0;
2552 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2557 DPRINT("Srb: %p\n", Srb
);
2558 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
2559 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
2561 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2565 if (LunExtension
== NULL
)
2567 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2568 Status
= STATUS_NO_SUCH_DEVICE
;
2570 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2571 Irp
->IoStatus
.Status
= Status
;
2572 Irp
->IoStatus
.Information
= 0;
2574 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2579 switch (Srb
->Function
)
2581 case SRB_FUNCTION_SHUTDOWN
:
2582 case SRB_FUNCTION_FLUSH
:
2583 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2584 if (DeviceExtension
->CachesData
== FALSE
)
2586 /* All success here */
2587 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2588 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2589 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2590 return STATUS_SUCCESS
;
2592 /* Fall through to a usual execute operation */
2594 case SRB_FUNCTION_EXECUTE_SCSI
:
2595 case SRB_FUNCTION_IO_CONTROL
:
2596 /* Mark IRP as pending in all cases */
2597 IoMarkIrpPending(Irp
);
2599 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2601 /* Start IO directly */
2602 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2608 /* We need to be at DISPATCH_LEVEL */
2609 KeRaiseIrql (DISPATCH_LEVEL
, &oldIrql
);
2611 /* Insert IRP into the queue */
2612 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
2613 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
2616 /* It means the queue is empty, and we just start this request */
2617 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2620 /* Back to the old IRQL */
2621 KeLowerIrql (oldIrql
);
2623 return STATUS_PENDING
;
2625 case SRB_FUNCTION_CLAIM_DEVICE
:
2626 case SRB_FUNCTION_ATTACH_DEVICE
:
2627 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2629 /* Reference device object and keep the device object */
2630 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2633 case SRB_FUNCTION_RELEASE_DEVICE
:
2634 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2636 /* Dereference device object and clear the device object */
2637 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2640 case SRB_FUNCTION_RELEASE_QUEUE
:
2641 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2643 /* Guard with the spinlock */
2644 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2646 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2648 DPRINT("Queue is not frozen really\n");
2650 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2651 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2652 Status
= STATUS_SUCCESS
;
2657 /* Unfreeze the queue */
2658 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2660 if (LunExtension
->SrbInfo
.Srb
== NULL
)
2662 /* Get next logical unit request */
2663 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
2665 /* SpiGetNextRequestFromLun() releases the spinlock */
2670 DPRINT("The queue has active request\n");
2671 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2675 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2676 Status
= STATUS_SUCCESS
;
2679 case SRB_FUNCTION_FLUSH_QUEUE
:
2680 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2682 /* Guard with the spinlock */
2683 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2685 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2687 DPRINT("Queue is not frozen really\n");
2689 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2690 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2694 /* Make sure there is no active request */
2695 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
2697 /* Compile a list from the device queue */
2699 while ((Entry
= KeRemoveDeviceQueue(&LunExtension
->DeviceQueue
)) != NULL
)
2701 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
2704 Stack
= IoGetCurrentIrpStackLocation(NextIrp
);
2705 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2708 Srb
->SrbStatus
= SRB_STATUS_REQUEST_FLUSHED
;
2709 NextIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2711 /* Add then to the list */
2712 NextIrp
->Tail
.Overlay
.ListEntry
.Flink
= (PLIST_ENTRY
)IrpList
;
2716 /* Unfreeze the queue */
2717 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2719 /* Release the spinlock */
2720 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2722 /* Complete those requests */
2726 IrpList
= (PIRP
)NextIrp
->Tail
.Overlay
.ListEntry
.Flink
;
2728 IoCompleteRequest(NextIrp
, 0);
2731 Status
= STATUS_SUCCESS
;
2735 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
2736 Status
= STATUS_NOT_IMPLEMENTED
;
2740 Irp
->IoStatus
.Status
= Status
;
2742 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2748 /**********************************************************************
2750 * ScsiPortDeviceControl
2753 * Answer requests for device control calls
2759 * Standard dispatch arguments
2765 static NTSTATUS NTAPI
2766 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
2769 PIO_STACK_LOCATION Stack
;
2770 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2771 NTSTATUS Status
= STATUS_SUCCESS
;
2773 DPRINT("ScsiPortDeviceControl()\n");
2775 Irp
->IoStatus
.Information
= 0;
2777 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2778 DeviceExtension
= DeviceObject
->DeviceExtension
;
2780 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
2782 case IOCTL_SCSI_GET_DUMP_POINTERS
:
2784 PDUMP_POINTERS DumpPointers
;
2785 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2786 DumpPointers
= (PDUMP_POINTERS
)Irp
->AssociatedIrp
.SystemBuffer
;
2787 DumpPointers
->DeviceObject
= DeviceObject
;
2789 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2793 case IOCTL_SCSI_GET_CAPABILITIES
:
2794 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2795 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
== sizeof(PVOID
))
2797 *((PVOID
*)Irp
->AssociatedIrp
.SystemBuffer
) = &DeviceExtension
->PortCapabilities
;
2799 Irp
->IoStatus
.Information
= sizeof(PVOID
);
2800 Status
= STATUS_SUCCESS
;
2804 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(IO_SCSI_CAPABILITIES
))
2806 Status
= STATUS_BUFFER_TOO_SMALL
;
2810 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2811 &DeviceExtension
->PortCapabilities
,
2812 sizeof(IO_SCSI_CAPABILITIES
));
2814 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
2815 Status
= STATUS_SUCCESS
;
2818 case IOCTL_SCSI_GET_INQUIRY_DATA
:
2819 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2821 /* Copy inquiry data to the port device extension */
2822 Status
= SpiGetInquiryData(DeviceExtension
, Irp
);
2825 case IOCTL_SCSI_MINIPORT
:
2826 DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
2829 case IOCTL_SCSI_PASS_THROUGH
:
2830 DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
2834 DPRINT1(" unknown ioctl code: 0x%lX\n",
2835 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2839 /* Complete the request with the given status */
2840 Irp
->IoStatus
.Status
= Status
;
2841 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2848 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
2851 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2852 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2853 PIO_STACK_LOCATION IrpStack
;
2854 PSCSI_REQUEST_BLOCK Srb
;
2855 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2859 DPRINT("ScsiPortStartIo() called!\n");
2861 DeviceExtension
= DeviceObject
->DeviceExtension
;
2862 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2864 DPRINT("DeviceExtension %p\n", DeviceExtension
);
2866 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2868 /* Apply "default" flags */
2869 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
2871 /* Get LUN extension */
2872 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2877 if (DeviceExtension
->NeedSrbDataAlloc
||
2878 DeviceExtension
->NeedSrbExtensionAlloc
)
2881 SrbInfo
= SpiAllocateSrbStructures(DeviceExtension
,
2885 /* Couldn't alloc one or both data structures, return */
2886 if (SrbInfo
== NULL
)
2888 /* We have to call IoStartNextPacket, because this request
2890 if (LunExtension
->Flags
& LUNEX_REQUEST_PENDING
)
2891 IoStartNextPacket(DeviceObject
, FALSE
);
2898 /* No allocations are needed */
2899 SrbInfo
= &LunExtension
->SrbInfo
;
2900 Srb
->SrbExtension
= NULL
;
2901 Srb
->QueueTag
= SP_UNTAGGED
;
2904 /* Increase sequence number of SRB */
2905 if (!SrbInfo
->SequenceNumber
)
2907 /* Increase global sequence number */
2908 DeviceExtension
->SequenceNumber
++;
2911 SrbInfo
->SequenceNumber
= DeviceExtension
->SequenceNumber
;
2914 /* Check some special SRBs */
2915 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2917 /* Some special handling */
2918 DPRINT1("Abort command! Unimplemented now\n");
2925 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
)
2927 // Store the MDL virtual address in SrbInfo structure
2928 SrbInfo
->DataOffset
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2930 if (DeviceExtension
->MapBuffers
)
2932 /* Calculate offset within DataBuffer */
2933 SrbInfo
->DataOffset
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
2934 Srb
->DataBuffer
= SrbInfo
->DataOffset
+
2935 (ULONG
)((PUCHAR
)Srb
->DataBuffer
-
2936 (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2939 if (DeviceExtension
->AdapterObject
)
2942 KeFlushIoBuffers(Irp
->MdlAddress
,
2943 Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? TRUE
: FALSE
,
2947 if (DeviceExtension
->MapRegisters
)
2949 /* Calculate number of needed map registers */
2950 SrbInfo
->NumberOfMapRegisters
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
2952 Srb
->DataTransferLength
);
2954 /* Allocate adapter channel */
2955 Status
= IoAllocateAdapterChannel(DeviceExtension
->AdapterObject
,
2956 DeviceExtension
->DeviceObject
,
2957 SrbInfo
->NumberOfMapRegisters
,
2961 if (!NT_SUCCESS(Status
))
2963 DPRINT1("IoAllocateAdapterChannel() failed!\n");
2965 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
2966 ScsiPortNotification(RequestComplete
,
2967 DeviceExtension
+ 1,
2970 ScsiPortNotification(NextRequest
,
2971 DeviceExtension
+ 1);
2973 /* Request DPC for that work */
2974 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2977 /* Control goes to SpiAdapterControl */
2982 /* Increase active request counter */
2983 CounterResult
= InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
2985 if (CounterResult
== 0 &&
2986 DeviceExtension
->AdapterObject
!= NULL
&&
2987 !DeviceExtension
->MapRegisters
)
2989 IoAllocateAdapterChannel(
2990 DeviceExtension
->AdapterObject
,
2992 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
,
2993 ScsiPortAllocateAdapterChannel
,
3000 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3002 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
3003 ScsiPortStartPacket
,
3006 DPRINT("Synchronization failed!\n");
3008 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3009 Irp
->IoStatus
.Information
= 0;
3010 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3012 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3016 /* Release the spinlock only */
3017 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3021 DPRINT("ScsiPortStartIo() done\n");
3025 static BOOLEAN NTAPI
3026 ScsiPortStartPacket(IN OUT PVOID Context
)
3028 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3029 PIO_STACK_LOCATION IrpStack
;
3030 PSCSI_REQUEST_BLOCK Srb
;
3031 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)Context
;
3032 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3033 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3037 DPRINT("ScsiPortStartPacket() called\n");
3039 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3041 IrpStack
= IoGetCurrentIrpStackLocation(DeviceObject
->CurrentIrp
);
3042 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
3044 /* Get LUN extension */
3045 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3050 /* Check if we are in a reset state */
3051 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
3053 /* Mark the we've got requests while being in the reset state */
3054 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET_REQUEST
;
3058 /* Set the time out value */
3059 DeviceExtension
->TimerCount
= Srb
->TimeOutValue
;
3062 DeviceExtension
->Flags
|= SCSI_PORT_DEVICE_BUSY
;
3064 if (LunExtension
->RequestTimeout
!= -1)
3066 /* Timer already active */
3071 /* It hasn't been initialized yet */
3072 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
3076 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
3078 /* Handle bypass-requests */
3080 /* Is this an abort request? */
3081 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
3083 /* Get pointer to SRB info structure */
3084 SrbInfo
= SpiGetSrbData(DeviceExtension
,
3090 /* Check if the request is still "active" */
3091 if (SrbInfo
== NULL
||
3092 SrbInfo
->Srb
== NULL
||
3093 !(SrbInfo
->Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
3095 /* It's not, mark it as active then */
3096 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
3099 LunExtension
->RequestTimeout
= -1;
3101 DPRINT("Request has been already completed, but abort request came\n");
3102 Srb
->SrbStatus
= SRB_STATUS_ABORT_FAILED
;
3104 /* Notify about request complete */
3105 ScsiPortNotification(RequestComplete
,
3106 DeviceExtension
->MiniPortDeviceExtension
,
3109 /* and about readiness for the next request */
3110 ScsiPortNotification(NextRequest
,
3111 DeviceExtension
->MiniPortDeviceExtension
);
3113 /* They might ask for some work, so queue the DPC for them */
3114 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3116 /* We're done in this branch */
3122 /* Add number of queued requests */
3123 LunExtension
->QueueCount
++;
3126 /* Bypass requests don't need request sense */
3127 LunExtension
->Flags
&= ~LUNEX_NEED_REQUEST_SENSE
;
3129 /* Is disconnect disabled for this request? */
3130 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3132 /* Set the corresponding flag */
3133 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3136 /* Transfer timeout value from Srb to Lun */
3137 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
3141 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3143 /* It's a disconnect, so no more requests can go */
3144 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3147 LunExtension
->Flags
|= SCSI_PORT_LU_ACTIVE
;
3149 /* Increment queue count */
3150 LunExtension
->QueueCount
++;
3152 /* If it's tagged - special thing */
3153 if (Srb
->QueueTag
!= SP_UNTAGGED
)
3155 SrbInfo
= &DeviceExtension
->SrbInfo
[Srb
->QueueTag
- 1];
3157 /* Chek for consistency */
3158 ASSERT(SrbInfo
->Requests
.Blink
== NULL
);
3160 /* Insert it into the list of requests */
3161 InsertTailList(&LunExtension
->SrbInfo
.Requests
, &SrbInfo
->Requests
);
3165 /* Mark this Srb active */
3166 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
3168 /* Call HwStartIo routine */
3169 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
3172 /* If notification is needed, then request a DPC */
3173 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
3174 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3179 IO_ALLOCATION_ACTION
3181 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
,
3183 PVOID MapRegisterBase
,
3186 PSCSI_REQUEST_BLOCK Srb
;
3187 PSCSI_SG_ADDRESS ScatterGatherList
;
3189 PIO_STACK_LOCATION IrpStack
;
3190 ULONG TotalLength
= 0;
3191 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3192 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3194 BOOLEAN WriteToDevice
;
3196 /* Get pointers to SrbInfo and DeviceExtension */
3197 SrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)Context
;
3198 DeviceExtension
= DeviceObject
->DeviceExtension
;
3200 /* Get pointer to SRB */
3201 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3202 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
3204 /* Depending on the map registers number, we allocate
3205 either from NonPagedPool, or from our static list */
3206 if (SrbInfo
->NumberOfMapRegisters
> MAX_SG_LIST
)
3208 SrbInfo
->ScatterGather
= ExAllocatePoolWithTag(
3209 NonPagedPool
, SrbInfo
->NumberOfMapRegisters
* sizeof(SCSI_SG_ADDRESS
), TAG_SCSIPORT
);
3211 if (SrbInfo
->ScatterGather
== NULL
)
3214 Srb
->SrbFlags
|= SRB_FLAGS_SGLIST_FROM_POOL
;
3218 SrbInfo
->ScatterGather
= SrbInfo
->ScatterGatherList
;
3221 /* Use chosen SG list source */
3222 ScatterGatherList
= SrbInfo
->ScatterGather
;
3224 /* Save map registers base */
3225 SrbInfo
->BaseOfMapRegister
= MapRegisterBase
;
3227 /* Determine WriteToDevice flag */
3228 WriteToDevice
= Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
? TRUE
: FALSE
;
3230 /* Get virtual address of the data buffer */
3231 DataVA
= (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
3232 ((PCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
3234 /* Build the actual SG list */
3235 while (TotalLength
< Srb
->DataTransferLength
)
3237 if (!ScatterGatherList
)
3240 ScatterGatherList
->Length
= Srb
->DataTransferLength
- TotalLength
;
3241 ScatterGatherList
->PhysicalAddress
= IoMapTransfer(NULL
,
3244 DataVA
+ TotalLength
,
3245 &ScatterGatherList
->Length
,
3248 TotalLength
+= ScatterGatherList
->Length
;
3249 ScatterGatherList
++;
3252 /* Schedule an active request */
3253 InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
3254 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &CurrentIrql
);
3255 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
3256 ScsiPortStartPacket
,
3258 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, CurrentIrql
);
3260 return DeallocateObjectKeepRegisters
;
3263 static PSCSI_PORT_LUN_EXTENSION
3264 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3266 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3267 ULONG LunExtensionSize
;
3269 DPRINT("SpiAllocateLunExtension (%p)\n",
3272 /* Round LunExtensionSize first to the sizeof LONGLONG */
3273 LunExtensionSize
= (DeviceExtension
->LunExtensionSize
+
3274 sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
3276 LunExtensionSize
+= sizeof(SCSI_PORT_LUN_EXTENSION
);
3277 DPRINT("LunExtensionSize %lu\n", LunExtensionSize
);
3279 LunExtension
= ExAllocatePoolWithTag(NonPagedPool
, LunExtensionSize
, TAG_SCSIPORT
);
3280 if (LunExtension
== NULL
)
3282 DPRINT1("Out of resources!\n");
3286 /* Zero everything */
3287 RtlZeroMemory(LunExtension
, LunExtensionSize
);
3289 /* Initialize a list of requests */
3290 InitializeListHead(&LunExtension
->SrbInfo
.Requests
);
3292 /* Initialize timeout counter */
3293 LunExtension
->RequestTimeout
= -1;
3295 /* Set maximum queue size */
3296 LunExtension
->MaxQueueCount
= 256;
3298 /* Initialize request queue */
3299 KeInitializeDeviceQueue (&LunExtension
->DeviceQueue
);
3301 return LunExtension
;
3304 static PSCSI_PORT_LUN_EXTENSION
3305 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3310 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3312 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3313 DeviceExtension
, PathId
, TargetId
, Lun
);
3315 /* Get appropriate list */
3316 LunExtension
= DeviceExtension
->LunExtensionList
[(TargetId
+ Lun
) % LUS_NUMBER
];
3318 /* Iterate it until we find what we need */
3319 while (LunExtension
)
3321 if (LunExtension
->TargetId
== TargetId
&&
3322 LunExtension
->Lun
== Lun
&&
3323 LunExtension
->PathId
== PathId
)
3325 /* All matches, return */
3326 return LunExtension
;
3329 /* Advance to the next item */
3330 LunExtension
= LunExtension
->Next
;
3333 /* We did not find anything */
3334 DPRINT("Nothing found\n");
3338 static PSCSI_REQUEST_BLOCK_INFO
3339 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3340 PSCSI_PORT_LUN_EXTENSION LunExtension
,
3341 PSCSI_REQUEST_BLOCK Srb
)
3344 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3346 /* Spinlock must be held while this function executes */
3347 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3349 /* Allocate SRB data structure */
3350 if (DeviceExtension
->NeedSrbDataAlloc
)
3352 /* Treat the abort request in a special way */
3353 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
3355 SrbInfo
= SpiGetSrbData(DeviceExtension
,
3361 else if (Srb
->SrbFlags
&
3362 (SRB_FLAGS_QUEUE_ACTION_ENABLE
| SRB_FLAGS_NO_QUEUE_FREEZE
) &&
3363 !(Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3366 /* Do not process tagged commands if need request sense is set */
3367 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
3369 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3371 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3372 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3374 /* Relese the spinlock and return */
3375 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3379 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
3380 SrbInfo
= DeviceExtension
->FreeSrbInfo
;
3382 if (SrbInfo
== NULL
)
3384 /* No SRB structures left in the list. We have to leave
3385 and wait while we are called again */
3387 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3388 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3392 DeviceExtension
->FreeSrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)SrbInfo
->Requests
.Flink
;
3394 /* QueueTag must never be 0, so +1 to it */
3395 Srb
->QueueTag
= (UCHAR
)(SrbInfo
- DeviceExtension
->SrbInfo
) + 1;
3399 /* Usual untagged command */
3401 (!IsListEmpty(&LunExtension
->SrbInfo
.Requests
) ||
3402 LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
) &&
3403 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
3406 /* Mark it as pending and leave */
3407 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3408 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3409 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3411 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3415 Srb
->QueueTag
= SP_UNTAGGED
;
3416 SrbInfo
= &LunExtension
->SrbInfo
;
3421 Srb
->QueueTag
= SP_UNTAGGED
;
3422 SrbInfo
= &LunExtension
->SrbInfo
;
3425 /* Allocate SRB extension structure */
3426 if (DeviceExtension
->NeedSrbExtensionAlloc
)
3428 /* Check the list of free extensions */
3429 SrbExtension
= DeviceExtension
->FreeSrbExtensions
;
3431 /* If no free extensions... */
3432 if (SrbExtension
== NULL
)
3435 if (Srb
->Function
!= SRB_FUNCTION_ABORT_COMMAND
&&
3436 Srb
->QueueTag
!= SP_UNTAGGED
)
3438 SrbInfo
->Requests
.Blink
= NULL
;
3439 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
3440 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
3443 /* Return, in order to be called again later */
3444 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3445 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3449 /* Remove that free SRB extension from the list (since
3450 we're going to use it) */
3451 DeviceExtension
->FreeSrbExtensions
= *((PVOID
*)SrbExtension
);
3453 /* Spinlock can be released now */
3454 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3456 Srb
->SrbExtension
= SrbExtension
;
3458 if (Srb
->SenseInfoBuffer
!= NULL
&&
3459 DeviceExtension
->SupportsAutoSense
)
3461 /* Store pointer to the SenseInfo buffer */
3462 SrbInfo
->SaveSenseRequest
= Srb
->SenseInfoBuffer
;
3464 /* Does data fit the buffer? */
3465 if (Srb
->SenseInfoBufferLength
> sizeof(SENSE_DATA
))
3467 /* No, disabling autosense at all */
3468 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_AUTOSENSE
;
3472 /* Yes, update the buffer pointer */
3473 Srb
->SenseInfoBuffer
= SrbExtension
+ DeviceExtension
->SrbExtensionSize
;
3480 Srb
->SrbExtension
= NULL
;
3481 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3489 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
3490 IN PSCSI_LUN_INFO LunInfo
)
3492 IO_STATUS_BLOCK IoStatusBlock
;
3493 PIO_STACK_LOCATION IrpStack
;
3498 PINQUIRYDATA InquiryBuffer
;
3499 PSENSE_DATA SenseBuffer
;
3500 BOOLEAN KeepTrying
= TRUE
;
3501 ULONG RetryCount
= 0;
3502 SCSI_REQUEST_BLOCK Srb
;
3504 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3505 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3507 DPRINT ("SpiSendInquiry() called\n");
3509 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3511 InquiryBuffer
= ExAllocatePoolWithTag (NonPagedPool
, INQUIRYDATABUFFERSIZE
, TAG_SCSIPORT
);
3512 if (InquiryBuffer
== NULL
)
3513 return STATUS_INSUFFICIENT_RESOURCES
;
3515 SenseBuffer
= ExAllocatePoolWithTag (NonPagedPool
, SENSE_BUFFER_SIZE
, TAG_SCSIPORT
);
3516 if (SenseBuffer
== NULL
)
3518 ExFreePool(InquiryBuffer
);
3519 return STATUS_INSUFFICIENT_RESOURCES
;
3524 /* Initialize event for waiting */
3525 KeInitializeEvent(&Event
,
3530 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN
,
3535 INQUIRYDATABUFFERSIZE
,
3541 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3542 return STATUS_INSUFFICIENT_RESOURCES
;
3546 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3548 Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
3549 Srb
.OriginalRequest
= Irp
;
3550 Srb
.PathId
= LunInfo
->PathId
;
3551 Srb
.TargetId
= LunInfo
->TargetId
;
3552 Srb
.Lun
= LunInfo
->Lun
;
3553 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3554 Srb
.SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3555 Srb
.TimeOutValue
= 4;
3558 Srb
.SenseInfoBuffer
= SenseBuffer
;
3559 Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3561 Srb
.DataBuffer
= InquiryBuffer
;
3562 Srb
.DataTransferLength
= INQUIRYDATABUFFERSIZE
;
3564 /* Attach Srb to the Irp */
3565 IrpStack
= IoGetNextIrpStackLocation (Irp
);
3566 IrpStack
->Parameters
.Scsi
.Srb
= &Srb
;
3569 Cdb
= (PCDB
)Srb
.Cdb
;
3570 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_INQUIRY
;
3571 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= LunInfo
->Lun
;
3572 Cdb
->CDB6INQUIRY
.AllocationLength
= INQUIRYDATABUFFERSIZE
;
3574 /* Call the driver */
3575 Status
= IoCallDriver(DeviceObject
, Irp
);
3577 /* Wait for it to complete */
3578 if (Status
== STATUS_PENDING
)
3580 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3581 KeWaitForSingleObject(&Event
,
3586 Status
= IoStatusBlock
.Status
;
3589 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status
);
3591 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_SUCCESS
)
3593 /* All fine, copy data over */
3594 RtlCopyMemory(LunInfo
->InquiryData
,
3596 INQUIRYDATABUFFERSIZE
);
3598 Status
= STATUS_SUCCESS
;
3603 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb
.SrbStatus
);
3604 /* Check if the queue is frozen */
3605 if (Srb
.SrbStatus
& SRB_STATUS_QUEUE_FROZEN
)
3607 /* Something weird happened, deal with it (unfreeze the queue) */
3610 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb
.TargetId
);
3612 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3617 /* Clear frozen flag */
3618 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
3620 /* Acquire the spinlock */
3621 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
3623 /* Process the request */
3624 SpiGetNextRequestFromLun(DeviceObject
->DeviceExtension
, LunExtension
);
3626 /* SpiGetNextRequestFromLun() releases the spinlock,
3627 so we just lower irql back to what it was before */
3631 /* Check if data overrun happened */
3632 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
3634 DPRINT("Data overrun at TargetId %d\n", LunInfo
->TargetId
);
3635 /* Nothing dramatic, just copy data, but limiting the size */
3636 RtlCopyMemory(LunInfo
->InquiryData
,
3638 (Srb
.DataTransferLength
> INQUIRYDATABUFFERSIZE
) ?
3639 INQUIRYDATABUFFERSIZE
: Srb
.DataTransferLength
);
3641 Status
= STATUS_SUCCESS
;
3644 else if ((Srb
.SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3645 SenseBuffer
->SenseKey
== SCSI_SENSE_ILLEGAL_REQUEST
)
3647 /* LUN is not valid, but some device responds there.
3648 Mark it as invalid anyway */
3650 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3655 /* Retry a couple of times if no timeout happened */
3656 if ((RetryCount
< 2) &&
3657 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_NO_DEVICE
) &&
3658 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_SELECTION_TIMEOUT
))
3665 /* That's all, go to exit */
3668 /* Set status according to SRB status */
3669 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_FUNCTION
||
3670 SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH
)
3672 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3676 Status
= STATUS_IO_DEVICE_ERROR
;
3684 ExFreePool(InquiryBuffer
);
3685 ExFreePool(SenseBuffer
);
3687 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status
);
3693 /* Scans all SCSI buses */
3695 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3697 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3701 PSCSI_BUS_SCAN_INFO BusScanInfo
;
3702 PSCSI_LUN_INFO LastLunInfo
, LunInfo
, LunInfoExists
;
3703 BOOLEAN DeviceExists
;
3708 DPRINT("SpiScanAdapter() called\n");
3710 /* Scan all buses */
3711 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
3713 DPRINT(" Scanning bus %d\n", Bus
);
3716 /* Get pointer to the scan information */
3717 BusScanInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
];
3721 /* Find the last LUN info in the list */
3722 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3723 LastLunInfo
= LunInfo
;
3725 while (LunInfo
!= NULL
)
3727 LastLunInfo
= LunInfo
;
3728 LunInfo
= LunInfo
->Next
;
3733 /* We need to allocate this buffer */
3734 BusScanInfo
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_BUS_SCAN_INFO
), TAG_SCSIPORT
);
3738 DPRINT1("Out of resources!\n");
3742 /* Store the pointer in the BusScanInfo array */
3743 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
] = BusScanInfo
;
3745 /* Fill this struct (length and bus ids for now) */
3746 BusScanInfo
->Length
= sizeof(SCSI_BUS_SCAN_INFO
);
3747 BusScanInfo
->LogicalUnitsCount
= 0;
3748 BusScanInfo
->BusIdentifier
= DeviceExtension
->PortConfig
->InitiatorBusId
[Bus
];
3749 BusScanInfo
->LunInfo
= NULL
;
3751 /* Set pointer to the last LUN info to NULL */
3755 /* Create LUN information structure */
3756 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3758 if (LunInfo
== NULL
)
3760 DPRINT1("Out of resources!\n");
3764 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3766 /* Create LunExtension */
3767 LunExtension
= SpiAllocateLunExtension (DeviceExtension
);
3769 /* And send INQUIRY to every target */
3770 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
3772 /* TODO: Support scan bottom-up */
3774 /* Skip if it's the same address */
3775 if (Target
== BusScanInfo
->BusIdentifier
)
3778 /* Try to find an existing device here */
3779 DeviceExists
= FALSE
;
3780 LunInfoExists
= BusScanInfo
->LunInfo
;
3782 /* Find matching address on this bus */
3783 while (LunInfoExists
)
3785 if (LunInfoExists
->TargetId
== Target
)
3787 DeviceExists
= TRUE
;
3791 /* Advance to the next one */
3792 LunInfoExists
= LunInfoExists
->Next
;
3795 /* No need to bother rescanning, since we already did that before */
3799 /* Scan all logical units */
3800 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
3802 if ((!LunExtension
) || (!LunInfo
))
3805 /* Add extension to the list */
3806 Hint
= (Target
+ Lun
) % LUS_NUMBER
;
3807 LunExtension
->Next
= DeviceExtension
->LunExtensionList
[Hint
];
3808 DeviceExtension
->LunExtensionList
[Hint
] = LunExtension
;
3810 /* Fill Path, Target, Lun fields */
3811 LunExtension
->PathId
= LunInfo
->PathId
= (UCHAR
)Bus
;
3812 LunExtension
->TargetId
= LunInfo
->TargetId
= (UCHAR
) Target
;
3813 LunExtension
->Lun
= LunInfo
->Lun
= (UCHAR
)Lun
;
3815 /* Set flag to prevent race conditions */
3816 LunExtension
->Flags
|= SCSI_PORT_SCAN_IN_PROGRESS
;
3818 /* Zero LU extension contents */
3819 if (DeviceExtension
->LunExtensionSize
)
3821 RtlZeroMemory(LunExtension
+ 1,
3822 DeviceExtension
->LunExtensionSize
);
3825 /* Finally send the inquiry command */
3826 Status
= SpiSendInquiry(DeviceExtension
->DeviceObject
, LunInfo
);
3828 if (NT_SUCCESS(Status
))
3830 /* Let's see if we really found a device */
3831 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3833 /* Check if this device is unsupported */
3834 if (InquiryData
->DeviceTypeQualifier
== DEVICE_QUALIFIER_NOT_SUPPORTED
)
3836 DeviceExtension
->LunExtensionList
[Hint
] =
3837 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3842 /* Clear the "in scan" flag */
3843 LunExtension
->Flags
&= ~SCSI_PORT_SCAN_IN_PROGRESS
;
3845 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3846 InquiryData
->DeviceType
, Bus
, Target
, Lun
);
3848 /* Add this info to the linked list */
3849 LunInfo
->Next
= NULL
;
3851 LastLunInfo
->Next
= LunInfo
;
3853 BusScanInfo
->LunInfo
= LunInfo
;
3855 /* Store the last LUN info */
3856 LastLunInfo
= LunInfo
;
3858 /* Store DeviceObject */
3859 LunInfo
->DeviceObject
= DeviceExtension
->DeviceObject
;
3861 /* Allocate another buffer */
3862 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3866 DPRINT1("Out of resources!\n");
3870 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3872 /* Create a new LU extension */
3873 LunExtension
= SpiAllocateLunExtension(DeviceExtension
);
3879 /* Remove this LUN from the list */
3880 DeviceExtension
->LunExtensionList
[Hint
] =
3881 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3883 /* Decide whether we are continuing or not */
3884 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
3892 /* Free allocated buffers */
3894 ExFreePool(LunExtension
);
3897 ExFreePool(LunInfo
);
3899 /* Sum what we found */
3900 BusScanInfo
->LogicalUnitsCount
+= (UCHAR
) DevicesFound
;
3901 DPRINT(" Found %d devices on bus %d\n", DevicesFound
, Bus
);
3904 DPRINT ("SpiScanAdapter() done\n");
3909 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3912 ULONG InquiryDataSize
;
3913 PSCSI_LUN_INFO LunInfo
;
3914 ULONG BusCount
, LunCount
, Length
;
3915 PIO_STACK_LOCATION IrpStack
;
3916 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
3917 PSCSI_INQUIRY_DATA InquiryData
;
3918 PSCSI_BUS_DATA BusData
;
3922 DPRINT("SpiGetInquiryData() called\n");
3924 /* Get pointer to the buffer */
3925 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3926 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3928 /* Initialize bus and LUN counters */
3929 BusCount
= DeviceExtension
->BusesConfig
->NumberOfBuses
;
3932 /* Calculate total number of LUNs */
3933 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3934 LunCount
+= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3936 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
3938 ((sizeof(SCSI_INQUIRY_DATA
) - 1 + INQUIRYDATABUFFERSIZE
+
3939 sizeof(ULONG
) - 1) & ~(sizeof(ULONG
) - 1));
3941 /* Calculate data size */
3942 Length
= sizeof(SCSI_ADAPTER_BUS_INFO
) + (BusCount
- 1) *
3943 sizeof(SCSI_BUS_DATA
);
3945 Length
+= InquiryDataSize
* LunCount
;
3947 /* Check, if all data is going to fit into provided buffer */
3948 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< Length
)
3950 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3951 return STATUS_BUFFER_TOO_SMALL
;
3954 /* Store data size in the IRP */
3955 Irp
->IoStatus
.Information
= Length
;
3957 DPRINT("Data size: %lu\n", Length
);
3959 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
3961 AdapterBusInfo
->NumberOfBuses
= (UCHAR
)BusCount
;
3963 /* Point InquiryData to the corresponding place inside Buffer */
3964 InquiryData
= (PSCSI_INQUIRY_DATA
)(Buffer
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
3965 (BusCount
- 1) * sizeof(SCSI_BUS_DATA
));
3968 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3970 BusData
= &AdapterBusInfo
->BusData
[Bus
];
3972 /* Calculate and save an offset of the inquiry data */
3973 BusData
->InquiryDataOffset
= (PUCHAR
)InquiryData
- Buffer
;
3975 /* Get a pointer to the LUN information structure */
3976 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3978 /* Store Initiator Bus Id */
3979 BusData
->InitiatorBusId
=
3980 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->BusIdentifier
;
3982 /* Store LUN count */
3983 BusData
->NumberOfLogicalUnits
=
3984 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3987 while (LunInfo
!= NULL
)
3989 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
3990 Bus
, LunInfo
->TargetId
, LunInfo
->Lun
);
3992 /* Fill InquiryData with values */
3993 InquiryData
->PathId
= LunInfo
->PathId
;
3994 InquiryData
->TargetId
= LunInfo
->TargetId
;
3995 InquiryData
->Lun
= LunInfo
->Lun
;
3996 InquiryData
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
3997 InquiryData
->DeviceClaimed
= LunInfo
->DeviceClaimed
;
3998 InquiryData
->NextInquiryDataOffset
=
3999 (PUCHAR
)InquiryData
+ InquiryDataSize
- Buffer
;
4001 /* Copy data in it */
4002 RtlCopyMemory(InquiryData
->InquiryData
,
4003 LunInfo
->InquiryData
,
4004 INQUIRYDATABUFFERSIZE
);
4006 /* Move to the next LUN */
4007 LunInfo
= LunInfo
->Next
;
4008 InquiryData
= (PSCSI_INQUIRY_DATA
) ((PCHAR
)InquiryData
+ InquiryDataSize
);
4011 /* Either mark the end, or set offset to 0 */
4012 if (BusData
->NumberOfLogicalUnits
!= 0)
4013 ((PSCSI_INQUIRY_DATA
) ((PCHAR
) InquiryData
- InquiryDataSize
))->NextInquiryDataOffset
= 0;
4015 BusData
->InquiryDataOffset
= 0;
4018 /* Finish with success */
4019 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4020 return STATUS_SUCCESS
;
4023 static PSCSI_REQUEST_BLOCK_INFO
4024 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4030 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4032 if (QueueTag
== SP_UNTAGGED
)
4034 /* Untagged request, get LU and return pointer to SrbInfo */
4035 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4040 /* Return NULL in case of error */
4044 /* Return the pointer to SrbInfo */
4045 return &LunExtension
->SrbInfo
;
4049 /* Make sure the tag is valid, if it is - return the data */
4050 if (QueueTag
> DeviceExtension
->SrbDataCount
|| QueueTag
< 1)
4053 return &DeviceExtension
->SrbInfo
[QueueTag
-1];
4058 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4059 IN PSCSI_REQUEST_BLOCK InitialSrb
)
4061 PSCSI_REQUEST_BLOCK Srb
;
4064 PIO_STACK_LOCATION IrpStack
;
4065 LARGE_INTEGER LargeInt
;
4068 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb
);
4071 Srb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
) + sizeof(PVOID
), TAG_SCSIPORT
);
4072 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
4075 LargeInt
.QuadPart
= (LONGLONG
) 1;
4076 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_READ
,
4077 DeviceExtension
->DeviceObject
,
4078 InitialSrb
->SenseInfoBuffer
,
4079 InitialSrb
->SenseInfoBufferLength
,
4083 IoSetCompletionRoutine(Irp
,
4084 (PIO_COMPLETION_ROUTINE
)SpiCompletionRoutine
,
4092 DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb
);
4096 IrpStack
= IoGetNextIrpStackLocation(Irp
);
4097 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
4099 /* Put Srb address into Irp... */
4100 IrpStack
->Parameters
.Others
.Argument1
= (PVOID
)Srb
;
4102 /* ...and vice versa */
4103 Srb
->OriginalRequest
= Irp
;
4106 Ptr
= (PVOID
*)(Srb
+1);
4109 /* Build CDB for REQUEST SENSE */
4111 Cdb
= (PCDB
)Srb
->Cdb
;
4113 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
4114 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= 0;
4115 Cdb
->CDB6INQUIRY
.Reserved1
= 0;
4116 Cdb
->CDB6INQUIRY
.PageCode
= 0;
4117 Cdb
->CDB6INQUIRY
.IReserved
= 0;
4118 Cdb
->CDB6INQUIRY
.AllocationLength
= (UCHAR
)InitialSrb
->SenseInfoBufferLength
;
4119 Cdb
->CDB6INQUIRY
.Control
= 0;
4122 Srb
->TargetId
= InitialSrb
->TargetId
;
4123 Srb
->Lun
= InitialSrb
->Lun
;
4124 Srb
->PathId
= InitialSrb
->PathId
;
4126 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4127 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
4129 /* Timeout will be 2 seconds */
4130 Srb
->TimeOutValue
= 2;
4132 /* No auto request sense */
4133 Srb
->SenseInfoBufferLength
= 0;
4134 Srb
->SenseInfoBuffer
= NULL
;
4136 /* Set necessary flags */
4137 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_BYPASS_FROZEN_QUEUE
|
4138 SRB_FLAGS_DISABLE_DISCONNECT
;
4140 /* Transfer disable synch transfer flag */
4141 if (InitialSrb
->SrbFlags
& SRB_FLAGS_DISABLE_SYNCH_TRANSFER
)
4142 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4144 Srb
->DataBuffer
= InitialSrb
->SenseInfoBuffer
;
4146 /* Fill the transfer length */
4147 Srb
->DataTransferLength
= InitialSrb
->SenseInfoBufferLength
;
4149 /* Clear statuses */
4150 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
4153 /* Call the driver */
4154 (VOID
)IoCallDriver(DeviceExtension
->DeviceObject
, Irp
);
4156 DPRINT("SpiSendRequestSense() done\n");
4163 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4164 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
4165 OUT PBOOLEAN NeedToCallStartIo
)
4167 PSCSI_REQUEST_BLOCK Srb
;
4168 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4171 ULONG SequenceNumber
;
4174 Irp
= Srb
->OriginalRequest
;
4176 /* Get Lun extension */
4177 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4182 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
&&
4183 DeviceExtension
->MapBuffers
&&
4186 /* MDL is shared if transfer is broken into smaller parts */
4187 Srb
->DataBuffer
= (PCCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
4188 ((PCCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
4190 /* In case of data going in, flush the buffers */
4191 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
4193 KeFlushIoBuffers(Irp
->MdlAddress
,
4199 /* Flush adapter if needed */
4200 if (SrbInfo
->BaseOfMapRegister
)
4202 /* TODO: Implement */
4206 /* Clear the request */
4207 SrbInfo
->Srb
= NULL
;
4209 /* If disconnect is disabled... */
4210 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
4212 /* Acquire the spinlock since we mess with flags */
4213 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4215 /* Set corresponding flag */
4216 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
4218 /* Clear the timer if needed */
4219 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
))
4220 DeviceExtension
->TimerCount
= -1;
4222 /* Spinlock is not needed anymore */
4223 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4225 if (!(DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
) &&
4226 !(DeviceExtension
->Flags
& SCSI_PORT_DEVICE_BUSY
) &&
4227 !(*NeedToCallStartIo
))
4229 /* We're not busy, but we have a request pending */
4230 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4234 /* Scatter/gather */
4235 if (Srb
->SrbFlags
& SRB_FLAGS_SGLIST_FROM_POOL
)
4237 /* TODO: Implement */
4241 /* Acquire spinlock (we're freeing SrbExtension) */
4242 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4244 /* Free it (if needed) */
4245 if (Srb
->SrbExtension
)
4247 if (Srb
->SenseInfoBuffer
!= NULL
&& DeviceExtension
->SupportsAutoSense
)
4249 ASSERT(Srb
->SenseInfoBuffer
== NULL
|| SrbInfo
->SaveSenseRequest
!= NULL
);
4251 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)
4253 /* Copy sense data to the buffer */
4254 RtlCopyMemory(SrbInfo
->SaveSenseRequest
,
4255 Srb
->SenseInfoBuffer
,
4256 Srb
->SenseInfoBufferLength
);
4259 /* And restore the pointer */
4260 Srb
->SenseInfoBuffer
= SrbInfo
->SaveSenseRequest
;
4263 /* Put it into the free srb extensions list */
4264 *((PVOID
*)Srb
->SrbExtension
) = DeviceExtension
->FreeSrbExtensions
;
4265 DeviceExtension
->FreeSrbExtensions
= Srb
->SrbExtension
;
4268 /* Save transfer length in the IRP */
4269 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
4271 SequenceNumber
= SrbInfo
->SequenceNumber
;
4272 SrbInfo
->SequenceNumber
= 0;
4274 /* Decrement the queue count */
4275 LunExtension
->QueueCount
--;
4277 /* Free Srb, if needed*/
4278 if (Srb
->QueueTag
!= SP_UNTAGGED
)
4280 /* Put it into the free list */
4281 SrbInfo
->Requests
.Blink
= NULL
;
4282 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
4283 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
4286 /* SrbInfo is not used anymore */
4289 if (DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
)
4291 /* Clear the flag */
4292 DeviceExtension
->Flags
&= ~SCSI_PORT_REQUEST_PENDING
;
4294 /* Note the caller about StartIo */
4295 *NeedToCallStartIo
= TRUE
;
4298 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
4300 /* Start the packet */
4301 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4303 if (!(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
) &&
4304 LunExtension
->RequestTimeout
== -1)
4306 /* Start the next packet */
4307 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4311 /* Release the spinlock */
4312 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4315 DPRINT("IoCompleting request IRP 0x%p\n", Irp
);
4317 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4319 /* Decrement number of active requests, and analyze the result */
4320 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4323 !DeviceExtension
->MapRegisters
&&
4324 DeviceExtension
->AdapterObject
!= NULL
)
4326 /* Nullify map registers */
4327 DeviceExtension
->MapRegisterBase
= NULL
;
4328 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4331 /* Exit, we're done */
4335 /* Decrement number of active requests, and analyze the result */
4336 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4339 !DeviceExtension
->MapRegisters
&&
4340 DeviceExtension
->AdapterObject
!= NULL
)
4342 /* Result is negative, so this is a slave, free map registers */
4343 DeviceExtension
->MapRegisterBase
= NULL
;
4344 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4347 /* Convert status */
4348 Irp
->IoStatus
.Status
= SpiStatusSrbToNt(Srb
->SrbStatus
);
4350 /* It's not a bypass, it's busy or the queue is full? */
4351 if ((Srb
->ScsiStatus
== SCSISTAT_BUSY
||
4352 Srb
->SrbStatus
== SRB_STATUS_BUSY
||
4353 Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
) &&
4354 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
))
4357 DPRINT("Busy SRB status %x\n", Srb
->SrbStatus
);
4359 /* Requeu, if needed */
4360 if (LunExtension
->Flags
& (LUNEX_FROZEN_QUEUE
| LUNEX_BUSY
))
4362 DPRINT("it's being requeued\n");
4364 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4365 Srb
->ScsiStatus
= 0;
4367 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4368 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
4371 /* It's a big f.ck up if we got here */
4372 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
4373 Srb
->ScsiStatus
= SCSISTAT_BUSY
;
4379 /* Release the spinlock */
4380 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4383 else if (LunExtension
->AttemptCount
++ < 20)
4385 /* LUN is still busy */
4386 Srb
->ScsiStatus
= 0;
4387 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4389 LunExtension
->BusyRequest
= Irp
;
4390 LunExtension
->Flags
|= LUNEX_BUSY
;
4392 /* Release the spinlock */
4393 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4398 /* Freeze the queue*/
4399 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4400 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4402 /* "Unfull" the queue */
4403 LunExtension
->Flags
&= ~LUNEX_FULL_QUEUE
;
4405 /* Release the spinlock */
4406 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4408 /* Return status that the device is not ready */
4409 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
4410 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4416 /* Start the next request, if LUN is idle, and this is sense request */
4417 if (((Srb
->ScsiStatus
!= SCSISTAT_CHECK_CONDITION
) ||
4418 (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) ||
4419 !Srb
->SenseInfoBuffer
|| !Srb
->SenseInfoBufferLength
)
4420 && (Srb
->SrbFlags
& SRB_FLAGS_NO_QUEUE_FREEZE
))
4422 if (LunExtension
->RequestTimeout
== -1)
4423 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4425 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4429 /* Freeze the queue */
4430 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4431 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4433 /* Do we need a request sense? */
4434 if (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4435 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
4436 Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
)
4438 /* If LUN is busy, we have to requeue it in order to allow request sense */
4439 if (LunExtension
->Flags
& LUNEX_BUSY
)
4441 DPRINT("Requeueing busy request to allow request sense\n");
4443 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4444 &LunExtension
->BusyRequest
->Tail
.Overlay
.DeviceQueueEntry
,
4447 /* We should never get here */
4450 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4451 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4456 /* Clear busy flags */
4457 LunExtension
->Flags
&= ~(LUNEX_FULL_QUEUE
| LUNEX_BUSY
);
4460 /* Release the spinlock */
4461 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4463 /* Send RequestSense */
4464 SpiSendRequestSense(DeviceExtension
, Srb
);
4470 /* Release the spinlock */
4471 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4474 /* Complete the request */
4475 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4480 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
4484 PSCSI_REQUEST_BLOCK Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
4485 PSCSI_REQUEST_BLOCK InitialSrb
;
4488 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp
);
4490 if ((Srb
->Function
== SRB_FUNCTION_RESET_BUS
) ||
4491 (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
))
4493 /* Deallocate SRB and IRP and exit */
4497 return STATUS_MORE_PROCESSING_REQUIRED
;
4500 /* Get a pointer to the SRB and IRP which were initially sent */
4501 InitialSrb
= *((PVOID
*)(Srb
+1));
4502 InitialIrp
= InitialSrb
->OriginalRequest
;
4504 if ((SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
) ||
4505 (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_DATA_OVERRUN
))
4507 /* Sense data is OK */
4508 InitialSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
4510 /* Set length to be the same */
4511 InitialSrb
->SenseInfoBufferLength
= (UCHAR
)Srb
->DataTransferLength
;
4514 /* Make sure initial SRB's queue is frozen */
4515 ASSERT(InitialSrb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
);
4517 /* Complete this request */
4518 IoCompleteRequest(InitialIrp
, IO_DISK_INCREMENT
);
4520 /* Deallocate everything (internal) */
4523 if (Irp
->MdlAddress
!= NULL
)
4525 MmUnlockPages(Irp
->MdlAddress
);
4526 IoFreeMdl(Irp
->MdlAddress
);
4527 Irp
->MdlAddress
= NULL
;
4531 return STATUS_MORE_PROCESSING_REQUIRED
;
4534 static BOOLEAN NTAPI
4535 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
4536 IN PVOID ServiceContext
)
4538 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4541 DPRINT("ScsiPortIsr() called!\n");
4543 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
4545 /* If interrupts are disabled - we don't expect any */
4546 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_DISABLE_INTERRUPTS
)
4549 /* Call miniport's HwInterrupt routine */
4550 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
4552 /* If flag of notification is set - queue a DPC */
4553 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4555 IoRequestDpc(DeviceExtension
->DeviceObject
,
4556 DeviceExtension
->CurrentIrp
,
4565 SpiSaveInterruptData(IN PVOID Context
)
4567 PSCSI_PORT_SAVE_INTERRUPT InterruptContext
= Context
;
4568 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4569 PSCSI_REQUEST_BLOCK Srb
;
4570 PSCSI_REQUEST_BLOCK_INFO SrbInfo
, NextSrbInfo
;
4571 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4574 /* Get pointer to the device extension */
4575 DeviceExtension
= InterruptContext
->DeviceExtension
;
4577 /* If we don't have anything pending - return */
4578 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
))
4581 /* Actually save the interrupt data */
4582 *InterruptContext
->InterruptData
= DeviceExtension
->InterruptData
;
4584 /* Clear the data stored in the device extension */
4585 DeviceExtension
->InterruptData
.Flags
&=
4586 (SCSI_PORT_RESET
| SCSI_PORT_RESET_REQUEST
| SCSI_PORT_DISABLE_INTERRUPTS
);
4587 DeviceExtension
->InterruptData
.CompletedAbort
= NULL
;
4588 DeviceExtension
->InterruptData
.ReadyLun
= NULL
;
4589 DeviceExtension
->InterruptData
.CompletedRequests
= NULL
;
4591 /* Loop through the list of completed requests */
4592 SrbInfo
= InterruptContext
->InterruptData
->CompletedRequests
;
4596 /* Make sure we have SRV */
4597 ASSERT(SrbInfo
->Srb
);
4599 /* Get SRB and LunExtension */
4602 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4607 /* We have to check special cases if request is unsuccessfull*/
4608 if (Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
)
4610 /* Check if we need request sense by a few conditions */
4611 if (Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
&&
4612 Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4613 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
))
4615 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
4617 /* It means: we tried to send REQUEST SENSE, but failed */
4619 Srb
->ScsiStatus
= 0;
4620 Srb
->SrbStatus
= SRB_STATUS_REQUEST_SENSE_FAILED
;
4624 /* Set the corresponding flag, so that REQUEST SENSE
4626 LunExtension
->Flags
|= LUNEX_NEED_REQUEST_SENSE
;
4631 /* Check for a full queue */
4632 if (Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
)
4634 /* TODO: Implement when it's encountered */
4639 /* Let's decide if we need to watch timeout or not */
4640 if (Srb
->QueueTag
== SP_UNTAGGED
)
4646 if (LunExtension
->SrbInfo
.Requests
.Flink
== &SrbInfo
->Requests
)
4651 /* Remove it from the queue */
4652 RemoveEntryList(&SrbInfo
->Requests
);
4657 /* We have to maintain timeout counter */
4658 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
))
4660 LunExtension
->RequestTimeout
= -1;
4664 NextSrbInfo
= CONTAINING_RECORD(LunExtension
->SrbInfo
.Requests
.Flink
,
4665 SCSI_REQUEST_BLOCK_INFO
,
4668 Srb
= NextSrbInfo
->Srb
;
4670 /* Update timeout counter */
4671 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
4675 SrbInfo
= SrbInfo
->CompletedRequests
;
4683 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4684 IN PSCSI_PORT_LUN_EXTENSION LunExtension
)
4686 PIO_STACK_LOCATION IrpStack
;
4688 PKDEVICE_QUEUE_ENTRY Entry
;
4689 PSCSI_REQUEST_BLOCK Srb
;
4692 /* If LUN is not active or queue is more than maximum allowed */
4693 if (LunExtension
->QueueCount
>= LunExtension
->MaxQueueCount
||
4694 !(LunExtension
->Flags
& SCSI_PORT_LU_ACTIVE
))
4696 /* Release the spinlock and exit */
4697 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4701 /* Check if we can get a next request */
4702 if (LunExtension
->Flags
&
4703 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_BUSY
|
4704 LUNEX_FULL_QUEUE
| LUNEX_FROZEN_QUEUE
| LUNEX_REQUEST_PENDING
))
4706 /* Pending requests can only be started if the queue is empty */
4707 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
) &&
4708 !(LunExtension
->Flags
&
4709 (LUNEX_BUSY
| LUNEX_FROZEN_QUEUE
| LUNEX_FULL_QUEUE
| LUNEX_NEED_REQUEST_SENSE
)))
4711 /* Make sure we have SRB */
4712 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
4714 /* Clear active and pending flags */
4715 LunExtension
->Flags
&= ~(LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
);
4717 /* Get next Irp, and clear pending requests list */
4718 NextIrp
= LunExtension
->PendingRequest
;
4719 LunExtension
->PendingRequest
= NULL
;
4721 /* Set attempt counter to zero */
4722 LunExtension
->AttemptCount
= 0;
4724 /* Release the spinlock */
4725 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4727 /* Start the next pending request */
4728 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4734 /* Release the spinlock, without clearing any flags and exit */
4735 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4741 /* Reset active flag */
4742 LunExtension
->Flags
&= ~SCSI_PORT_LU_ACTIVE
;
4744 /* Set attempt counter to zero */
4745 LunExtension
->AttemptCount
= 0;
4747 /* Remove packet from the device queue */
4748 Entry
= KeRemoveByKeyDeviceQueue(&LunExtension
->DeviceQueue
, LunExtension
->SortKey
);
4752 /* Get pointer to the next irp */
4753 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
4755 /* Get point to the SRB */
4756 IrpStack
= IoGetCurrentIrpStackLocation(NextIrp
);
4757 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
4760 LunExtension
->SortKey
= Srb
->QueueSortKey
;
4761 LunExtension
->SortKey
++;
4763 /* Release the spinlock */
4764 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4766 /* Start the next pending request */
4767 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4771 /* Release the spinlock */
4772 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4778 // ScsiPortDpcForIsr
4785 // IN PDEVICE_OBJECT DpcDeviceObject
4787 // IN PVOID DpcContext
4790 ScsiPortDpcForIsr(IN PKDPC Dpc
,
4791 IN PDEVICE_OBJECT DpcDeviceObject
,
4793 IN PVOID DpcContext
)
4795 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DpcDeviceObject
->DeviceExtension
;
4796 SCSI_PORT_INTERRUPT_DATA InterruptData
;
4797 SCSI_PORT_SAVE_INTERRUPT Context
;
4798 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4799 BOOLEAN NeedToStartIo
;
4800 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
4802 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4803 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
4805 /* We need to acquire spinlock */
4806 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4808 RtlZeroMemory(&InterruptData
, sizeof(SCSI_PORT_INTERRUPT_DATA
));
4812 /* Interrupt structure must be snapshotted, and only then analyzed */
4813 Context
.InterruptData
= &InterruptData
;
4814 Context
.DeviceExtension
= DeviceExtension
;
4816 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4817 SpiSaveInterruptData
,
4820 /* Nothing - just return (don't forget to release the spinlock */
4821 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4822 DPRINT("ScsiPortDpcForIsr() done\n");
4826 /* If flush of adapters is needed - do it */
4827 if (InterruptData
.Flags
& SCSI_PORT_FLUSH_ADAPTERS
)
4829 /* TODO: Implement */
4833 /* Check for IoMapTransfer */
4834 if (InterruptData
.Flags
& SCSI_PORT_MAP_TRANSFER
)
4836 /* TODO: Implement */
4840 /* Check if timer is needed */
4841 if (InterruptData
.Flags
& SCIS_PORT_TIMER_NEEDED
)
4843 /* TODO: Implement */
4847 /* If it's ready for the next request */
4848 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4850 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4851 if ((DeviceExtension
->Flags
&
4852 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
)) ==
4853 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
))
4855 /* Clear busy flag set by ScsiPortStartPacket() */
4856 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4858 if (!(InterruptData
.Flags
& SCSI_PORT_RESET
))
4860 /* Ready for next, and no reset is happening */
4861 DeviceExtension
->TimerCount
= -1;
4866 /* Not busy, but not ready for the next request */
4867 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4868 InterruptData
.Flags
&= ~SCSI_PORT_NEXT_REQUEST_READY
;
4873 if (InterruptData
.Flags
& SCSI_PORT_RESET_REPORTED
)
4875 /* Hold for a bit */
4876 DeviceExtension
->TimerCount
= 4;
4879 /* Any ready LUN? */
4880 if (InterruptData
.ReadyLun
!= NULL
)
4883 /* Process all LUNs from the list*/
4886 /* Remove it from the list first (as processed) */
4887 LunExtension
= InterruptData
.ReadyLun
;
4888 InterruptData
.ReadyLun
= LunExtension
->ReadyLun
;
4889 LunExtension
->ReadyLun
= NULL
;
4891 /* Get next request for this LUN */
4892 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4894 /* Still ready requests exist?
4895 If yes - get spinlock, if no - stop here */
4896 if (InterruptData
.ReadyLun
!= NULL
)
4897 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4904 /* Release the spinlock */
4905 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4908 /* If we ready for next packet, start it */
4909 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4910 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4912 NeedToStartIo
= FALSE
;
4914 /* Loop the completed request list */
4915 while (InterruptData
.CompletedRequests
)
4917 /* Remove the request */
4918 SrbInfo
= InterruptData
.CompletedRequests
;
4919 InterruptData
.CompletedRequests
= SrbInfo
->CompletedRequests
;
4920 SrbInfo
->CompletedRequests
= NULL
;
4923 SpiProcessCompletedRequest(DeviceExtension
,
4928 /* Loop abort request list */
4929 while (InterruptData
.CompletedAbort
)
4931 LunExtension
= InterruptData
.CompletedAbort
;
4933 /* Remove the request */
4934 InterruptData
.CompletedAbort
= LunExtension
->CompletedAbortRequests
;
4936 /* Get spinlock since we're going to change flags */
4937 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4939 /* TODO: Put SrbExtension to the list of free extensions */
4943 /* If we need - call StartIo routine */
4946 /* Make sure CurrentIrp is not null! */
4947 ASSERT(DpcDeviceObject
->CurrentIrp
!= NULL
);
4948 ScsiPortStartIo(DpcDeviceObject
, DpcDeviceObject
->CurrentIrp
);
4951 /* Everything has been done, check */
4952 if (InterruptData
.Flags
& SCSI_PORT_ENABLE_INT_REQUEST
)
4954 /* Synchronize using spinlock */
4955 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4957 /* Request an interrupt */
4958 DeviceExtension
->HwInterrupt(DeviceExtension
->MiniPortDeviceExtension
);
4960 ASSERT(DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
);
4962 /* Should interrupts be enabled again? */
4963 if (DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
)
4965 /* Clear this flag */
4966 DeviceExtension
->Flags
&= ~SCSI_PORT_DISABLE_INT_REQUESET
;
4968 /* Call a special routine to do this */
4971 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4972 SpiEnableInterrupts
,
4977 /* If we need a notification again - loop */
4978 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4981 /* Release the spinlock */
4982 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4985 DPRINT("ScsiPortDpcForIsr() done\n");
4990 SpiProcessTimeout(PVOID ServiceContext
)
4992 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
4993 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
4996 DPRINT("SpiProcessTimeout() entered\n");
4998 DeviceExtension
->TimerCount
= -1;
5000 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
5002 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET
;
5004 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET_REQUEST
)
5006 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET_REQUEST
;
5007 ScsiPortStartPacket(ServiceContext
);
5014 DPRINT("Resetting the bus\n");
5016 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
5018 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
, Bus
);
5020 /* Reset flags and set reset timeout to 4 seconds */
5021 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
5022 DeviceExtension
->TimerCount
= 4;
5025 /* If miniport requested - request a dpc for it */
5026 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5027 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
5036 SpiResetBus(PVOID ServiceContext
)
5038 PRESETBUS_PARAMS ResetParams
= (PRESETBUS_PARAMS
)ServiceContext
;
5039 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5041 /* Perform the bus reset */
5042 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ResetParams
->DeviceExtension
;
5043 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
,
5044 ResetParams
->PathId
);
5046 /* Set flags and start the timer */
5047 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
5048 DeviceExtension
->TimerCount
= 4;
5050 /* If miniport requested - give him a DPC */
5051 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5052 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
5059 // This function handles timeouts and other time delayed processing
5064 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
5065 // IN PVOID Context the Controller extension for the
5066 // controller the device is on
5069 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
5072 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5073 PSCSI_PORT_LUN_EXTENSION LunExtension
;
5077 DPRINT("ScsiPortIoTimer()\n");
5079 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
5081 /* Protect with the spinlock */
5082 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5084 /* Check timeouts */
5085 if (DeviceExtension
->TimerCount
> 0)
5087 /* Decrease the timeout counter */
5088 DeviceExtension
->TimerCount
--;
5090 if (DeviceExtension
->TimerCount
== 0)
5092 /* Timeout, process it */
5093 if (KeSynchronizeExecution(DeviceExtension
->Interrupt
,
5095 DeviceExtension
->DeviceObject
))
5097 DPRINT("Error happened during processing timeout, but nothing critical\n");
5101 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5103 /* We should exit now, since timeout is processed */
5107 /* Per-Lun scanning of timeouts is needed... */
5108 for (Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
5110 LunExtension
= DeviceExtension
->LunExtensionList
[Lun
];
5112 while (LunExtension
)
5114 if (LunExtension
->Flags
& LUNEX_BUSY
)
5116 if (!(LunExtension
->Flags
&
5117 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_FROZEN_QUEUE
)))
5119 DPRINT("Retrying busy request\n");
5121 /* Clear flags, and retry busy request */
5122 LunExtension
->Flags
&= ~(LUNEX_BUSY
| LUNEX_FULL_QUEUE
);
5123 Irp
= LunExtension
->BusyRequest
;
5125 /* Clearing busy request */
5126 LunExtension
->BusyRequest
= NULL
;
5128 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5130 IoStartPacket(DeviceObject
, Irp
, (PULONG
)NULL
, NULL
);
5132 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5135 else if (LunExtension
->RequestTimeout
== 0)
5137 RESETBUS_PARAMS ResetParams
;
5139 LunExtension
->RequestTimeout
= -1;
5141 DPRINT("Request timed out, resetting bus\n");
5143 /* Pass params to the bus reset routine */
5144 ResetParams
.PathId
= LunExtension
->PathId
;
5145 ResetParams
.DeviceExtension
= DeviceExtension
;
5147 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
5151 DPRINT1("Reset failed\n");
5154 else if (LunExtension
->RequestTimeout
> 0)
5156 /* Decrement the timeout counter */
5157 LunExtension
->RequestTimeout
--;
5160 LunExtension
= LunExtension
->Next
;
5164 /* Release the spinlock */
5165 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5168 /**********************************************************************
5173 * Builds the registry device map of all device which are attached
5174 * to the given SCSI HBA port. The device map is located at:
5175 * \Registry\Machine\DeviceMap\Scsi
5185 * Name of registry driver service key.
5192 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5193 PUNICODE_STRING RegistryPath
)
5195 PSCSI_PORT_LUN_EXTENSION LunExtension
;
5196 OBJECT_ATTRIBUTES ObjectAttributes
;
5197 UNICODE_STRING KeyName
;
5198 UNICODE_STRING ValueName
;
5199 WCHAR NameBuffer
[64];
5202 HANDLE ScsiPortKey
= NULL
;
5203 HANDLE ScsiBusKey
= NULL
;
5204 HANDLE ScsiInitiatorKey
= NULL
;
5205 HANDLE ScsiTargetKey
= NULL
;
5206 HANDLE ScsiLunKey
= NULL
;
5209 ULONG CurrentTarget
;
5216 DPRINT("SpiBuildDeviceMap() called\n");
5218 if (DeviceExtension
== NULL
|| RegistryPath
== NULL
)
5220 DPRINT1("Invalid parameter\n");
5221 return(STATUS_INVALID_PARAMETER
);
5224 /* Open or create the 'Scsi' subkey */
5225 RtlInitUnicodeString(&KeyName
,
5226 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
5227 InitializeObjectAttributes(&ObjectAttributes
,
5229 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
5232 Status
= ZwCreateKey(&ScsiKey
,
5237 REG_OPTION_VOLATILE
,
5239 if (!NT_SUCCESS(Status
))
5241 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5245 /* Create new 'Scsi Port X' subkey */
5246 DPRINT("Scsi Port %lu\n",
5247 DeviceExtension
->PortNumber
);
5249 swprintf(NameBuffer
,
5251 DeviceExtension
->PortNumber
);
5252 RtlInitUnicodeString(&KeyName
,
5254 InitializeObjectAttributes(&ObjectAttributes
,
5259 Status
= ZwCreateKey(&ScsiPortKey
,
5264 REG_OPTION_VOLATILE
,
5267 if (!NT_SUCCESS(Status
))
5269 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5274 * Create port-specific values
5277 /* Set 'DMA Enabled' (REG_DWORD) value */
5278 UlongData
= (ULONG
)!DeviceExtension
->PortCapabilities
.AdapterUsesPio
;
5279 DPRINT(" DMA Enabled = %s\n", (UlongData
) ? "TRUE" : "FALSE");
5280 RtlInitUnicodeString(&ValueName
,
5282 Status
= ZwSetValueKey(ScsiPortKey
,
5288 if (!NT_SUCCESS(Status
))
5290 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status
);
5291 ZwClose(ScsiPortKey
);
5295 /* Set 'Driver' (REG_SZ) value */
5296 DriverName
= wcsrchr(RegistryPath
->Buffer
, L
'\\') + 1;
5297 RtlInitUnicodeString(&ValueName
,
5299 Status
= ZwSetValueKey(ScsiPortKey
,
5304 (wcslen(DriverName
) + 1) * sizeof(WCHAR
));
5305 if (!NT_SUCCESS(Status
))
5307 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status
);
5308 ZwClose(ScsiPortKey
);
5312 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
5313 UlongData
= (ULONG
)DeviceExtension
->PortConfig
->BusInterruptLevel
;
5314 DPRINT(" Interrupt = %lu\n", UlongData
);
5315 RtlInitUnicodeString(&ValueName
,
5317 Status
= ZwSetValueKey(ScsiPortKey
,
5323 if (!NT_SUCCESS(Status
))
5325 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status
);
5326 ZwClose(ScsiPortKey
);
5330 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
5331 UlongData
= ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension
->PortConfig
->AccessRanges
)[0].RangeStart
);
5332 DPRINT(" IOAddress = %lx\n", UlongData
);
5333 RtlInitUnicodeString(&ValueName
,
5335 Status
= ZwSetValueKey(ScsiPortKey
,
5341 if (!NT_SUCCESS(Status
))
5343 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status
);
5344 ZwClose(ScsiPortKey
);
5348 /* Enumerate buses */
5349 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
->NumberOfBuses
; BusNumber
++)
5351 /* Create 'Scsi Bus X' key */
5352 DPRINT(" Scsi Bus %lu\n", BusNumber
);
5353 swprintf(NameBuffer
,
5356 RtlInitUnicodeString(&KeyName
,
5358 InitializeObjectAttributes(&ObjectAttributes
,
5363 Status
= ZwCreateKey(&ScsiBusKey
,
5368 REG_OPTION_VOLATILE
,
5370 if (!NT_SUCCESS(Status
))
5372 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5376 /* Create 'Initiator Id X' key */
5377 DPRINT(" Initiator Id %u\n",
5378 DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5379 swprintf(NameBuffer
,
5381 (unsigned int)(UCHAR
)DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5382 RtlInitUnicodeString(&KeyName
,
5384 InitializeObjectAttributes(&ObjectAttributes
,
5389 Status
= ZwCreateKey(&ScsiInitiatorKey
,
5394 REG_OPTION_VOLATILE
,
5396 if (!NT_SUCCESS(Status
))
5398 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5402 /* FIXME: Are there any initiator values (??) */
5404 ZwClose(ScsiInitiatorKey
);
5405 ScsiInitiatorKey
= NULL
;
5408 /* Enumerate targets */
5409 CurrentTarget
= (ULONG
)-1;
5410 ScsiTargetKey
= NULL
;
5411 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
5413 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
5415 LunExtension
= SpiGetLunExtension(DeviceExtension
,
5419 if (LunExtension
!= NULL
)
5421 if (Target
!= CurrentTarget
)
5423 /* Close old target key */
5424 if (ScsiTargetKey
!= NULL
)
5426 ZwClose(ScsiTargetKey
);
5427 ScsiTargetKey
= NULL
;
5430 /* Create 'Target Id X' key */
5431 DPRINT(" Target Id %lu\n", Target
);
5432 swprintf(NameBuffer
,
5435 RtlInitUnicodeString(&KeyName
,
5437 InitializeObjectAttributes(&ObjectAttributes
,
5442 Status
= ZwCreateKey(&ScsiTargetKey
,
5447 REG_OPTION_VOLATILE
,
5449 if (!NT_SUCCESS(Status
))
5451 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5455 CurrentTarget
= Target
;
5458 /* Create 'Logical Unit Id X' key */
5459 DPRINT(" Logical Unit Id %lu\n", Lun
);
5460 swprintf(NameBuffer
,
5461 L
"Logical Unit Id %lu",
5463 RtlInitUnicodeString(&KeyName
,
5465 InitializeObjectAttributes(&ObjectAttributes
,
5470 Status
= ZwCreateKey(&ScsiLunKey
,
5475 REG_OPTION_VOLATILE
,
5477 if (!NT_SUCCESS(Status
))
5479 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5483 /* Set 'Identifier' (REG_SZ) value */
5484 swprintf(NameBuffer
,
5486 LunExtension
->InquiryData
.VendorId
,
5487 LunExtension
->InquiryData
.ProductId
,
5488 LunExtension
->InquiryData
.ProductRevisionLevel
);
5489 DPRINT(" Identifier = '%S'\n", NameBuffer
);
5490 RtlInitUnicodeString(&ValueName
,
5492 Status
= ZwSetValueKey(ScsiLunKey
,
5497 (wcslen(NameBuffer
) + 1) * sizeof(WCHAR
));
5498 if (!NT_SUCCESS(Status
))
5500 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status
);
5504 /* Set 'Type' (REG_SZ) value */
5505 switch (LunExtension
->InquiryData
.DeviceType
)
5508 TypeName
= L
"DiskPeripheral";
5511 TypeName
= L
"TapePeripheral";
5514 TypeName
= L
"PrinterPeripheral";
5517 TypeName
= L
"WormPeripheral";
5520 TypeName
= L
"CdRomPeripheral";
5523 TypeName
= L
"ScannerPeripheral";
5526 TypeName
= L
"OpticalDiskPeripheral";
5529 TypeName
= L
"MediumChangerPeripheral";
5532 TypeName
= L
"CommunicationPeripheral";
5535 TypeName
= L
"OtherPeripheral";
5538 DPRINT(" Type = '%S'\n", TypeName
);
5539 RtlInitUnicodeString(&ValueName
,
5541 Status
= ZwSetValueKey(ScsiLunKey
,
5546 (wcslen(TypeName
) + 1) * sizeof(WCHAR
));
5547 if (!NT_SUCCESS(Status
))
5549 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status
);
5553 ZwClose(ScsiLunKey
);
5558 /* Close old target key */
5559 if (ScsiTargetKey
!= NULL
)
5561 ZwClose(ScsiTargetKey
);
5562 ScsiTargetKey
= NULL
;
5566 ZwClose(ScsiBusKey
);
5571 if (ScsiLunKey
!= NULL
)
5572 ZwClose (ScsiLunKey
);
5574 if (ScsiInitiatorKey
!= NULL
)
5575 ZwClose (ScsiInitiatorKey
);
5577 if (ScsiTargetKey
!= NULL
)
5578 ZwClose (ScsiTargetKey
);
5580 if (ScsiBusKey
!= NULL
)
5581 ZwClose (ScsiBusKey
);
5583 if (ScsiPortKey
!= NULL
)
5584 ZwClose (ScsiPortKey
);
5586 DPRINT("SpiBuildDeviceMap() done\n");
5593 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
5594 IN PVOID DeviceObject
,
5595 IN PVOID SystemArgument1
,
5596 IN PVOID SystemArgument2
)
5598 DPRINT1("Miniport timer DPC\n");
5603 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5604 PHW_INITIALIZATION_DATA HwInitData
,
5605 PCONFIGURATION_INFO InternalConfigInfo
,
5606 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5609 UNICODE_STRING UnicodeString
;
5610 OBJECT_ATTRIBUTES ObjectAttributes
;
5611 PCONFIGURATION_INFORMATION DdkConfigInformation
;
5612 HANDLE RootKey
, Key
;
5614 WCHAR DeviceBuffer
[16];
5615 WCHAR StrBuffer
[512];
5619 /* Zero out the struct if told so */
5622 /* First zero the portconfig */
5623 RtlZeroMemory(ConfigInfo
, sizeof(PORT_CONFIGURATION_INFORMATION
));
5625 /* Then access ranges */
5626 RtlZeroMemory(InternalConfigInfo
->AccessRanges
,
5627 HwInitData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
5629 /* Initialize the struct */
5630 ConfigInfo
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
5631 ConfigInfo
->AdapterInterfaceType
= HwInitData
->AdapterInterfaceType
;
5632 ConfigInfo
->InterruptMode
= Latched
;
5633 ConfigInfo
->DmaChannel
= SP_UNINITIALIZED_VALUE
;
5634 ConfigInfo
->DmaPort
= SP_UNINITIALIZED_VALUE
;
5635 ConfigInfo
->MaximumTransferLength
= SP_UNINITIALIZED_VALUE
;
5636 ConfigInfo
->NumberOfAccessRanges
= HwInitData
->NumberOfAccessRanges
;
5637 ConfigInfo
->MaximumNumberOfTargets
= 8;
5639 /* Store parameters */
5640 ConfigInfo
->NeedPhysicalAddresses
= HwInitData
->NeedPhysicalAddresses
;
5641 ConfigInfo
->MapBuffers
= HwInitData
->MapBuffers
;
5642 ConfigInfo
->AutoRequestSense
= HwInitData
->AutoRequestSense
;
5643 ConfigInfo
->ReceiveEvent
= HwInitData
->ReceiveEvent
;
5644 ConfigInfo
->TaggedQueuing
= HwInitData
->TaggedQueuing
;
5645 ConfigInfo
->MultipleRequestPerLu
= HwInitData
->MultipleRequestPerLu
;
5647 /* Get the disk usage */
5648 DdkConfigInformation
= IoGetConfigurationInformation();
5649 ConfigInfo
->AtdiskPrimaryClaimed
= DdkConfigInformation
->AtDiskPrimaryAddressClaimed
;
5650 ConfigInfo
->AtdiskSecondaryClaimed
= DdkConfigInformation
->AtDiskSecondaryAddressClaimed
;
5652 /* Initiator bus id is not set */
5653 for (Bus
= 0; Bus
< 8; Bus
++)
5654 ConfigInfo
->InitiatorBusId
[Bus
] = (CCHAR
)SP_UNINITIALIZED_VALUE
;
5657 ConfigInfo
->NumberOfPhysicalBreaks
= 17;
5659 /* Clear this information */
5660 InternalConfigInfo
->DisableTaggedQueueing
= FALSE
;
5661 InternalConfigInfo
->DisableMultipleLun
= FALSE
;
5663 /* Store Bus Number */
5664 ConfigInfo
->SystemIoBusNumber
= InternalConfigInfo
->BusNumber
;
5668 if (ConfigInfo
->AdapterInterfaceType
== Internal
)
5670 /* Open registry key for HW database */
5671 InitializeObjectAttributes(&ObjectAttributes
,
5672 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
5673 OBJ_CASE_INSENSITIVE
,
5677 Status
= ZwOpenKey(&RootKey
,
5681 if (NT_SUCCESS(Status
))
5683 /* Create name for it */
5684 swprintf(StrBuffer
, L
"ScsiAdapter\\%lu",
5685 InternalConfigInfo
->AdapterNumber
);
5687 RtlInitUnicodeString(&UnicodeString
, StrBuffer
);
5689 /* Open device key */
5690 InitializeObjectAttributes(&ObjectAttributes
,
5692 OBJ_CASE_INSENSITIVE
,
5696 Status
= ZwOpenKey(&Key
,
5702 if (NT_SUCCESS(Status
))
5704 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5706 DPRINT("Hardware info found at %S\n", StrBuffer
);
5709 SpiParseDeviceInfo(DeviceExtension
,
5715 InternalConfigInfo
->BusNumber
= 0;
5719 /* Try the next adapter */
5720 InternalConfigInfo
->AdapterNumber
++;
5726 /* Info was not found, exit */
5727 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status
);
5728 return STATUS_DEVICE_DOES_NOT_EXIST
;
5733 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status
);
5737 /* Look at device params */
5739 if (InternalConfigInfo
->Parameter
)
5741 ExFreePool(InternalConfigInfo
->Parameter
);
5742 InternalConfigInfo
->Parameter
= NULL
;
5745 if (InternalConfigInfo
->ServiceKey
!= NULL
)
5747 swprintf(DeviceBuffer
, L
"Device%lu", InternalConfigInfo
->AdapterNumber
);
5748 RtlInitUnicodeString(&UnicodeString
, DeviceBuffer
);
5750 /* Open the service key */
5751 InitializeObjectAttributes(&ObjectAttributes
,
5753 OBJ_CASE_INSENSITIVE
,
5754 InternalConfigInfo
->ServiceKey
,
5757 Status
= ZwOpenKey(&Key
,
5762 /* Parse device key */
5763 if (InternalConfigInfo
->DeviceKey
!= NULL
)
5765 SpiParseDeviceInfo(DeviceExtension
,
5766 InternalConfigInfo
->DeviceKey
,
5772 /* Then parse hw info */
5775 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5777 SpiParseDeviceInfo(DeviceExtension
,
5788 /* Adapter not found, go try the next one */
5789 InternalConfigInfo
->AdapterNumber
++;
5798 /* Update the last adapter number */
5799 InternalConfigInfo
->LastAdapterNumber
= InternalConfigInfo
->AdapterNumber
;
5801 /* Do we have this kind of bus at all? */
5803 Status
= IoQueryDeviceDescription(&HwInitData
->AdapterInterfaceType
,
5804 &InternalConfigInfo
->BusNumber
,
5809 SpQueryDeviceCallout
,
5812 /* This bus was not found */
5815 INTERFACE_TYPE InterfaceType
= Eisa
;
5817 /* Check for EISA */
5818 if (HwInitData
->AdapterInterfaceType
== Isa
)
5820 Status
= IoQueryDeviceDescription(&InterfaceType
,
5821 &InternalConfigInfo
->BusNumber
,
5826 SpQueryDeviceCallout
,
5829 /* Return respectively */
5831 return STATUS_SUCCESS
;
5833 return STATUS_DEVICE_DOES_NOT_EXIST
;
5837 return STATUS_DEVICE_DOES_NOT_EXIST
;
5842 return STATUS_SUCCESS
;
5847 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5849 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5850 IN PCONFIGURATION_INFO InternalConfigInfo
,
5853 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
5854 PCM_FULL_RESOURCE_DESCRIPTOR FullResource
;
5855 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
5856 PCM_SCSI_DEVICE_DATA ScsiDeviceData
;
5857 ULONG Length
, Count
;
5858 ULONG Index
= 0, RangeCount
= 0;
5859 UNICODE_STRING UnicodeString
;
5860 ANSI_STRING AnsiString
;
5861 NTSTATUS Status
= STATUS_SUCCESS
;
5863 KeyValueInformation
= (PKEY_VALUE_FULL_INFORMATION
) Buffer
;
5865 /* Loop through all values in the device node */
5868 Status
= ZwEnumerateValueKey(Key
,
5870 KeyValueFullInformation
,
5875 if (!NT_SUCCESS(Status
))
5880 /* Length for DWORD is ok? */
5881 if (KeyValueInformation
->Type
== REG_DWORD
&&
5882 KeyValueInformation
->DataLength
!= sizeof(ULONG
))
5887 /* Get MaximumLogicalUnit */
5888 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumLogicalUnit",
5889 KeyValueInformation
->NameLength
/2) == 0)
5892 if (KeyValueInformation
->Type
!= REG_DWORD
)
5894 DPRINT("Bad data type for MaximumLogicalUnit\n");
5898 DeviceExtension
->MaxLunCount
= *((PUCHAR
)
5899 (Buffer
+ KeyValueInformation
->DataOffset
));
5901 /* Check / reset if needed */
5902 if (DeviceExtension
->MaxLunCount
> SCSI_MAXIMUM_LOGICAL_UNITS
)
5903 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
5905 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension
->MaxLunCount
);
5908 /* Get InitiatorTargetId */
5909 if (_wcsnicmp(KeyValueInformation
->Name
, L
"InitiatorTargetId",
5910 KeyValueInformation
->NameLength
/ 2) == 0)
5913 if (KeyValueInformation
->Type
!= REG_DWORD
)
5915 DPRINT("Bad data type for InitiatorTargetId\n");
5919 ConfigInfo
->InitiatorBusId
[0] = *((PUCHAR
)
5920 (Buffer
+ KeyValueInformation
->DataOffset
));
5922 /* Check / reset if needed */
5923 if (ConfigInfo
->InitiatorBusId
[0] > ConfigInfo
->MaximumNumberOfTargets
- 1)
5924 ConfigInfo
->InitiatorBusId
[0] = (CCHAR
)-1;
5926 DPRINT("InitiatorTargetId = %d\n", ConfigInfo
->InitiatorBusId
[0]);
5930 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ScsiDebug",
5931 KeyValueInformation
->NameLength
/2) == 0)
5933 DPRINT("ScsiDebug key not supported\n");
5936 /* Check for a breakpoint */
5937 if (_wcsnicmp(KeyValueInformation
->Name
, L
"BreakPointOnEntry",
5938 KeyValueInformation
->NameLength
/2) == 0)
5940 DPRINT1("Breakpoint on entry requested!\n");
5944 /* Get DisableSynchronousTransfers */
5945 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableSynchronousTransfers",
5946 KeyValueInformation
->NameLength
/2) == 0)
5948 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5949 DPRINT("Synch transfers disabled\n");
5952 /* Get DisableDisconnects */
5953 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableDisconnects",
5954 KeyValueInformation
->NameLength
/2) == 0)
5956 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
5957 DPRINT("Disconnects disabled\n");
5960 /* Get DisableTaggedQueuing */
5961 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableTaggedQueuing",
5962 KeyValueInformation
->NameLength
/2) == 0)
5964 InternalConfigInfo
->DisableTaggedQueueing
= TRUE
;
5965 DPRINT("Tagged queueing disabled\n");
5968 /* Get DisableMultipleRequests */
5969 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableMultipleRequests",
5970 KeyValueInformation
->NameLength
/2) == 0)
5972 InternalConfigInfo
->DisableMultipleLun
= TRUE
;
5973 DPRINT("Multiple requests disabled\n");
5976 /* Get DriverParameters */
5977 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DriverParameters",
5978 KeyValueInformation
->NameLength
/2) == 0)
5980 /* Skip if nothing */
5981 if (KeyValueInformation
->DataLength
== 0)
5984 /* If there was something previously allocated - free it */
5985 if (InternalConfigInfo
->Parameter
!= NULL
)
5986 ExFreePool(InternalConfigInfo
->Parameter
);
5989 InternalConfigInfo
->Parameter
= ExAllocatePoolWithTag(NonPagedPool
,
5990 KeyValueInformation
->DataLength
, TAG_SCSIPORT
);
5992 if (InternalConfigInfo
->Parameter
!= NULL
)
5994 if (KeyValueInformation
->Type
!= REG_SZ
)
5998 InternalConfigInfo
->Parameter
,
5999 (PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
,
6000 KeyValueInformation
->DataLength
);
6004 /* If it's a unicode string, convert it to ansi */
6005 UnicodeString
.Length
= (USHORT
)KeyValueInformation
->DataLength
;
6006 UnicodeString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
6007 UnicodeString
.Buffer
=
6008 (PWSTR
)((PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
6010 AnsiString
.Length
= 0;
6011 AnsiString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
6012 AnsiString
.Buffer
= (PCHAR
)InternalConfigInfo
->Parameter
;
6014 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
6018 /* In case of error, free the allocated space */
6019 if (!NT_SUCCESS(Status
))
6021 ExFreePool(InternalConfigInfo
->Parameter
);
6022 InternalConfigInfo
->Parameter
= NULL
;
6028 DPRINT("Found driver parameter\n");
6031 /* Get MaximumSGList */
6032 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumSGList",
6033 KeyValueInformation
->NameLength
/2) == 0)
6035 if (KeyValueInformation
->Type
!= REG_DWORD
)
6037 DPRINT("Bad data type for MaximumSGList\n");
6041 ConfigInfo
->NumberOfPhysicalBreaks
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
6044 if (ConfigInfo
->NumberOfPhysicalBreaks
> SCSI_MAXIMUM_PHYSICAL_BREAKS
)
6046 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MAXIMUM_PHYSICAL_BREAKS
;
6048 else if (ConfigInfo
->NumberOfPhysicalBreaks
< SCSI_MINIMUM_PHYSICAL_BREAKS
)
6050 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MINIMUM_PHYSICAL_BREAKS
;
6053 DPRINT("MaximumSGList = %d\n", ConfigInfo
->NumberOfPhysicalBreaks
);
6056 /* Get NumberOfRequests */
6057 if (_wcsnicmp(KeyValueInformation
->Name
, L
"NumberOfRequests",
6058 KeyValueInformation
->NameLength
/2) == 0)
6060 if (KeyValueInformation
->Type
!= REG_DWORD
)
6062 DPRINT("NumberOfRequests has wrong data type\n");
6066 DeviceExtension
->RequestsNumber
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
6069 if (DeviceExtension
->RequestsNumber
< 16)
6071 DeviceExtension
->RequestsNumber
= 16;
6073 else if (DeviceExtension
->RequestsNumber
> 512)
6075 DeviceExtension
->RequestsNumber
= 512;
6078 DPRINT("Number Of Requests = %d\n", DeviceExtension
->RequestsNumber
);
6081 /* Get resource list */
6082 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ResourceList",
6083 KeyValueInformation
->NameLength
/2) == 0 ||
6084 _wcsnicmp(KeyValueInformation
->Name
, L
"Configuration Data",
6085 KeyValueInformation
->NameLength
/2) == 0 )
6087 if (KeyValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
||
6088 KeyValueInformation
->DataLength
< sizeof(REG_FULL_RESOURCE_DESCRIPTOR
))
6090 DPRINT("Bad data type for ResourceList\n");
6095 DPRINT("Found ResourceList\n");
6098 FullResource
= (PCM_FULL_RESOURCE_DESCRIPTOR
)(Buffer
+ KeyValueInformation
->DataOffset
);
6100 /* Copy some info from it */
6101 InternalConfigInfo
->BusNumber
= FullResource
->BusNumber
;
6102 ConfigInfo
->SystemIoBusNumber
= FullResource
->BusNumber
;
6104 /* Loop through it */
6105 for (Count
= 0; Count
< FullResource
->PartialResourceList
.Count
; Count
++)
6107 /* Get partial descriptor */
6109 &FullResource
->PartialResourceList
.PartialDescriptors
[Count
];
6111 /* Check datalength */
6112 if ((ULONG
)((PCHAR
)(PartialDescriptor
+ 1) -
6113 (PCHAR
)FullResource
) > KeyValueInformation
->DataLength
)
6115 DPRINT("Resource data is of incorrect size\n");
6119 switch (PartialDescriptor
->Type
)
6121 case CmResourceTypePort
:
6122 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
6124 DPRINT("Too many access ranges\n");
6128 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= FALSE
;
6129 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Port
.Start
;
6130 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Port
.Length
;
6135 case CmResourceTypeMemory
:
6136 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
6138 DPRINT("Too many access ranges\n");
6142 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= TRUE
;
6143 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Memory
.Start
;
6144 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Memory
.Length
;
6149 case CmResourceTypeInterrupt
:
6150 ConfigInfo
->BusInterruptLevel
=
6151 PartialDescriptor
->u
.Interrupt
.Level
;
6153 ConfigInfo
->BusInterruptVector
=
6154 PartialDescriptor
->u
.Interrupt
.Vector
;
6157 case CmResourceTypeDma
:
6158 ConfigInfo
->DmaChannel
= PartialDescriptor
->u
.Dma
.Channel
;
6159 ConfigInfo
->DmaPort
= PartialDescriptor
->u
.Dma
.Port
;
6162 case CmResourceTypeDeviceSpecific
:
6163 if (PartialDescriptor
->u
.DeviceSpecificData
.DataSize
<
6164 sizeof(CM_SCSI_DEVICE_DATA
) ||
6165 (PCHAR
) (PartialDescriptor
+ 1) - (PCHAR
)FullResource
+
6166 PartialDescriptor
->u
.DeviceSpecificData
.DataSize
>
6167 KeyValueInformation
->DataLength
)
6169 DPRINT("Resource data length is incorrect");
6173 /* Set only one field from it */
6174 ScsiDeviceData
= (PCM_SCSI_DEVICE_DATA
) (PartialDescriptor
+1);
6175 ConfigInfo
->InitiatorBusId
[0] = ScsiDeviceData
->HostIdentifier
;
6185 SpQueryDeviceCallout(IN PVOID Context
,
6186 IN PUNICODE_STRING PathName
,
6187 IN INTERFACE_TYPE BusType
,
6189 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
6190 IN CONFIGURATION_TYPE ControllerType
,
6191 IN ULONG ControllerNumber
,
6192 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
6193 IN CONFIGURATION_TYPE PeripheralType
,
6194 IN ULONG PeripheralNumber
,
6195 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
6197 PBOOLEAN Found
= (PBOOLEAN
)Context
;
6198 /* We just set our Found variable to TRUE */
6201 return STATUS_SUCCESS
;
6204 IO_ALLOCATION_ACTION
6206 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject
,
6208 IN PVOID MapRegisterBase
,
6212 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
6214 /* Guard access with the spinlock */
6215 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
6217 /* Save MapRegisterBase we've got here */
6218 DeviceExtension
->MapRegisterBase
= MapRegisterBase
;
6220 /* Start pending request */
6221 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
6222 ScsiPortStartPacket
, DeviceObject
);
6224 /* Release spinlock we took */
6225 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
6232 SpiStatusSrbToNt(UCHAR SrbStatus
)
6234 switch (SRB_STATUS(SrbStatus
))
6236 case SRB_STATUS_TIMEOUT
:
6237 case SRB_STATUS_COMMAND_TIMEOUT
:
6238 return STATUS_IO_TIMEOUT
;
6240 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH
:
6241 case SRB_STATUS_BAD_FUNCTION
:
6242 return STATUS_INVALID_DEVICE_REQUEST
;
6244 case SRB_STATUS_NO_DEVICE
:
6245 case SRB_STATUS_INVALID_LUN
:
6246 case SRB_STATUS_INVALID_TARGET_ID
:
6247 case SRB_STATUS_NO_HBA
:
6248 return STATUS_DEVICE_DOES_NOT_EXIST
;
6250 case SRB_STATUS_DATA_OVERRUN
:
6251 return STATUS_BUFFER_OVERFLOW
;
6253 case SRB_STATUS_SELECTION_TIMEOUT
:
6254 return STATUS_DEVICE_NOT_CONNECTED
;
6257 return STATUS_IO_DEVICE_ERROR
;
6260 return STATUS_IO_DEVICE_ERROR
;
6264 #undef ScsiPortConvertPhysicalAddressToUlong
6269 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
6271 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
6272 return(Address
.u
.LowPart
);