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 *****************************************************************/
41 #include "scsiport_int.h"
43 ULONG InternalDebugLevel
= 0x00;
45 #undef ScsiPortMoveMemory
47 /* GLOBALS *******************************************************************/
50 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
51 IN PDEVICE_OBJECT DeviceObject
,
52 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
53 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
54 IN PUNICODE_STRING RegistryPath
,
56 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
);
59 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
62 static DRIVER_DISPATCH ScsiPortDispatchScsi
;
64 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
68 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
71 static DRIVER_STARTIO ScsiPortStartIo
;
73 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
77 ScsiPortStartPacket(IN OUT PVOID Context
);
81 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
82 PVOID MapRegisterBase
, PVOID Context
);
84 static PSCSI_PORT_LUN_EXTENSION
85 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
87 static PSCSI_PORT_LUN_EXTENSION
88 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
93 static PSCSI_REQUEST_BLOCK_INFO
94 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
95 PSCSI_PORT_LUN_EXTENSION LunExtension
,
96 PSCSI_REQUEST_BLOCK Srb
);
99 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
100 IN PSCSI_LUN_INFO LunInfo
);
103 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
106 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
109 static PSCSI_REQUEST_BLOCK_INFO
110 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
117 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
118 IN PVOID ServiceContext
);
121 ScsiPortDpcForIsr(IN PKDPC Dpc
,
122 IN PDEVICE_OBJECT DpcDeviceObject
,
124 IN PVOID DpcContext
);
127 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
132 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject
,
134 IN PVOID MapRegisterBase
,
138 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
139 PUNICODE_STRING RegistryPath
);
142 SpiStatusSrbToNt(UCHAR SrbStatus
);
145 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
146 IN PSCSI_REQUEST_BLOCK Srb
);
148 static IO_COMPLETION_ROUTINE SpiCompletionRoutine
;
150 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
156 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
157 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
158 OUT PBOOLEAN NeedToCallStartIo
);
161 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
162 IN PSCSI_PORT_LUN_EXTENSION LunExtension
);
165 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
166 IN PVOID DeviceObject
,
167 IN PVOID SystemArgument1
,
168 IN PVOID SystemArgument2
);
171 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
172 PHW_INITIALIZATION_DATA HwInitData
,
173 PCONFIGURATION_INFO InternalConfigInfo
,
174 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
178 SpQueryDeviceCallout(IN PVOID Context
,
179 IN PUNICODE_STRING PathName
,
180 IN INTERFACE_TYPE BusType
,
182 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
183 IN CONFIGURATION_TYPE ControllerType
,
184 IN ULONG ControllerNumber
,
185 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
186 IN CONFIGURATION_TYPE PeripheralType
,
187 IN ULONG PeripheralNumber
,
188 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
);
191 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
193 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
194 IN PCONFIGURATION_INFO InternalConfigInfo
,
198 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
199 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
200 IN PPORT_CONFIGURATION_INFORMATION PortConfig
);
202 static PCM_RESOURCE_LIST
203 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
204 PPORT_CONFIGURATION_INFORMATION PortConfig
);
207 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
210 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
214 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
);
216 NTHALAPI ULONG NTAPI
HalGetBusData(BUS_DATA_TYPE
, ULONG
, ULONG
, PVOID
, ULONG
);
217 NTHALAPI ULONG NTAPI
HalGetInterruptVector(INTERFACE_TYPE
, ULONG
, ULONG
, ULONG
, PKIRQL
, PKAFFINITY
);
218 NTHALAPI NTSTATUS NTAPI
HalAssignSlotResources(PUNICODE_STRING
, PUNICODE_STRING
, PDRIVER_OBJECT
, PDEVICE_OBJECT
, INTERFACE_TYPE
, ULONG
, ULONG
, PCM_RESOURCE_LIST
*);
220 /* FUNCTIONS *****************************************************************/
222 /**********************************************************************
227 * This function initializes the driver.
234 * System allocated Driver Object for this driver.
237 * Name of registry driver service key.
244 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
245 IN PUNICODE_STRING RegistryPath
)
247 DPRINT("ScsiPort Driver %s\n", VERSION
);
248 return(STATUS_SUCCESS
);
252 /**********************************************************************
257 * Prints debugging messages.
264 * Debug level of the given message.
267 * Pointer to printf()-compatible format string.
270 Additional output data (see printf()).
279 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
280 IN PCHAR DebugMessage
,
286 if (DebugPrintLevel
> InternalDebugLevel
)
289 va_start(ap
, DebugMessage
);
290 vsprintf(Buffer
, DebugMessage
, ap
);
296 /* An internal helper function for ScsiPortCompleteRequest */
299 SpiCompleteRequest(IN PVOID HwDeviceExtension
,
300 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
303 PSCSI_REQUEST_BLOCK Srb
;
305 /* Get current SRB */
308 /* Return if there is no SRB or it is not active */
309 if (!Srb
|| !(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
)) return;
312 Srb
->SrbStatus
= SrbStatus
;
314 /* Set data transfered to 0 */
315 Srb
->DataTransferLength
= 0;
318 ScsiPortNotification(RequestComplete
,
327 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
333 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
334 PSCSI_PORT_LUN_EXTENSION LunExtension
;
335 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
336 PLIST_ENTRY ListEntry
;
340 DPRINT("ScsiPortCompleteRequest() called\n");
342 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
343 SCSI_PORT_DEVICE_EXTENSION
,
344 MiniPortDeviceExtension
);
346 /* Go through all buses */
347 for (BusNumber
= 0; BusNumber
< 8; BusNumber
++)
349 /* Go through all targets */
350 for (Target
= 0; Target
< DeviceExtension
->MaxTargedIds
; Target
++)
352 /* Get logical unit list head */
353 LunExtension
= DeviceExtension
->LunExtensionList
[Target
% 8];
355 /* Go through all logical units */
358 /* Now match what caller asked with what we are at now */
359 if ((PathId
== SP_UNTAGGED
|| PathId
== LunExtension
->PathId
) &&
360 (TargetId
== SP_UNTAGGED
|| TargetId
== LunExtension
->TargetId
) &&
361 (Lun
== SP_UNTAGGED
|| Lun
== LunExtension
->Lun
))
363 /* Yes, that's what caller asked for. Complete abort requests */
364 if (LunExtension
->CompletedAbortRequests
)
366 /* TODO: Save SrbStatus in this request */
367 DPRINT1("Completing abort request without setting SrbStatus!\n");
369 /* Issue a notification request */
370 ScsiPortNotification(RequestComplete
,
372 LunExtension
->CompletedAbortRequests
);
375 /* Complete the request using our helper */
376 SpiCompleteRequest(HwDeviceExtension
,
377 &LunExtension
->SrbInfo
,
380 /* Go through the queue and complete everything there too */
381 ListEntry
= LunExtension
->SrbInfo
.Requests
.Flink
;
382 while (ListEntry
!= &LunExtension
->SrbInfo
.Requests
)
384 /* Get the actual SRB info entry */
385 SrbInfo
= CONTAINING_RECORD(ListEntry
,
386 SCSI_REQUEST_BLOCK_INFO
,
390 SpiCompleteRequest(HwDeviceExtension
,
394 /* Advance to the next request in queue */
395 ListEntry
= SrbInfo
->Requests
.Flink
;
399 /* Advance to the next one */
400 LunExtension
= LunExtension
->Next
;
410 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
412 DPRINT("ScsiPortFlushDma()\n");
421 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
422 IN PVOID MappedAddress
)
424 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
425 PMAPPED_ADDRESS NextMa
, LastMa
;
427 //DPRINT("ScsiPortFreeDeviceBase() called\n");
429 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
430 SCSI_PORT_DEVICE_EXTENSION
,
431 MiniPortDeviceExtension
);
433 /* Initialize our pointers */
434 NextMa
= DeviceExtension
->MappedAddressList
;
439 if (NextMa
->MappedAddress
== MappedAddress
)
442 MmUnmapIoSpace(MappedAddress
, NextMa
->NumberOfBytes
);
444 /* Remove it from the list */
445 if (NextMa
== DeviceExtension
->MappedAddressList
)
447 /* Remove the first entry */
448 DeviceExtension
->MappedAddressList
= NextMa
->NextMappedAddress
;
452 LastMa
->NextMappedAddress
= NextMa
->NextMappedAddress
;
455 /* Free the resources and quit */
463 NextMa
= NextMa
->NextMappedAddress
;
473 ScsiPortGetBusData(IN PVOID DeviceExtension
,
474 IN ULONG BusDataType
,
475 IN ULONG SystemIoBusNumber
,
480 DPRINT("ScsiPortGetBusData()\n");
484 /* If Length is non-zero, just forward the call to
485 HalGetBusData() function */
486 return HalGetBusData(BusDataType
,
493 /* We have a more complex case here */
502 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
503 IN ULONG BusDataType
,
504 IN ULONG SystemIoBusNumber
,
510 DPRINT("ScsiPortSetBusDataByOffset()\n");
511 return HalSetBusDataByOffset(BusDataType
,
523 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
524 IN INTERFACE_TYPE BusType
,
525 IN ULONG SystemIoBusNumber
,
526 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
527 IN ULONG NumberOfBytes
,
528 IN BOOLEAN InIoSpace
)
530 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
531 PHYSICAL_ADDRESS TranslatedAddress
;
532 PMAPPED_ADDRESS DeviceBase
;
536 //DPRINT ("ScsiPortGetDeviceBase() called\n");
538 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
539 SCSI_PORT_DEVICE_EXTENSION
,
540 MiniPortDeviceExtension
);
542 AddressSpace
= (ULONG
)InIoSpace
;
543 if (HalTranslateBusAddress(BusType
,
547 &TranslatedAddress
) == FALSE
)
553 if (AddressSpace
!= 0)
554 return((PVOID
)(ULONG_PTR
)TranslatedAddress
.QuadPart
);
556 MappedAddress
= MmMapIoSpace(TranslatedAddress
,
560 DeviceBase
= ExAllocatePoolWithTag(NonPagedPool
,
561 sizeof(MAPPED_ADDRESS
), TAG_SCSIPORT
);
563 if (DeviceBase
== NULL
)
564 return MappedAddress
;
566 DeviceBase
->MappedAddress
= MappedAddress
;
567 DeviceBase
->NumberOfBytes
= NumberOfBytes
;
568 DeviceBase
->IoAddress
= IoAddress
;
569 DeviceBase
->BusNumber
= SystemIoBusNumber
;
571 /* Link it to the Device Extension list */
572 DeviceBase
->NextMappedAddress
= DeviceExtension
->MappedAddressList
;
573 DeviceExtension
->MappedAddressList
= DeviceBase
;
575 return MappedAddress
;
582 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
587 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
588 PSCSI_PORT_LUN_EXTENSION LunExtension
;
590 DPRINT("ScsiPortGetLogicalUnit() called\n");
592 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
593 SCSI_PORT_DEVICE_EXTENSION
,
594 MiniPortDeviceExtension
);
596 /* Check the extension size */
597 if (!DeviceExtension
->LunExtensionSize
)
599 /* They didn't want one */
603 LunExtension
= SpiGetLunExtension(DeviceExtension
,
607 /* Check that the logical unit exists */
610 /* Nope, return NULL */
614 /* Return the logical unit miniport extension */
615 return (LunExtension
+ 1);
622 SCSI_PHYSICAL_ADDRESS NTAPI
623 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
624 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
625 IN PVOID VirtualAddress
,
628 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
629 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
630 SIZE_T BufferLength
= 0;
632 PSCSI_SG_ADDRESS SGList
;
633 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
635 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
636 HwDeviceExtension
, Srb
, VirtualAddress
, Length
);
638 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
639 SCSI_PORT_DEVICE_EXTENSION
,
640 MiniPortDeviceExtension
);
642 if (Srb
== NULL
|| Srb
->SenseInfoBuffer
== VirtualAddress
)
644 /* Simply look it up in the allocated common buffer */
645 Offset
= (PUCHAR
)VirtualAddress
- (PUCHAR
)DeviceExtension
->SrbExtensionBuffer
;
647 BufferLength
= DeviceExtension
->CommonBufferLength
- Offset
;
648 PhysicalAddress
.QuadPart
= DeviceExtension
->PhysicalAddress
.QuadPart
+ Offset
;
650 else if (DeviceExtension
->MapRegisters
)
652 /* Scatter-gather list must be used */
653 SrbInfo
= SpiGetSrbData(DeviceExtension
,
659 SGList
= SrbInfo
->ScatterGather
;
661 /* Find needed item in the SG list */
662 Offset
= (PCHAR
)VirtualAddress
- (PCHAR
)Srb
->DataBuffer
;
663 while (Offset
>= SGList
->Length
)
665 Offset
-= SGList
->Length
;
669 /* We're done, store length and physical address */
670 BufferLength
= SGList
->Length
- Offset
;
671 PhysicalAddress
.QuadPart
= SGList
->PhysicalAddress
.QuadPart
+ Offset
;
677 PhysicalAddress
.QuadPart
= (LONGLONG
)(SP_UNINITIALIZED_VALUE
);
680 *Length
= (ULONG
)BufferLength
;
681 return PhysicalAddress
;
688 PSCSI_REQUEST_BLOCK NTAPI
689 ScsiPortGetSrb(IN PVOID DeviceExtension
,
695 DPRINT1("ScsiPortGetSrb() unimplemented\n");
705 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
706 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
707 IN ULONG NumberOfBytes
)
709 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
710 DEVICE_DESCRIPTION DeviceDescription
;
711 ULONG MapRegistersCount
;
714 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
715 HwDeviceExtension
, ConfigInfo
, NumberOfBytes
);
717 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
718 SCSI_PORT_DEVICE_EXTENSION
,
719 MiniPortDeviceExtension
);
721 /* Check for allocated common DMA buffer */
722 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
)
724 DPRINT1("The HBA has already got a common DMA buffer!\n");
728 /* Check for DMA adapter object */
729 if (DeviceExtension
->AdapterObject
== NULL
)
731 /* Initialize DMA adapter description */
732 RtlZeroMemory(&DeviceDescription
, sizeof(DEVICE_DESCRIPTION
));
734 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
735 DeviceDescription
.Master
= ConfigInfo
->Master
;
736 DeviceDescription
.ScatterGather
= ConfigInfo
->ScatterGather
;
737 DeviceDescription
.DemandMode
= ConfigInfo
->DemandMode
;
738 DeviceDescription
.Dma32BitAddresses
= ConfigInfo
->Dma32BitAddresses
;
739 DeviceDescription
.BusNumber
= ConfigInfo
->SystemIoBusNumber
;
740 DeviceDescription
.DmaChannel
= ConfigInfo
->DmaChannel
;
741 DeviceDescription
.InterfaceType
= ConfigInfo
->AdapterInterfaceType
;
742 DeviceDescription
.DmaWidth
= ConfigInfo
->DmaWidth
;
743 DeviceDescription
.DmaSpeed
= ConfigInfo
->DmaSpeed
;
744 DeviceDescription
.MaximumLength
= ConfigInfo
->MaximumTransferLength
;
745 DeviceDescription
.DmaPort
= ConfigInfo
->DmaPort
;
747 /* Get a DMA adapter object */
748 DeviceExtension
->AdapterObject
=
749 HalGetAdapter(&DeviceDescription
, &MapRegistersCount
);
751 /* Fail in case of error */
752 if (DeviceExtension
->AdapterObject
== NULL
)
754 DPRINT1("HalGetAdapter() failed\n");
758 /* Set number of physical breaks */
759 if (ConfigInfo
->NumberOfPhysicalBreaks
!= 0 &&
760 MapRegistersCount
> ConfigInfo
->NumberOfPhysicalBreaks
)
762 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
=
763 ConfigInfo
->NumberOfPhysicalBreaks
;
767 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
= MapRegistersCount
;
771 /* Update auto request sense feature */
772 DeviceExtension
->SupportsAutoSense
= ConfigInfo
->AutoRequestSense
;
774 /* Update Srb extension size */
775 if (DeviceExtension
->SrbExtensionSize
!= ConfigInfo
->SrbExtensionSize
)
776 DeviceExtension
->SrbExtensionSize
= ConfigInfo
->SrbExtensionSize
;
778 /* Update Srb extension alloc flag */
779 if (ConfigInfo
->AutoRequestSense
|| DeviceExtension
->SrbExtensionSize
)
780 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
782 /* Allocate a common DMA buffer */
783 Status
= SpiAllocateCommonBuffer(DeviceExtension
, NumberOfBytes
);
785 if (!NT_SUCCESS(Status
))
787 DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status
);
791 return DeviceExtension
->NonCachedExtension
;
795 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
, ULONG NonCachedSize
)
797 PVOID
*SrbExtension
, CommonBuffer
;
798 ULONG CommonBufferLength
, BufSize
;
800 /* If size is 0, set it to 16 */
801 if (!DeviceExtension
->SrbExtensionSize
)
802 DeviceExtension
->SrbExtensionSize
= 16;
805 BufSize
= DeviceExtension
->SrbExtensionSize
;
807 /* Add autosense data size if needed */
808 if (DeviceExtension
->SupportsAutoSense
)
809 BufSize
+= sizeof(SENSE_DATA
);
813 BufSize
= (BufSize
+ sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
815 /* Sum up into the total common buffer length, and round it to page size */
817 ROUND_TO_PAGES(NonCachedSize
+ BufSize
* DeviceExtension
->RequestsNumber
);
820 if (!DeviceExtension
->AdapterObject
)
822 /* From nonpaged pool if there is no DMA */
823 CommonBuffer
= ExAllocatePoolWithTag(NonPagedPool
, CommonBufferLength
, TAG_SCSIPORT
);
827 /* Perform a full request since we have a DMA adapter*/
828 CommonBuffer
= HalAllocateCommonBuffer(DeviceExtension
->AdapterObject
,
830 &DeviceExtension
->PhysicalAddress
,
834 /* Fail in case of error */
836 return STATUS_INSUFFICIENT_RESOURCES
;
839 RtlZeroMemory(CommonBuffer
, CommonBufferLength
);
841 /* Store its size in Device Extension */
842 DeviceExtension
->CommonBufferLength
= CommonBufferLength
;
844 /* SrbExtension buffer is located at the beginning of the buffer */
845 DeviceExtension
->SrbExtensionBuffer
= CommonBuffer
;
847 /* Non-cached extension buffer is located at the end of
851 CommonBufferLength
-= NonCachedSize
;
852 DeviceExtension
->NonCachedExtension
= (PUCHAR
)CommonBuffer
+ CommonBufferLength
;
856 DeviceExtension
->NonCachedExtension
= NULL
;
859 if (DeviceExtension
->NeedSrbExtensionAlloc
)
861 /* Look up how many SRB data structures we need */
862 DeviceExtension
->SrbDataCount
= CommonBufferLength
/ BufSize
;
864 /* Initialize the free SRB extensions list */
865 SrbExtension
= (PVOID
*)CommonBuffer
;
866 DeviceExtension
->FreeSrbExtensions
= SrbExtension
;
868 /* Fill the remainding pointers (if we have more than 1 SRB) */
869 while (CommonBufferLength
>= 2 * BufSize
)
871 *SrbExtension
= (PVOID
*)((PCHAR
)SrbExtension
+ BufSize
);
872 SrbExtension
= *SrbExtension
;
874 CommonBufferLength
-= BufSize
;
878 return STATUS_SUCCESS
;
887 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
888 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
890 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
893 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
894 HwDeviceExtension
, PhysicalAddress
.QuadPart
);
896 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
897 SCSI_PORT_DEVICE_EXTENSION
,
898 MiniPortDeviceExtension
);
900 if (DeviceExtension
->PhysicalAddress
.QuadPart
> PhysicalAddress
.QuadPart
)
903 Offset
= (ULONG
)(PhysicalAddress
.QuadPart
- DeviceExtension
->PhysicalAddress
.QuadPart
);
905 if (Offset
>= DeviceExtension
->CommonBufferLength
)
908 return (PVOID
)((ULONG_PTR
)DeviceExtension
->SrbExtensionBuffer
+ Offset
);
912 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo
, PUNICODE_STRING RegistryPath
)
914 OBJECT_ATTRIBUTES ObjectAttributes
;
915 UNICODE_STRING KeyName
;
918 /* Open the service key */
919 InitializeObjectAttributes(&ObjectAttributes
,
921 OBJ_CASE_INSENSITIVE
,
925 Status
= ZwOpenKey(&ConfigInfo
->ServiceKey
,
929 if (!NT_SUCCESS(Status
))
931 DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath
, Status
);
932 ConfigInfo
->ServiceKey
= NULL
;
935 /* If we could open driver's service key, then proceed to the Parameters key */
936 if (ConfigInfo
->ServiceKey
!= NULL
)
938 RtlInitUnicodeString(&KeyName
, L
"Parameters");
939 InitializeObjectAttributes(&ObjectAttributes
,
941 OBJ_CASE_INSENSITIVE
,
942 ConfigInfo
->ServiceKey
,
943 (PSECURITY_DESCRIPTOR
) NULL
);
946 Status
= ZwOpenKey(&ConfigInfo
->DeviceKey
,
950 if (NT_SUCCESS(Status
))
952 /* Yes, Parameters key exist, and it must be used instead of
954 ZwClose(ConfigInfo
->ServiceKey
);
955 ConfigInfo
->ServiceKey
= ConfigInfo
->DeviceKey
;
956 ConfigInfo
->DeviceKey
= NULL
;
960 if (ConfigInfo
->ServiceKey
!= NULL
)
962 /* Open the Device key */
963 RtlInitUnicodeString(&KeyName
, L
"Device");
964 InitializeObjectAttributes(&ObjectAttributes
,
966 OBJ_CASE_INSENSITIVE
,
967 ConfigInfo
->ServiceKey
,
970 /* We don't check for failure here - not needed */
971 ZwOpenKey(&ConfigInfo
->DeviceKey
,
978 /**********************************************************************
983 * Initializes SCSI port driver specific data.
990 * Pointer to the miniport driver's driver object.
993 * Pointer to the miniport driver's registry path.
995 * HwInitializationData
996 * Pointer to port driver specific configuration data.
999 Miniport driver specific context.
1008 ScsiPortInitialize(IN PVOID Argument1
,
1010 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
1013 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
1014 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
1015 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
1016 PCONFIGURATION_INFORMATION SystemConfig
;
1017 PPORT_CONFIGURATION_INFORMATION PortConfig
;
1018 PORT_CONFIGURATION_INFORMATION InitialPortConfig
;
1019 CONFIGURATION_INFO ConfigInfo
;
1020 ULONG DeviceExtensionSize
;
1021 ULONG PortConfigSize
;
1023 BOOLEAN DeviceFound
= FALSE
;
1024 BOOLEAN FirstConfigCall
= TRUE
;
1028 ULONG BusNumber
= 0;
1029 PCI_SLOT_NUMBER SlotNumber
;
1031 PDEVICE_OBJECT PortDeviceObject
;
1032 WCHAR NameBuffer
[80];
1033 UNICODE_STRING DeviceName
;
1034 WCHAR DosNameBuffer
[80];
1035 UNICODE_STRING DosDeviceName
;
1036 PIO_SCSI_CAPABILITIES PortCapabilities
;
1039 PCM_RESOURCE_LIST ResourceList
;
1041 SIZE_T BusConfigSize
;
1044 DPRINT ("ScsiPortInitialize() called!\n");
1046 /* Check params for validity */
1047 if ((HwInitializationData
->HwInitialize
== NULL
) ||
1048 (HwInitializationData
->HwStartIo
== NULL
) ||
1049 (HwInitializationData
->HwInterrupt
== NULL
) ||
1050 (HwInitializationData
->HwFindAdapter
== NULL
) ||
1051 (HwInitializationData
->HwResetBus
== NULL
))
1053 return STATUS_INVALID_PARAMETER
;
1057 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
1058 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
1059 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
1060 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
1061 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
1063 /* Obtain configuration information */
1064 SystemConfig
= IoGetConfigurationInformation();
1066 /* Zero the internal configuration info structure */
1067 RtlZeroMemory(&ConfigInfo
, sizeof(CONFIGURATION_INFO
));
1069 /* Zero starting slot number */
1070 SlotNumber
.u
.AsULONG
= 0;
1072 /* Allocate space for access ranges */
1073 if (HwInitializationData
->NumberOfAccessRanges
)
1075 ConfigInfo
.AccessRanges
=
1076 ExAllocatePoolWithTag(PagedPool
,
1077 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
), TAG_SCSIPORT
);
1079 /* Fail if failed */
1080 if (ConfigInfo
.AccessRanges
== NULL
)
1081 return STATUS_INSUFFICIENT_RESOURCES
;
1084 /* Open registry keys */
1085 SpiInitOpenKeys(&ConfigInfo
, (PUNICODE_STRING
)Argument2
);
1087 /* Last adapter number = not known */
1088 ConfigInfo
.LastAdapterNumber
= SP_UNINITIALIZED_VALUE
;
1090 /* Calculate sizes of DeviceExtension and PortConfig */
1091 DeviceExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
1092 HwInitializationData
->DeviceExtensionSize
;
1094 MaxBus
= (HwInitializationData
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
1095 DPRINT("MaxBus: %lu\n", MaxBus
);
1099 /* Create a unicode device name */
1100 swprintf(NameBuffer
,
1101 L
"\\Device\\ScsiPort%lu",
1102 SystemConfig
->ScsiPortCount
);
1103 RtlInitUnicodeString(&DeviceName
, NameBuffer
);
1105 DPRINT("Creating device: %wZ\n", &DeviceName
);
1107 /* Create the port device */
1108 Status
= IoCreateDevice(DriverObject
,
1109 DeviceExtensionSize
,
1111 FILE_DEVICE_CONTROLLER
,
1116 if (!NT_SUCCESS(Status
))
1118 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
1119 PortDeviceObject
= NULL
;
1123 DPRINT ("Created device: %wZ (%p)\n", &DeviceName
, PortDeviceObject
);
1125 /* Set the buffering strategy here... */
1126 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1127 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
; /* FIXME: Is this really needed? */
1129 /* Fill Device Extension */
1130 DeviceExtension
= PortDeviceObject
->DeviceExtension
;
1131 RtlZeroMemory(DeviceExtension
, DeviceExtensionSize
);
1132 DeviceExtension
->Length
= DeviceExtensionSize
;
1133 DeviceExtension
->DeviceObject
= PortDeviceObject
;
1134 DeviceExtension
->PortNumber
= SystemConfig
->ScsiPortCount
;
1136 /* Driver's routines... */
1137 DeviceExtension
->HwInitialize
= HwInitializationData
->HwInitialize
;
1138 DeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
1139 DeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
1140 DeviceExtension
->HwResetBus
= HwInitializationData
->HwResetBus
;
1141 DeviceExtension
->HwDmaStarted
= HwInitializationData
->HwDmaStarted
;
1143 /* Extensions sizes */
1144 DeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
1145 DeviceExtension
->LunExtensionSize
= HwInitializationData
->SpecificLuExtensionSize
;
1146 DeviceExtension
->SrbExtensionSize
= HwInitializationData
->SrbExtensionSize
;
1148 /* Round Srb extension size to the quadword */
1149 DeviceExtension
->SrbExtensionSize
=
1150 ~(sizeof(LONGLONG
) - 1) & (DeviceExtension
->SrbExtensionSize
+
1151 sizeof(LONGLONG
) - 1);
1153 /* Fill some numbers (bus count, lun count, etc) */
1154 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
1155 DeviceExtension
->RequestsNumber
= 16;
1157 /* Initialize the spin lock in the controller extension */
1158 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1159 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
1161 /* Initialize the DPC object */
1162 IoInitializeDpcRequest(PortDeviceObject
,
1165 /* Initialize the device timer */
1166 DeviceExtension
->TimerCount
= -1;
1167 IoInitializeTimer(PortDeviceObject
,
1171 /* Initialize miniport timer */
1172 KeInitializeTimer(&DeviceExtension
->MiniportTimer
);
1173 KeInitializeDpc(&DeviceExtension
->MiniportTimerDpc
,
1174 SpiMiniportTimerDpc
,
1179 Status
= SpiCreatePortConfig(DeviceExtension
,
1180 HwInitializationData
,
1185 if (!NT_SUCCESS(Status
))
1187 DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status
);
1191 /* Allocate and initialize port configuration info */
1192 PortConfigSize
= (sizeof(PORT_CONFIGURATION_INFORMATION
) +
1193 HwInitializationData
->NumberOfAccessRanges
*
1194 sizeof(ACCESS_RANGE
) + 7) & ~7;
1195 DeviceExtension
->PortConfig
= ExAllocatePoolWithTag(NonPagedPool
, PortConfigSize
, TAG_SCSIPORT
);
1197 /* Fail if failed */
1198 if (DeviceExtension
->PortConfig
== NULL
)
1200 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1204 PortConfig
= DeviceExtension
->PortConfig
;
1206 /* Copy information here */
1207 RtlCopyMemory(PortConfig
,
1209 sizeof(PORT_CONFIGURATION_INFORMATION
));
1212 /* Copy extension sizes into the PortConfig */
1213 PortConfig
->SpecificLuExtensionSize
= DeviceExtension
->LunExtensionSize
;
1214 PortConfig
->SrbExtensionSize
= DeviceExtension
->SrbExtensionSize
;
1216 /* Initialize Access ranges */
1217 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1219 PortConfig
->AccessRanges
= (PVOID
)(PortConfig
+1);
1221 /* Align to LONGLONG */
1222 PortConfig
->AccessRanges
= (PVOID
)((ULONG_PTR
)(PortConfig
->AccessRanges
) + 7);
1223 PortConfig
->AccessRanges
= (PVOID
)((ULONG_PTR
)(PortConfig
->AccessRanges
) & ~7);
1226 RtlCopyMemory(PortConfig
->AccessRanges
,
1227 ConfigInfo
.AccessRanges
,
1228 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
1231 /* Search for matching PCI device */
1232 if ((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1233 (HwInitializationData
->VendorIdLength
> 0) &&
1234 (HwInitializationData
->VendorId
!= NULL
) &&
1235 (HwInitializationData
->DeviceIdLength
> 0) &&
1236 (HwInitializationData
->DeviceId
!= NULL
))
1238 PortConfig
->BusInterruptLevel
= 0;
1240 /* Get PCI device data */
1241 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1242 HwInitializationData
->VendorIdLength
,
1243 HwInitializationData
->VendorId
,
1244 HwInitializationData
->DeviceIdLength
,
1245 HwInitializationData
->DeviceId
);
1247 if (!SpiGetPciConfigData(DriverObject
,
1249 HwInitializationData
,
1252 ConfigInfo
.BusNumber
,
1255 /* Continue to the next bus, nothing here */
1256 ConfigInfo
.BusNumber
++;
1257 DeviceExtension
->PortConfig
= NULL
;
1258 ExFreePool(PortConfig
);
1260 goto CreatePortConfig
;
1263 if (!PortConfig
->BusInterruptLevel
)
1265 /* Bypass this slot, because no interrupt was assigned */
1266 DeviceExtension
->PortConfig
= NULL
;
1267 ExFreePool(PortConfig
);
1268 goto CreatePortConfig
;
1273 DPRINT("Non-pci bus\n");
1276 /* Note: HwFindAdapter is called once for each bus */
1278 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
1279 Result
= (HwInitializationData
->HwFindAdapter
)(&DeviceExtension
->MiniPortDeviceExtension
,
1281 0, /* BusInformation */
1282 ConfigInfo
.Parameter
, /* ArgumentString */
1286 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1287 Result
, (Again
) ? "True" : "False");
1289 /* Free MapRegisterBase, it's not needed anymore */
1290 if (DeviceExtension
->MapRegisterBase
!= NULL
)
1292 ExFreePool(DeviceExtension
->MapRegisterBase
);
1293 DeviceExtension
->MapRegisterBase
= NULL
;
1296 /* If result is nothing good... */
1297 if (Result
!= SP_RETURN_FOUND
)
1299 DPRINT("HwFindAdapter() Result: %lu\n", Result
);
1301 if (Result
== SP_RETURN_NOT_FOUND
)
1303 /* We can continue on the next bus */
1304 ConfigInfo
.BusNumber
++;
1307 DeviceExtension
->PortConfig
= NULL
;
1308 ExFreePool(PortConfig
);
1309 goto CreatePortConfig
;
1312 /* Otherwise, break */
1313 Status
= STATUS_INTERNAL_ERROR
;
1317 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1318 PortConfig
->BusInterruptVector
, PortConfig
->InitiatorBusId
[0]);
1320 /* If the SRB extension size was updated */
1321 if (!DeviceExtension
->NonCachedExtension
&&
1322 (PortConfig
->SrbExtensionSize
!= DeviceExtension
->SrbExtensionSize
))
1324 /* Set it (rounding to LONGLONG again) */
1325 DeviceExtension
->SrbExtensionSize
=
1326 (PortConfig
->SrbExtensionSize
+
1327 sizeof(LONGLONG
)) & ~(sizeof(LONGLONG
) - 1);
1330 /* The same with LUN extension size */
1331 if (PortConfig
->SpecificLuExtensionSize
!= DeviceExtension
->LunExtensionSize
)
1332 DeviceExtension
->LunExtensionSize
= PortConfig
->SpecificLuExtensionSize
;
1335 if (!((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1336 (HwInitializationData
->VendorIdLength
> 0) &&
1337 (HwInitializationData
->VendorId
!= NULL
) &&
1338 (HwInitializationData
->DeviceIdLength
> 0) &&
1339 (HwInitializationData
->DeviceId
!= NULL
)))
1341 /* Construct a resource list */
1342 ResourceList
= SpiConfigToResource(DeviceExtension
,
1347 UNICODE_STRING UnicodeString
;
1348 RtlInitUnicodeString(&UnicodeString
, L
"ScsiAdapter");
1349 DPRINT("Reporting resources\n");
1350 Status
= IoReportResourceUsage(&UnicodeString
,
1356 FIELD_OFFSET(CM_RESOURCE_LIST
,
1357 List
[0].PartialResourceList
.PartialDescriptors
) +
1358 ResourceList
->List
[0].PartialResourceList
.Count
1359 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
1362 ExFreePool(ResourceList
);
1364 /* In case of a failure or a conflict, break */
1365 if (Conflict
|| (!NT_SUCCESS(Status
)))
1368 Status
= STATUS_CONFLICTING_ADDRESSES
;
1374 /* Reset the Conflict var */
1377 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1378 if (PortConfig
->MaximumNumberOfTargets
> SCSI_MAXIMUM_TARGETS_PER_BUS
)
1379 DeviceExtension
->MaxTargedIds
= SCSI_MAXIMUM_TARGETS_PER_BUS
;
1381 DeviceExtension
->MaxTargedIds
= PortConfig
->MaximumNumberOfTargets
;
1383 DeviceExtension
->BusNum
= PortConfig
->NumberOfBuses
;
1384 DeviceExtension
->CachesData
= PortConfig
->CachesData
;
1385 DeviceExtension
->ReceiveEvent
= PortConfig
->ReceiveEvent
;
1386 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->TaggedQueuing
;
1387 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
;
1389 /* If something was disabled via registry - apply it */
1390 if (ConfigInfo
.DisableMultipleLun
)
1391 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1393 if (ConfigInfo
.DisableTaggedQueueing
)
1394 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1396 /* Check if we need to alloc SRB data */
1397 if (DeviceExtension
->SupportsTaggedQueuing
||
1398 DeviceExtension
->MultipleReqsPerLun
)
1400 DeviceExtension
->NeedSrbDataAlloc
= TRUE
;
1404 DeviceExtension
->NeedSrbDataAlloc
= FALSE
;
1407 /* Get a pointer to the port capabilities */
1408 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1410 /* Copy one field there */
1411 DeviceExtension
->MapBuffers
= PortConfig
->MapBuffers
;
1412 PortCapabilities
->AdapterUsesPio
= PortConfig
->MapBuffers
;
1414 if (DeviceExtension
->AdapterObject
== NULL
&&
1415 (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
|| PortConfig
->Master
))
1417 DPRINT1("DMA is not supported yet\n");
1421 if (DeviceExtension
->SrbExtensionBuffer
== NULL
&&
1422 (DeviceExtension
->SrbExtensionSize
!= 0 ||
1423 PortConfig
->AutoRequestSense
))
1425 DeviceExtension
->SupportsAutoSense
= PortConfig
->AutoRequestSense
;
1426 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
1428 /* Allocate common buffer */
1429 Status
= SpiAllocateCommonBuffer(DeviceExtension
, 0);
1431 /* Check for failure */
1432 if (!NT_SUCCESS(Status
))
1436 /* Allocate SrbData, if needed */
1437 if (DeviceExtension
->NeedSrbDataAlloc
)
1440 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1442 if (DeviceExtension
->SrbDataCount
!= 0)
1443 Count
= DeviceExtension
->SrbDataCount
;
1445 Count
= DeviceExtension
->RequestsNumber
* 2;
1447 /* Allocate the data */
1448 SrbData
= ExAllocatePoolWithTag(NonPagedPool
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
), TAG_SCSIPORT
);
1449 if (SrbData
== NULL
)
1450 return STATUS_INSUFFICIENT_RESOURCES
;
1452 RtlZeroMemory(SrbData
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
));
1454 DeviceExtension
->SrbInfo
= SrbData
;
1455 DeviceExtension
->FreeSrbInfo
= SrbData
;
1456 DeviceExtension
->SrbDataCount
= Count
;
1458 /* Link it to the list */
1461 SrbData
->Requests
.Flink
= (PLIST_ENTRY
)(SrbData
+ 1);
1466 /* Mark the last entry of the list */
1468 SrbData
->Requests
.Flink
= NULL
;
1471 /* Initialize port capabilities */
1472 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1473 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1474 PortCapabilities
->MaximumTransferLength
= PortConfig
->MaximumTransferLength
;
1476 if (PortConfig
->ReceiveEvent
)
1477 PortCapabilities
->SupportedAsynchronousEvents
|= SRBEV_SCSI_ASYNC_NOTIFICATION
;
1479 PortCapabilities
->TaggedQueuing
= DeviceExtension
->SupportsTaggedQueuing
;
1480 PortCapabilities
->AdapterScansDown
= PortConfig
->AdapterScansDown
;
1482 if (PortConfig
->AlignmentMask
> PortDeviceObject
->AlignmentRequirement
)
1483 PortDeviceObject
->AlignmentRequirement
= PortConfig
->AlignmentMask
;
1485 PortCapabilities
->AlignmentMask
= PortDeviceObject
->AlignmentRequirement
;
1487 if (PortCapabilities
->MaximumPhysicalPages
== 0)
1489 PortCapabilities
->MaximumPhysicalPages
=
1490 BYTES_TO_PAGES(PortCapabilities
->MaximumTransferLength
);
1492 /* Apply miniport's limits */
1493 if (PortConfig
->NumberOfPhysicalBreaks
< PortCapabilities
->MaximumPhysicalPages
)
1495 PortCapabilities
->MaximumPhysicalPages
= PortConfig
->NumberOfPhysicalBreaks
;
1499 /* Deal with interrupts */
1500 if (DeviceExtension
->HwInterrupt
== NULL
||
1501 (PortConfig
->BusInterruptLevel
== 0 && PortConfig
->BusInterruptVector
== 0))
1504 DeviceExtension
->InterruptCount
= 0;
1506 DPRINT1("Interrupt Count: 0\n");
1510 /* This code path will ALWAYS crash so stop it now */
1515 BOOLEAN InterruptShareable
;
1516 KINTERRUPT_MODE InterruptMode
[2];
1517 ULONG InterruptVector
[2], i
, MappedIrq
[2];
1518 KIRQL Dirql
[2], MaxDirql
;
1519 KAFFINITY Affinity
[2];
1521 DeviceExtension
->InterruptLevel
[0] = PortConfig
->BusInterruptLevel
;
1522 DeviceExtension
->InterruptLevel
[1] = PortConfig
->BusInterruptLevel2
;
1524 InterruptVector
[0] = PortConfig
->BusInterruptVector
;
1525 InterruptVector
[1] = PortConfig
->BusInterruptVector2
;
1527 InterruptMode
[0] = PortConfig
->InterruptMode
;
1528 InterruptMode
[1] = PortConfig
->InterruptMode2
;
1530 DeviceExtension
->InterruptCount
= (PortConfig
->BusInterruptLevel2
!= 0 || PortConfig
->BusInterruptVector2
!= 0) ? 2 : 1;
1532 for (i
= 0; i
< DeviceExtension
->InterruptCount
; i
++)
1534 /* Register an interrupt handler for this device */
1535 MappedIrq
[i
] = HalGetInterruptVector(PortConfig
->AdapterInterfaceType
,
1536 PortConfig
->SystemIoBusNumber
,
1537 DeviceExtension
->InterruptLevel
[i
],
1543 if (DeviceExtension
->InterruptCount
== 1 || Dirql
[0] > Dirql
[1])
1544 MaxDirql
= Dirql
[0];
1546 MaxDirql
= Dirql
[1];
1548 for (i
= 0; i
< DeviceExtension
->InterruptCount
; i
++)
1550 /* Determing IRQ sharability as usual */
1551 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1552 InterruptMode
[i
] == LevelSensitive
)
1554 InterruptShareable
= TRUE
;
1558 InterruptShareable
= FALSE
;
1561 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
[i
],
1562 (PKSERVICE_ROUTINE
)ScsiPortIsr
,
1564 &DeviceExtension
->IrqLock
,
1573 if (!(NT_SUCCESS(Status
)))
1575 DPRINT1("Could not connect interrupt %d\n",
1576 InterruptVector
[i
]);
1577 DeviceExtension
->Interrupt
[i
] = NULL
;
1582 if (!NT_SUCCESS(Status
))
1586 /* Save IoAddress (from access ranges) */
1587 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1589 DeviceExtension
->IoAddress
=
1590 ((*(PortConfig
->AccessRanges
))[0]).RangeStart
.LowPart
;
1592 DPRINT("Io Address %x\n", DeviceExtension
->IoAddress
);
1595 /* Set flag that it's allowed to disconnect during this command */
1596 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
1598 /* Initialize counter of active requests (-1 means there are none) */
1599 DeviceExtension
->ActiveRequestCounter
= -1;
1601 /* Analyze what we have about DMA */
1602 if (DeviceExtension
->AdapterObject
!= NULL
&&
1603 PortConfig
->Master
&&
1604 PortConfig
->NeedPhysicalAddresses
)
1606 DeviceExtension
->MapRegisters
= TRUE
;
1610 DeviceExtension
->MapRegisters
= FALSE
;
1613 /* Call HwInitialize at DISPATCH_LEVEL */
1614 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1616 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
1617 DeviceExtension
->HwInitialize
,
1618 DeviceExtension
->MiniPortDeviceExtension
))
1620 DPRINT1("HwInitialize() failed!\n");
1621 KeLowerIrql(OldIrql
);
1622 Status
= STATUS_ADAPTER_HARDWARE_ERROR
;
1626 /* Check if a notification is needed */
1627 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
1629 /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1630 ScsiPortDpcForIsr(NULL
,
1631 DeviceExtension
->DeviceObject
,
1636 /* Lower irql back to what it was */
1637 KeLowerIrql(OldIrql
);
1639 /* Start our timer */
1640 IoStartTimer(PortDeviceObject
);
1642 /* Initialize bus scanning information */
1643 BusConfigSize
= FIELD_OFFSET(BUSES_CONFIGURATION_INFORMATION
,
1644 BusScanInfo
[DeviceExtension
->PortConfig
->NumberOfBuses
]);
1645 DeviceExtension
->BusesConfig
= ExAllocatePoolWithTag(PagedPool
,
1648 if (!DeviceExtension
->BusesConfig
)
1650 DPRINT1("Out of resources!\n");
1651 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1656 RtlZeroMemory(DeviceExtension
->BusesConfig
, BusConfigSize
);
1658 /* Store number of buses there */
1659 DeviceExtension
->BusesConfig
->NumberOfBuses
= (UCHAR
)DeviceExtension
->BusNum
;
1661 /* Scan the adapter for devices */
1662 SpiScanAdapter(DeviceExtension
);
1664 /* Build the registry device map */
1665 SpiBuildDeviceMap(DeviceExtension
,
1666 (PUNICODE_STRING
)Argument2
);
1668 /* Create the dos device link */
1669 swprintf(DosNameBuffer
,
1671 SystemConfig
->ScsiPortCount
);
1672 RtlInitUnicodeString(&DosDeviceName
, DosNameBuffer
);
1673 IoCreateSymbolicLink(&DosDeviceName
, &DeviceName
);
1675 /* Increase the port count */
1676 SystemConfig
->ScsiPortCount
++;
1677 FirstConfigCall
= FALSE
;
1679 /* Increase adapter number and bus number respectively */
1680 ConfigInfo
.AdapterNumber
++;
1683 ConfigInfo
.BusNumber
++;
1685 DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber
, MaxBus
);
1690 /* Clean up the mess */
1691 SpiCleanupAfterInit(DeviceExtension
);
1693 /* Close registry keys */
1694 if (ConfigInfo
.ServiceKey
!= NULL
)
1695 ZwClose(ConfigInfo
.ServiceKey
);
1697 if (ConfigInfo
.DeviceKey
!= NULL
)
1698 ZwClose(ConfigInfo
.DeviceKey
);
1700 if (ConfigInfo
.BusKey
!= NULL
)
1701 ZwClose(ConfigInfo
.BusKey
);
1703 if (ConfigInfo
.AccessRanges
!= NULL
)
1704 ExFreePool(ConfigInfo
.AccessRanges
);
1706 if (ConfigInfo
.Parameter
!= NULL
)
1707 ExFreePool(ConfigInfo
.Parameter
);
1709 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1710 Status
, DeviceFound
);
1712 return (DeviceFound
== FALSE
) ? Status
: STATUS_SUCCESS
;
1716 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1718 PSCSI_LUN_INFO LunInfo
;
1722 /* Check if we have something to clean up */
1723 if (DeviceExtension
== NULL
)
1726 /* Stop the timer */
1727 IoStopTimer(DeviceExtension
->DeviceObject
);
1729 /* Disconnect the interrupts */
1730 while (DeviceExtension
->InterruptCount
)
1732 if (DeviceExtension
->Interrupt
[--DeviceExtension
->InterruptCount
])
1733 IoDisconnectInterrupt(DeviceExtension
->Interrupt
[DeviceExtension
->InterruptCount
]);
1736 /* Delete ConfigInfo */
1737 if (DeviceExtension
->BusesConfig
)
1739 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
1741 if (!DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
])
1744 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
1748 /* Free current, but save pointer to the next one */
1749 Ptr
= LunInfo
->Next
;
1750 ExFreePool(LunInfo
);
1754 ExFreePool(DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]);
1757 ExFreePool(DeviceExtension
->BusesConfig
);
1760 /* Free PortConfig */
1761 if (DeviceExtension
->PortConfig
)
1762 ExFreePool(DeviceExtension
->PortConfig
);
1765 for(Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
1767 while (DeviceExtension
->LunExtensionList
[Lun
])
1769 Ptr
= DeviceExtension
->LunExtensionList
[Lun
];
1770 DeviceExtension
->LunExtensionList
[Lun
] = DeviceExtension
->LunExtensionList
[Lun
]->Next
;
1776 /* Free common buffer (if it exists) */
1777 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
&&
1778 DeviceExtension
->CommonBufferLength
!= 0)
1780 if (!DeviceExtension
->AdapterObject
)
1782 ExFreePool(DeviceExtension
->SrbExtensionBuffer
);
1786 HalFreeCommonBuffer(DeviceExtension
->AdapterObject
,
1787 DeviceExtension
->CommonBufferLength
,
1788 DeviceExtension
->PhysicalAddress
,
1789 DeviceExtension
->SrbExtensionBuffer
,
1795 if (DeviceExtension
->SrbInfo
!= NULL
)
1796 ExFreePool(DeviceExtension
->SrbInfo
);
1798 /* Unmap mapped addresses */
1799 while (DeviceExtension
->MappedAddressList
!= NULL
)
1801 MmUnmapIoSpace(DeviceExtension
->MappedAddressList
->MappedAddress
,
1802 DeviceExtension
->MappedAddressList
->NumberOfBytes
);
1804 Ptr
= DeviceExtension
->MappedAddressList
;
1805 DeviceExtension
->MappedAddressList
= DeviceExtension
->MappedAddressList
->NextMappedAddress
;
1810 /* Finally delete the device object */
1811 DPRINT("Deleting device %p\n", DeviceExtension
->DeviceObject
);
1812 IoDeleteDevice(DeviceExtension
->DeviceObject
);
1819 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
1820 IN PSCSI_REQUEST_BLOCK Srb
,
1821 IN PVOID LogicalAddress
,
1824 DPRINT1("ScsiPortIoMapTransfer()\n");
1832 ScsiPortLogError(IN PVOID HwDeviceExtension
,
1833 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
1840 //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1842 DPRINT1("ScsiPortLogError() called\n");
1843 DPRINT1("PathId: 0x%02x TargetId: 0x%02x Lun: 0x%02x ErrorCode: 0x%08lx UniqueId: 0x%08lx\n",
1844 PathId
, TargetId
, Lun
, ErrorCode
, UniqueId
);
1846 //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1849 DPRINT("ScsiPortLogError() done\n");
1856 ScsiPortMoveMemory(OUT PVOID Destination
,
1860 RtlMoveMemory(Destination
,
1870 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
1871 IN PVOID HwDeviceExtension
,
1874 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1877 DPRINT("ScsiPortNotification() called\n");
1879 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1880 SCSI_PORT_DEVICE_EXTENSION
,
1881 MiniPortDeviceExtension
);
1883 DPRINT("DeviceExtension %p\n", DeviceExtension
);
1885 va_start(ap
, HwDeviceExtension
);
1887 switch (NotificationType
)
1889 case RequestComplete
:
1891 PSCSI_REQUEST_BLOCK Srb
;
1892 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1894 Srb
= (PSCSI_REQUEST_BLOCK
) va_arg (ap
, PSCSI_REQUEST_BLOCK
);
1896 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb
);
1898 /* Make sure Srb is allright */
1899 ASSERT(Srb
->SrbStatus
!= SRB_STATUS_PENDING
);
1900 ASSERT(Srb
->Function
!= SRB_FUNCTION_EXECUTE_SCSI
|| Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
|| Srb
->ScsiStatus
== SCSISTAT_GOOD
);
1902 if (!(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
1904 /* It's been already completed */
1909 /* It's not active anymore */
1910 Srb
->SrbFlags
&= ~SRB_FLAGS_IS_ACTIVE
;
1912 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
1914 /* TODO: Treat it specially */
1919 /* Get the SRB data */
1920 SrbData
= SpiGetSrbData(DeviceExtension
,
1926 /* Make sure there are no CompletedRequests and there is a Srb */
1927 ASSERT(SrbData
->CompletedRequests
== NULL
&& SrbData
->Srb
!= NULL
);
1929 /* If it's a read/write request, make sure it has data inside it */
1930 if ((Srb
->SrbStatus
== SRB_STATUS_SUCCESS
) &&
1931 ((Srb
->Cdb
[0] == SCSIOP_READ
) || (Srb
->Cdb
[0] == SCSIOP_WRITE
)))
1933 ASSERT(Srb
->DataTransferLength
);
1936 SrbData
->CompletedRequests
= DeviceExtension
->InterruptData
.CompletedRequests
;
1937 DeviceExtension
->InterruptData
.CompletedRequests
= SrbData
;
1943 DPRINT("Notify: NextRequest\n");
1944 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1952 PSCSI_PORT_LUN_EXTENSION LunExtension
;
1954 PathId
= (UCHAR
) va_arg (ap
, int);
1955 TargetId
= (UCHAR
) va_arg (ap
, int);
1956 Lun
= (UCHAR
) va_arg (ap
, int);
1958 DPRINT("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1959 PathId
, TargetId
, Lun
);
1961 /* Mark it in the flags field */
1962 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1964 /* Get the LUN extension */
1965 LunExtension
= SpiGetLunExtension(DeviceExtension
,
1970 /* If returned LunExtension is NULL, break out */
1971 if (!LunExtension
) break;
1973 /* This request should not be processed if */
1974 if ((LunExtension
->ReadyLun
) ||
1975 (LunExtension
->SrbInfo
.Srb
))
1977 /* Nothing to do here */
1981 /* Add this LUN to the list */
1982 LunExtension
->ReadyLun
= DeviceExtension
->InterruptData
.ReadyLun
;
1983 DeviceExtension
->InterruptData
.ReadyLun
= LunExtension
;
1988 DPRINT("Notify: ResetDetected\n");
1989 /* Add RESET flags */
1990 DeviceExtension
->InterruptData
.Flags
|=
1991 SCSI_PORT_RESET
| SCSI_PORT_RESET_REPORTED
;
1994 case CallDisableInterrupts
:
1995 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
1998 case CallEnableInterrupts
:
1999 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
2002 case RequestTimerCall
:
2003 DPRINT("Notify: RequestTimerCall\n");
2004 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_TIMER_NEEDED
;
2005 DeviceExtension
->InterruptData
.HwScsiTimer
= (PHW_TIMER
)va_arg(ap
, PHW_TIMER
);
2006 DeviceExtension
->InterruptData
.MiniportTimerValue
= (ULONG
)va_arg(ap
, ULONG
);
2009 case BusChangeDetected
:
2010 DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
2014 DPRINT1 ("Unsupported notification from WMI: %lu\n", NotificationType
);
2020 /* Request a DPC after we're done with the interrupt */
2021 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NOTIFICATION_NEEDED
;
2028 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
2029 IN INTERFACE_TYPE BusType
,
2030 IN ULONG SystemIoBusNumber
,
2031 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
2032 IN ULONG NumberOfBytes
,
2033 IN BOOLEAN InIoSpace
)
2035 DPRINT("ScsiPortValidateRange()\n");
2040 /* INTERNAL FUNCTIONS ********************************************************/
2043 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
2044 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
2045 IN PPORT_CONFIGURATION_INFORMATION PortConfig
)
2047 PACCESS_RANGE AccessRange
;
2048 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData
;
2051 ULONG Interrupt
= 0;
2056 /* Loop through all entries */
2057 for (Index
= 0; Index
< ResourceDescriptor
->PartialResourceList
.Count
; Index
++)
2059 PartialData
= &ResourceDescriptor
->PartialResourceList
.PartialDescriptors
[Index
];
2061 switch (PartialData
->Type
)
2063 case CmResourceTypePort
:
2064 /* Copy access ranges */
2065 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
2067 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
2069 AccessRange
->RangeStart
= PartialData
->u
.Port
.Start
;
2070 AccessRange
->RangeLength
= PartialData
->u
.Port
.Length
;
2072 AccessRange
->RangeInMemory
= FALSE
;
2077 case CmResourceTypeMemory
:
2078 /* Copy access ranges */
2079 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
2081 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
2083 AccessRange
->RangeStart
= PartialData
->u
.Memory
.Start
;
2084 AccessRange
->RangeLength
= PartialData
->u
.Memory
.Length
;
2086 AccessRange
->RangeInMemory
= TRUE
;
2091 case CmResourceTypeInterrupt
:
2095 /* Copy interrupt data */
2096 PortConfig
->BusInterruptLevel
= PartialData
->u
.Interrupt
.Level
;
2097 PortConfig
->BusInterruptVector
= PartialData
->u
.Interrupt
.Vector
;
2099 /* Set interrupt mode accordingly to the resource */
2100 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
2102 PortConfig
->InterruptMode
= Latched
;
2104 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
2106 PortConfig
->InterruptMode
= LevelSensitive
;
2109 else if (Interrupt
== 1)
2111 /* Copy interrupt data */
2112 PortConfig
->BusInterruptLevel2
= PartialData
->u
.Interrupt
.Level
;
2113 PortConfig
->BusInterruptVector2
= PartialData
->u
.Interrupt
.Vector
;
2115 /* Set interrupt mode accordingly to the resource */
2116 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
2118 PortConfig
->InterruptMode2
= Latched
;
2120 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
2122 PortConfig
->InterruptMode2
= LevelSensitive
;
2129 case CmResourceTypeDma
:
2133 PortConfig
->DmaChannel
= PartialData
->u
.Dma
.Channel
;
2134 PortConfig
->DmaPort
= PartialData
->u
.Dma
.Port
;
2136 if (PartialData
->Flags
& CM_RESOURCE_DMA_8
)
2137 PortConfig
->DmaWidth
= Width8Bits
;
2138 else if ((PartialData
->Flags
& CM_RESOURCE_DMA_16
) ||
2139 (PartialData
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
2140 PortConfig
->DmaWidth
= Width16Bits
;
2141 else if (PartialData
->Flags
& CM_RESOURCE_DMA_32
)
2142 PortConfig
->DmaWidth
= Width32Bits
;
2146 PortConfig
->DmaChannel2
= PartialData
->u
.Dma
.Channel
;
2147 PortConfig
->DmaPort2
= PartialData
->u
.Dma
.Port
;
2149 if (PartialData
->Flags
& CM_RESOURCE_DMA_8
)
2150 PortConfig
->DmaWidth2
= Width8Bits
;
2151 else if ((PartialData
->Flags
& CM_RESOURCE_DMA_16
) ||
2152 (PartialData
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
2153 PortConfig
->DmaWidth2
= Width16Bits
;
2154 else if (PartialData
->Flags
& CM_RESOURCE_DMA_32
)
2155 PortConfig
->DmaWidth2
= Width32Bits
;
2162 static PCM_RESOURCE_LIST
2163 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2164 PPORT_CONFIGURATION_INFORMATION PortConfig
)
2166 PCONFIGURATION_INFORMATION ConfigInfo
;
2167 PCM_RESOURCE_LIST ResourceList
;
2168 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
2169 PACCESS_RANGE AccessRange
;
2170 ULONG ListLength
= 0, i
, FullSize
;
2171 ULONG Interrupt
, Dma
;
2173 /* Get current Atdisk usage from the system */
2174 ConfigInfo
= IoGetConfigurationInformation();
2176 if (PortConfig
->AtdiskPrimaryClaimed
)
2177 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
2179 if (PortConfig
->AtdiskSecondaryClaimed
)
2180 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
2182 /* Do we use DMA? */
2183 if (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
||
2184 PortConfig
->DmaPort
!= SP_UNINITIALIZED_VALUE
)
2188 if (PortConfig
->DmaChannel2
!= SP_UNINITIALIZED_VALUE
||
2189 PortConfig
->DmaPort2
!= SP_UNINITIALIZED_VALUE
)
2198 /* How many interrupts to we have? */
2199 Interrupt
= DeviceExtension
->InterruptCount
;
2200 ListLength
+= Interrupt
;
2202 /* How many access ranges do we use? */
2203 AccessRange
= &((*(PortConfig
->AccessRanges
))[0]);
2204 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2206 if (AccessRange
->RangeLength
!= 0)
2212 /* Allocate the resource list, since we know its size now */
2213 FullSize
= sizeof(CM_RESOURCE_LIST
) + (ListLength
- 1) *
2214 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
2216 ResourceList
= (PCM_RESOURCE_LIST
)ExAllocatePoolWithTag(PagedPool
, FullSize
, TAG_SCSIPORT
);
2222 RtlZeroMemory(ResourceList
, FullSize
);
2225 ResourceList
->Count
= 1;
2226 ResourceList
->List
[0].InterfaceType
= PortConfig
->AdapterInterfaceType
;
2227 ResourceList
->List
[0].BusNumber
= PortConfig
->SystemIoBusNumber
;
2228 ResourceList
->List
[0].PartialResourceList
.Count
= ListLength
;
2229 ResourceDescriptor
= ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
;
2231 /* Copy access ranges array over */
2232 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
2234 AccessRange
= &((*(PortConfig
->AccessRanges
))[i
]);
2236 /* If the range is empty - skip it */
2237 if (AccessRange
->RangeLength
== 0)
2240 if (AccessRange
->RangeInMemory
)
2242 ResourceDescriptor
->Type
= CmResourceTypeMemory
;
2243 ResourceDescriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
;
2247 ResourceDescriptor
->Type
= CmResourceTypePort
;
2248 ResourceDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
2251 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2253 ResourceDescriptor
->u
.Memory
.Start
= AccessRange
->RangeStart
;
2254 ResourceDescriptor
->u
.Memory
.Length
= AccessRange
->RangeLength
;
2256 ResourceDescriptor
++;
2259 /* If we use interrupt(s), copy them */
2262 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2264 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2265 ((Interrupt
== 2) ? PortConfig
->InterruptMode2
: PortConfig
->InterruptMode
) == LevelSensitive
)
2267 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2268 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2272 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2273 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2276 ResourceDescriptor
->u
.Interrupt
.Level
= (Interrupt
== 2) ? PortConfig
->BusInterruptLevel2
: PortConfig
->BusInterruptLevel
;
2277 ResourceDescriptor
->u
.Interrupt
.Vector
= (Interrupt
== 2) ? PortConfig
->BusInterruptVector2
: PortConfig
->BusInterruptVector
;
2278 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2280 ResourceDescriptor
++;
2287 ResourceDescriptor
->Type
= CmResourceTypeDma
;
2288 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2289 ResourceDescriptor
->u
.Dma
.Channel
= (Dma
== 2) ? PortConfig
->DmaChannel2
: PortConfig
->DmaChannel
;
2290 ResourceDescriptor
->u
.Dma
.Port
= (Dma
== 2) ? PortConfig
->DmaPort2
: PortConfig
->DmaPort
;
2291 ResourceDescriptor
->Flags
= 0;
2293 if (((Dma
== 2) ? PortConfig
->DmaWidth2
: PortConfig
->DmaWidth
) == Width8Bits
)
2294 ResourceDescriptor
->Flags
|= CM_RESOURCE_DMA_8
;
2295 else if (((Dma
== 2) ? PortConfig
->DmaWidth2
: PortConfig
->DmaWidth
) == Width16Bits
)
2296 ResourceDescriptor
->Flags
|= CM_RESOURCE_DMA_16
;
2298 ResourceDescriptor
->Flags
|= CM_RESOURCE_DMA_32
;
2300 if (((Dma
== 2) ? PortConfig
->DmaChannel2
: PortConfig
->DmaChannel
) == SP_UNINITIALIZED_VALUE
)
2301 ResourceDescriptor
->u
.Dma
.Channel
= 0;
2303 if (((Dma
== 2) ? PortConfig
->DmaPort2
: PortConfig
->DmaPort
) == SP_UNINITIALIZED_VALUE
)
2304 ResourceDescriptor
->u
.Dma
.Port
= 0;
2306 ResourceDescriptor
++;
2310 return ResourceList
;
2315 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
2316 IN PDEVICE_OBJECT DeviceObject
,
2317 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
2318 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
2319 IN PUNICODE_STRING RegistryPath
,
2321 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
)
2323 PCI_COMMON_CONFIG PciConfig
;
2324 PCI_SLOT_NUMBER SlotNumber
;
2327 ULONG FunctionNumber
;
2328 CHAR VendorIdString
[8];
2329 CHAR DeviceIdString
[8];
2330 UNICODE_STRING UnicodeStr
;
2331 PCM_RESOURCE_LIST ResourceList
= NULL
;
2334 DPRINT ("SpiGetPciConfiguration() called\n");
2336 SlotNumber
.u
.AsULONG
= 0;
2338 /* Loop through all devices */
2339 for (DeviceNumber
= NextSlotNumber
->u
.bits
.DeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
2341 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
2343 /* Loop through all functions */
2344 for (FunctionNumber
= NextSlotNumber
->u
.bits
.FunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
2346 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
2348 /* Get PCI config bytes */
2349 DataSize
= HalGetBusData(PCIConfiguration
,
2351 SlotNumber
.u
.AsULONG
,
2355 /* If result of HalGetBusData is 0, then the bus is wrong */
2359 /* Check if result is PCI_INVALID_VENDORID or too small */
2360 if ((DataSize
< sizeof(ULONG
)) ||
2361 (PciConfig
.VendorID
== PCI_INVALID_VENDORID
))
2363 /* Continue to try the next function */
2367 sprintf (VendorIdString
, "%04hx", PciConfig
.VendorID
);
2368 sprintf (DeviceIdString
, "%04hx", PciConfig
.DeviceID
);
2370 if (_strnicmp(VendorIdString
, HwInitializationData
->VendorId
, HwInitializationData
->VendorIdLength
) ||
2371 _strnicmp(DeviceIdString
, HwInitializationData
->DeviceId
, HwInitializationData
->DeviceIdLength
))
2373 /* It is not our device */
2377 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2381 SlotNumber
.u
.bits
.DeviceNumber
,
2382 SlotNumber
.u
.bits
.FunctionNumber
);
2385 RtlInitUnicodeString(&UnicodeStr
, L
"ScsiAdapter");
2386 Status
= HalAssignSlotResources(RegistryPath
,
2392 SlotNumber
.u
.AsULONG
,
2395 if (!NT_SUCCESS(Status
))
2398 /* Create configuration information */
2399 SpiResourceToConfig(HwInitializationData
,
2403 /* Free the resource list */
2404 ExFreePool(ResourceList
);
2406 /* Set dev & fn numbers */
2407 NextSlotNumber
->u
.bits
.DeviceNumber
= DeviceNumber
;
2408 NextSlotNumber
->u
.bits
.FunctionNumber
= FunctionNumber
+ 1;
2410 /* Save the slot number */
2411 PortConfig
->SlotNumber
= SlotNumber
.u
.AsULONG
;
2415 NextSlotNumber
->u
.bits
.FunctionNumber
= 0;
2418 NextSlotNumber
->u
.bits
.DeviceNumber
= 0;
2419 DPRINT ("No device found\n");
2426 /**********************************************************************
2428 * ScsiPortCreateClose
2431 * Answer requests for Create/Close calls: a null operation.
2438 * Pointer to a device object.
2441 * Pointer to an IRP.
2447 static NTSTATUS NTAPI
2448 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
2451 DPRINT("ScsiPortCreateClose()\n");
2453 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2454 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2456 return STATUS_SUCCESS
;
2460 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2463 PSCSI_LUN_INFO LunInfo
;
2464 PIO_STACK_LOCATION IrpStack
;
2465 PDEVICE_OBJECT DeviceObject
;
2466 PSCSI_REQUEST_BLOCK Srb
;
2469 /* Get pointer to the SRB */
2470 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2471 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
2473 /* Check if PathId matches number of buses */
2474 if (DeviceExtension
->BusesConfig
== NULL
||
2475 DeviceExtension
->BusesConfig
->NumberOfBuses
<= Srb
->PathId
)
2477 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2478 return STATUS_DEVICE_DOES_NOT_EXIST
;
2481 /* Get pointer to LunInfo */
2482 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Srb
->PathId
]->LunInfo
;
2484 /* Find matching LunInfo */
2487 if (LunInfo
->PathId
== Srb
->PathId
&&
2488 LunInfo
->TargetId
== Srb
->TargetId
&&
2489 LunInfo
->Lun
== Srb
->Lun
)
2494 LunInfo
= LunInfo
->Next
;
2497 /* If we couldn't find it - exit */
2498 if (LunInfo
== NULL
)
2499 return STATUS_DEVICE_DOES_NOT_EXIST
;
2503 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2505 /* Release, if asked */
2506 if (Srb
->Function
== SRB_FUNCTION_RELEASE_DEVICE
)
2508 LunInfo
->DeviceClaimed
= FALSE
;
2509 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2510 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2512 return STATUS_SUCCESS
;
2515 /* Attach, if not already claimed */
2516 if (LunInfo
->DeviceClaimed
)
2518 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2519 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
2521 return STATUS_DEVICE_BUSY
;
2524 /* Save the device object */
2525 DeviceObject
= LunInfo
->DeviceObject
;
2527 if (Srb
->Function
== SRB_FUNCTION_CLAIM_DEVICE
)
2528 LunInfo
->DeviceClaimed
= TRUE
;
2530 if (Srb
->Function
== SRB_FUNCTION_ATTACH_DEVICE
)
2531 LunInfo
->DeviceObject
= Srb
->DataBuffer
;
2533 Srb
->DataBuffer
= DeviceObject
;
2535 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2536 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2538 return STATUS_SUCCESS
;
2542 /**********************************************************************
2544 * ScsiPortDispatchScsi
2547 * Answer requests for SCSI calls
2553 * Standard dispatch arguments
2559 static NTSTATUS NTAPI
2560 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
2563 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2564 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2565 PIO_STACK_LOCATION Stack
;
2566 PSCSI_REQUEST_BLOCK Srb
;
2568 NTSTATUS Status
= STATUS_SUCCESS
;
2569 PIRP NextIrp
, IrpList
;
2570 PKDEVICE_QUEUE_ENTRY Entry
;
2572 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2575 DeviceExtension
= DeviceObject
->DeviceExtension
;
2576 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2578 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2581 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2582 Status
= STATUS_UNSUCCESSFUL
;
2584 Irp
->IoStatus
.Status
= Status
;
2585 Irp
->IoStatus
.Information
= 0;
2587 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2592 DPRINT("Srb: %p\n", Srb
);
2593 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
2594 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
2596 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2600 if (LunExtension
== NULL
)
2602 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2603 Status
= STATUS_NO_SUCH_DEVICE
;
2605 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2606 Irp
->IoStatus
.Status
= Status
;
2607 Irp
->IoStatus
.Information
= 0;
2609 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2614 switch (Srb
->Function
)
2616 case SRB_FUNCTION_SHUTDOWN
:
2617 case SRB_FUNCTION_FLUSH
:
2618 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2619 if (DeviceExtension
->CachesData
== FALSE
)
2621 /* All success here */
2622 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2623 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2624 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2625 return STATUS_SUCCESS
;
2627 /* Fall through to a usual execute operation */
2629 case SRB_FUNCTION_EXECUTE_SCSI
:
2630 case SRB_FUNCTION_IO_CONTROL
:
2631 DPRINT(" SRB_FUNCTION_EXECUTE_SCSI or SRB_FUNCTION_IO_CONTROL\n");
2632 /* Mark IRP as pending in all cases */
2633 IoMarkIrpPending(Irp
);
2635 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2637 /* Start IO directly */
2638 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2644 /* We need to be at DISPATCH_LEVEL */
2645 KeRaiseIrql (DISPATCH_LEVEL
, &oldIrql
);
2647 /* Insert IRP into the queue */
2648 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
2649 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
2652 /* It means the queue is empty, and we just start this request */
2653 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2656 /* Back to the old IRQL */
2657 KeLowerIrql (oldIrql
);
2659 return STATUS_PENDING
;
2661 case SRB_FUNCTION_CLAIM_DEVICE
:
2662 case SRB_FUNCTION_ATTACH_DEVICE
:
2663 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2665 /* Reference device object and keep the device object */
2666 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2669 case SRB_FUNCTION_RELEASE_DEVICE
:
2670 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2672 /* Dereference device object and clear the device object */
2673 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2676 case SRB_FUNCTION_RELEASE_QUEUE
:
2677 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2679 /* Guard with the spinlock */
2680 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2682 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2684 DPRINT("Queue is not frozen really\n");
2686 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2687 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2688 Status
= STATUS_SUCCESS
;
2693 /* Unfreeze the queue */
2694 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2696 if (LunExtension
->SrbInfo
.Srb
== NULL
)
2698 /* Get next logical unit request */
2699 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
2701 /* SpiGetNextRequestFromLun() releases the spinlock */
2706 DPRINT("The queue has active request\n");
2707 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2711 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2712 Status
= STATUS_SUCCESS
;
2715 case SRB_FUNCTION_FLUSH_QUEUE
:
2716 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2718 /* Guard with the spinlock */
2719 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2721 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2723 DPRINT("Queue is not frozen really\n");
2725 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2726 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2730 /* Make sure there is no active request */
2731 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
2733 /* Compile a list from the device queue */
2735 while ((Entry
= KeRemoveDeviceQueue(&LunExtension
->DeviceQueue
)) != NULL
)
2737 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
2740 Stack
= IoGetCurrentIrpStackLocation(NextIrp
);
2741 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2744 Srb
->SrbStatus
= SRB_STATUS_REQUEST_FLUSHED
;
2745 NextIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2747 /* Add then to the list */
2748 NextIrp
->Tail
.Overlay
.ListEntry
.Flink
= (PLIST_ENTRY
)IrpList
;
2752 /* Unfreeze the queue */
2753 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2755 /* Release the spinlock */
2756 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2758 /* Complete those requests */
2762 IrpList
= (PIRP
)NextIrp
->Tail
.Overlay
.ListEntry
.Flink
;
2764 IoCompleteRequest(NextIrp
, 0);
2767 Status
= STATUS_SUCCESS
;
2771 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
2772 Status
= STATUS_NOT_IMPLEMENTED
;
2776 Irp
->IoStatus
.Status
= Status
;
2778 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2784 /**********************************************************************
2786 * ScsiPortDeviceControl
2789 * Answer requests for device control calls
2795 * Standard dispatch arguments
2801 static NTSTATUS NTAPI
2802 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
2805 PIO_STACK_LOCATION Stack
;
2806 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2807 PDUMP_POINTERS DumpPointers
;
2810 DPRINT("ScsiPortDeviceControl()\n");
2812 Irp
->IoStatus
.Information
= 0;
2814 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2815 DeviceExtension
= DeviceObject
->DeviceExtension
;
2817 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
2819 case IOCTL_SCSI_GET_DUMP_POINTERS
:
2820 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2822 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DUMP_POINTERS
))
2824 Status
= STATUS_BUFFER_OVERFLOW
;
2825 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2829 DumpPointers
= Irp
->AssociatedIrp
.SystemBuffer
;
2830 DumpPointers
->DeviceObject
= DeviceObject
;
2833 Status
= STATUS_SUCCESS
;
2834 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2837 case IOCTL_SCSI_GET_CAPABILITIES
:
2838 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2839 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
== sizeof(PVOID
))
2841 *((PVOID
*)Irp
->AssociatedIrp
.SystemBuffer
) = &DeviceExtension
->PortCapabilities
;
2843 Irp
->IoStatus
.Information
= sizeof(PVOID
);
2844 Status
= STATUS_SUCCESS
;
2848 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(IO_SCSI_CAPABILITIES
))
2850 Status
= STATUS_BUFFER_TOO_SMALL
;
2854 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2855 &DeviceExtension
->PortCapabilities
,
2856 sizeof(IO_SCSI_CAPABILITIES
));
2858 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
2859 Status
= STATUS_SUCCESS
;
2862 case IOCTL_SCSI_GET_INQUIRY_DATA
:
2863 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2865 /* Copy inquiry data to the port device extension */
2866 Status
= SpiGetInquiryData(DeviceExtension
, Irp
);
2869 case IOCTL_SCSI_MINIPORT
:
2870 DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
2871 Status
= STATUS_NOT_IMPLEMENTED
;
2874 case IOCTL_SCSI_PASS_THROUGH
:
2875 DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
2876 Status
= STATUS_NOT_IMPLEMENTED
;
2880 if ('M' == (Stack
->Parameters
.DeviceIoControl
.IoControlCode
>> 16)) {
2881 DPRINT1(" got ioctl intended for the mount manager: 0x%lX\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2883 DPRINT1(" unknown ioctl code: 0x%lX\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2885 Status
= STATUS_NOT_IMPLEMENTED
;
2889 /* Complete the request with the given status */
2890 Irp
->IoStatus
.Status
= Status
;
2891 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2898 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
2901 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2902 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2903 PIO_STACK_LOCATION IrpStack
;
2904 PSCSI_REQUEST_BLOCK Srb
;
2905 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2909 DPRINT("ScsiPortStartIo() called!\n");
2911 DeviceExtension
= DeviceObject
->DeviceExtension
;
2912 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2914 DPRINT("DeviceExtension %p\n", DeviceExtension
);
2916 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2918 /* Apply "default" flags */
2919 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
2921 /* Get LUN extension */
2922 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2927 if (DeviceExtension
->NeedSrbDataAlloc
||
2928 DeviceExtension
->NeedSrbExtensionAlloc
)
2931 SrbInfo
= SpiAllocateSrbStructures(DeviceExtension
,
2935 /* Couldn't alloc one or both data structures, return */
2936 if (SrbInfo
== NULL
)
2938 /* We have to call IoStartNextPacket, because this request
2940 if (LunExtension
->Flags
& LUNEX_REQUEST_PENDING
)
2941 IoStartNextPacket(DeviceObject
, FALSE
);
2948 /* No allocations are needed */
2949 SrbInfo
= &LunExtension
->SrbInfo
;
2950 Srb
->SrbExtension
= NULL
;
2951 Srb
->QueueTag
= SP_UNTAGGED
;
2954 /* Increase sequence number of SRB */
2955 if (!SrbInfo
->SequenceNumber
)
2957 /* Increase global sequence number */
2958 DeviceExtension
->SequenceNumber
++;
2961 SrbInfo
->SequenceNumber
= DeviceExtension
->SequenceNumber
;
2964 /* Check some special SRBs */
2965 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2967 /* Some special handling */
2968 DPRINT1("Abort command! Unimplemented now\n");
2975 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
)
2977 // Store the MDL virtual address in SrbInfo structure
2978 SrbInfo
->DataOffset
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2980 if (DeviceExtension
->MapBuffers
)
2982 /* Calculate offset within DataBuffer */
2983 SrbInfo
->DataOffset
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
2984 Srb
->DataBuffer
= SrbInfo
->DataOffset
+
2985 (ULONG
)((PUCHAR
)Srb
->DataBuffer
-
2986 (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2989 if (DeviceExtension
->AdapterObject
)
2992 KeFlushIoBuffers(Irp
->MdlAddress
,
2993 Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? TRUE
: FALSE
,
2997 if (DeviceExtension
->MapRegisters
)
2999 /* Calculate number of needed map registers */
3000 SrbInfo
->NumberOfMapRegisters
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
3002 Srb
->DataTransferLength
);
3004 /* Allocate adapter channel */
3005 Status
= IoAllocateAdapterChannel(DeviceExtension
->AdapterObject
,
3006 DeviceExtension
->DeviceObject
,
3007 SrbInfo
->NumberOfMapRegisters
,
3011 if (!NT_SUCCESS(Status
))
3013 DPRINT1("IoAllocateAdapterChannel() failed!\n");
3015 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
3016 ScsiPortNotification(RequestComplete
,
3017 DeviceExtension
+ 1,
3020 ScsiPortNotification(NextRequest
,
3021 DeviceExtension
+ 1);
3023 /* Request DPC for that work */
3024 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3027 /* Control goes to SpiAdapterControl */
3032 /* Increase active request counter */
3033 CounterResult
= InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
3035 if (CounterResult
== 0 &&
3036 DeviceExtension
->AdapterObject
!= NULL
&&
3037 !DeviceExtension
->MapRegisters
)
3039 IoAllocateAdapterChannel(
3040 DeviceExtension
->AdapterObject
,
3042 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
,
3043 ScsiPortAllocateAdapterChannel
,
3050 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3052 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
3053 ScsiPortStartPacket
,
3056 DPRINT("Synchronization failed!\n");
3058 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3059 Irp
->IoStatus
.Information
= 0;
3060 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3062 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3066 /* Release the spinlock only */
3067 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3071 DPRINT("ScsiPortStartIo() done\n");
3075 static BOOLEAN NTAPI
3076 ScsiPortStartPacket(IN OUT PVOID Context
)
3078 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3079 PIO_STACK_LOCATION IrpStack
;
3080 PSCSI_REQUEST_BLOCK Srb
;
3081 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)Context
;
3082 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3083 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3087 DPRINT("ScsiPortStartPacket() called\n");
3089 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3091 IrpStack
= IoGetCurrentIrpStackLocation(DeviceObject
->CurrentIrp
);
3092 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
3094 /* Get LUN extension */
3095 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3100 /* Check if we are in a reset state */
3101 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
3103 /* Mark the we've got requests while being in the reset state */
3104 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET_REQUEST
;
3108 /* Set the time out value */
3109 DeviceExtension
->TimerCount
= Srb
->TimeOutValue
;
3112 DeviceExtension
->Flags
|= SCSI_PORT_DEVICE_BUSY
;
3114 if (LunExtension
->RequestTimeout
!= -1)
3116 /* Timer already active */
3121 /* It hasn't been initialized yet */
3122 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
3126 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
3128 /* Handle bypass-requests */
3130 /* Is this an abort request? */
3131 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
3133 /* Get pointer to SRB info structure */
3134 SrbInfo
= SpiGetSrbData(DeviceExtension
,
3140 /* Check if the request is still "active" */
3141 if (SrbInfo
== NULL
||
3142 SrbInfo
->Srb
== NULL
||
3143 !(SrbInfo
->Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
3145 /* It's not, mark it as active then */
3146 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
3149 LunExtension
->RequestTimeout
= -1;
3151 DPRINT("Request has been already completed, but abort request came\n");
3152 Srb
->SrbStatus
= SRB_STATUS_ABORT_FAILED
;
3154 /* Notify about request complete */
3155 ScsiPortNotification(RequestComplete
,
3156 DeviceExtension
->MiniPortDeviceExtension
,
3159 /* and about readiness for the next request */
3160 ScsiPortNotification(NextRequest
,
3161 DeviceExtension
->MiniPortDeviceExtension
);
3163 /* They might ask for some work, so queue the DPC for them */
3164 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3166 /* We're done in this branch */
3172 /* Add number of queued requests */
3173 LunExtension
->QueueCount
++;
3176 /* Bypass requests don't need request sense */
3177 LunExtension
->Flags
&= ~LUNEX_NEED_REQUEST_SENSE
;
3179 /* Is disconnect disabled for this request? */
3180 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3182 /* Set the corresponding flag */
3183 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3186 /* Transfer timeout value from Srb to Lun */
3187 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
3191 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3193 /* It's a disconnect, so no more requests can go */
3194 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
3197 LunExtension
->Flags
|= SCSI_PORT_LU_ACTIVE
;
3199 /* Increment queue count */
3200 LunExtension
->QueueCount
++;
3202 /* If it's tagged - special thing */
3203 if (Srb
->QueueTag
!= SP_UNTAGGED
)
3205 SrbInfo
= &DeviceExtension
->SrbInfo
[Srb
->QueueTag
- 1];
3207 /* Chek for consistency */
3208 ASSERT(SrbInfo
->Requests
.Blink
== NULL
);
3210 /* Insert it into the list of requests */
3211 InsertTailList(&LunExtension
->SrbInfo
.Requests
, &SrbInfo
->Requests
);
3215 /* Mark this Srb active */
3216 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
3218 /* Call HwStartIo routine */
3219 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
3222 /* If notification is needed, then request a DPC */
3223 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
3224 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
3229 IO_ALLOCATION_ACTION
3231 SpiAdapterControl(PDEVICE_OBJECT DeviceObject
,
3233 PVOID MapRegisterBase
,
3236 PSCSI_REQUEST_BLOCK Srb
;
3237 PSCSI_SG_ADDRESS ScatterGatherList
;
3239 PIO_STACK_LOCATION IrpStack
;
3240 ULONG TotalLength
= 0;
3241 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3242 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3244 BOOLEAN WriteToDevice
;
3246 /* Get pointers to SrbInfo and DeviceExtension */
3247 SrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)Context
;
3248 DeviceExtension
= DeviceObject
->DeviceExtension
;
3250 /* Get pointer to SRB */
3251 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3252 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
3254 /* Depending on the map registers number, we allocate
3255 either from NonPagedPool, or from our static list */
3256 if (SrbInfo
->NumberOfMapRegisters
> MAX_SG_LIST
)
3258 SrbInfo
->ScatterGather
= ExAllocatePoolWithTag(
3259 NonPagedPool
, SrbInfo
->NumberOfMapRegisters
* sizeof(SCSI_SG_ADDRESS
), TAG_SCSIPORT
);
3261 if (SrbInfo
->ScatterGather
== NULL
)
3264 Srb
->SrbFlags
|= SRB_FLAGS_SGLIST_FROM_POOL
;
3268 SrbInfo
->ScatterGather
= SrbInfo
->ScatterGatherList
;
3271 /* Use chosen SG list source */
3272 ScatterGatherList
= SrbInfo
->ScatterGather
;
3274 /* Save map registers base */
3275 SrbInfo
->BaseOfMapRegister
= MapRegisterBase
;
3277 /* Determine WriteToDevice flag */
3278 WriteToDevice
= Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
? TRUE
: FALSE
;
3280 /* Get virtual address of the data buffer */
3281 DataVA
= (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
3282 ((PCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
3284 /* Build the actual SG list */
3285 while (TotalLength
< Srb
->DataTransferLength
)
3287 if (!ScatterGatherList
)
3290 ScatterGatherList
->Length
= Srb
->DataTransferLength
- TotalLength
;
3291 ScatterGatherList
->PhysicalAddress
= IoMapTransfer(DeviceExtension
->AdapterObject
,
3294 DataVA
+ TotalLength
,
3295 &ScatterGatherList
->Length
,
3298 TotalLength
+= ScatterGatherList
->Length
;
3299 ScatterGatherList
++;
3302 /* Schedule an active request */
3303 InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
3304 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &CurrentIrql
);
3305 KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
3306 ScsiPortStartPacket
,
3308 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, CurrentIrql
);
3310 return DeallocateObjectKeepRegisters
;
3313 static PSCSI_PORT_LUN_EXTENSION
3314 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3316 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3317 ULONG LunExtensionSize
;
3319 DPRINT("SpiAllocateLunExtension (%p)\n",
3322 /* Round LunExtensionSize first to the sizeof LONGLONG */
3323 LunExtensionSize
= (DeviceExtension
->LunExtensionSize
+
3324 sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
3326 LunExtensionSize
+= sizeof(SCSI_PORT_LUN_EXTENSION
);
3327 DPRINT("LunExtensionSize %lu\n", LunExtensionSize
);
3329 LunExtension
= ExAllocatePoolWithTag(NonPagedPool
, LunExtensionSize
, TAG_SCSIPORT
);
3330 if (LunExtension
== NULL
)
3332 DPRINT1("Out of resources!\n");
3336 /* Zero everything */
3337 RtlZeroMemory(LunExtension
, LunExtensionSize
);
3339 /* Initialize a list of requests */
3340 InitializeListHead(&LunExtension
->SrbInfo
.Requests
);
3342 /* Initialize timeout counter */
3343 LunExtension
->RequestTimeout
= -1;
3345 /* Set maximum queue size */
3346 LunExtension
->MaxQueueCount
= 256;
3348 /* Initialize request queue */
3349 KeInitializeDeviceQueue (&LunExtension
->DeviceQueue
);
3351 return LunExtension
;
3354 static PSCSI_PORT_LUN_EXTENSION
3355 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3360 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3362 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3363 DeviceExtension
, PathId
, TargetId
, Lun
);
3365 /* Get appropriate list */
3366 LunExtension
= DeviceExtension
->LunExtensionList
[(TargetId
+ Lun
) % LUS_NUMBER
];
3368 /* Iterate it until we find what we need */
3369 while (LunExtension
)
3371 if (LunExtension
->TargetId
== TargetId
&&
3372 LunExtension
->Lun
== Lun
&&
3373 LunExtension
->PathId
== PathId
)
3375 /* All matches, return */
3376 return LunExtension
;
3379 /* Advance to the next item */
3380 LunExtension
= LunExtension
->Next
;
3383 /* We did not find anything */
3384 DPRINT("Nothing found\n");
3388 static PSCSI_REQUEST_BLOCK_INFO
3389 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3390 PSCSI_PORT_LUN_EXTENSION LunExtension
,
3391 PSCSI_REQUEST_BLOCK Srb
)
3394 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
3396 /* Spinlock must be held while this function executes */
3397 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3399 /* Allocate SRB data structure */
3400 if (DeviceExtension
->NeedSrbDataAlloc
)
3402 /* Treat the abort request in a special way */
3403 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
3405 SrbInfo
= SpiGetSrbData(DeviceExtension
,
3411 else if (Srb
->SrbFlags
&
3412 (SRB_FLAGS_QUEUE_ACTION_ENABLE
| SRB_FLAGS_NO_QUEUE_FREEZE
) &&
3413 !(Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3416 /* Do not process tagged commands if need request sense is set */
3417 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
3419 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3421 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3422 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3424 /* Relese the spinlock and return */
3425 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3429 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
3430 SrbInfo
= DeviceExtension
->FreeSrbInfo
;
3432 if (SrbInfo
== NULL
)
3434 /* No SRB structures left in the list. We have to leave
3435 and wait while we are called again */
3437 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3438 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3442 DeviceExtension
->FreeSrbInfo
= (PSCSI_REQUEST_BLOCK_INFO
)SrbInfo
->Requests
.Flink
;
3444 /* QueueTag must never be 0, so +1 to it */
3445 Srb
->QueueTag
= (UCHAR
)(SrbInfo
- DeviceExtension
->SrbInfo
) + 1;
3449 /* Usual untagged command */
3451 (!IsListEmpty(&LunExtension
->SrbInfo
.Requests
) ||
3452 LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
) &&
3453 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
3456 /* Mark it as pending and leave */
3457 ASSERT(!(LunExtension
->Flags
& LUNEX_REQUEST_PENDING
));
3458 LunExtension
->Flags
|= LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
;
3459 LunExtension
->PendingRequest
= Srb
->OriginalRequest
;
3461 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3465 Srb
->QueueTag
= SP_UNTAGGED
;
3466 SrbInfo
= &LunExtension
->SrbInfo
;
3471 Srb
->QueueTag
= SP_UNTAGGED
;
3472 SrbInfo
= &LunExtension
->SrbInfo
;
3475 /* Allocate SRB extension structure */
3476 if (DeviceExtension
->NeedSrbExtensionAlloc
)
3478 /* Check the list of free extensions */
3479 SrbExtension
= DeviceExtension
->FreeSrbExtensions
;
3481 /* If no free extensions... */
3482 if (SrbExtension
== NULL
)
3485 if (Srb
->Function
!= SRB_FUNCTION_ABORT_COMMAND
&&
3486 Srb
->QueueTag
!= SP_UNTAGGED
)
3488 SrbInfo
->Requests
.Blink
= NULL
;
3489 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
3490 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
3493 /* Return, in order to be called again later */
3494 DeviceExtension
->Flags
|= SCSI_PORT_REQUEST_PENDING
;
3495 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3499 /* Remove that free SRB extension from the list (since
3500 we're going to use it) */
3501 DeviceExtension
->FreeSrbExtensions
= *((PVOID
*)SrbExtension
);
3503 /* Spinlock can be released now */
3504 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3506 Srb
->SrbExtension
= SrbExtension
;
3508 if (Srb
->SenseInfoBuffer
!= NULL
&&
3509 DeviceExtension
->SupportsAutoSense
)
3511 /* Store pointer to the SenseInfo buffer */
3512 SrbInfo
->SaveSenseRequest
= Srb
->SenseInfoBuffer
;
3514 /* Does data fit the buffer? */
3515 if (Srb
->SenseInfoBufferLength
> sizeof(SENSE_DATA
))
3517 /* No, disabling autosense at all */
3518 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_AUTOSENSE
;
3522 /* Yes, update the buffer pointer */
3523 Srb
->SenseInfoBuffer
= SrbExtension
+ DeviceExtension
->SrbExtensionSize
;
3530 Srb
->SrbExtension
= NULL
;
3531 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3539 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
3540 IN PSCSI_LUN_INFO LunInfo
)
3542 IO_STATUS_BLOCK IoStatusBlock
;
3543 PIO_STACK_LOCATION IrpStack
;
3548 PINQUIRYDATA InquiryBuffer
;
3549 PSENSE_DATA SenseBuffer
;
3550 BOOLEAN KeepTrying
= TRUE
;
3551 ULONG RetryCount
= 0;
3552 SCSI_REQUEST_BLOCK Srb
;
3554 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3555 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3557 DPRINT ("SpiSendInquiry() called\n");
3559 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3561 InquiryBuffer
= ExAllocatePoolWithTag (NonPagedPool
, INQUIRYDATABUFFERSIZE
, TAG_SCSIPORT
);
3562 if (InquiryBuffer
== NULL
)
3563 return STATUS_INSUFFICIENT_RESOURCES
;
3565 SenseBuffer
= ExAllocatePoolWithTag (NonPagedPool
, SENSE_BUFFER_SIZE
, TAG_SCSIPORT
);
3566 if (SenseBuffer
== NULL
)
3568 ExFreePool(InquiryBuffer
);
3569 return STATUS_INSUFFICIENT_RESOURCES
;
3574 /* Initialize event for waiting */
3575 KeInitializeEvent(&Event
,
3580 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN
,
3585 INQUIRYDATABUFFERSIZE
,
3591 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3592 return STATUS_INSUFFICIENT_RESOURCES
;
3596 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3598 Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
3599 Srb
.OriginalRequest
= Irp
;
3600 Srb
.PathId
= LunInfo
->PathId
;
3601 Srb
.TargetId
= LunInfo
->TargetId
;
3602 Srb
.Lun
= LunInfo
->Lun
;
3603 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3604 Srb
.SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3605 Srb
.TimeOutValue
= 4;
3608 Srb
.SenseInfoBuffer
= SenseBuffer
;
3609 Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3611 Srb
.DataBuffer
= InquiryBuffer
;
3612 Srb
.DataTransferLength
= INQUIRYDATABUFFERSIZE
;
3614 /* Attach Srb to the Irp */
3615 IrpStack
= IoGetNextIrpStackLocation (Irp
);
3616 IrpStack
->Parameters
.Scsi
.Srb
= &Srb
;
3619 Cdb
= (PCDB
)Srb
.Cdb
;
3620 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_INQUIRY
;
3621 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= LunInfo
->Lun
;
3622 Cdb
->CDB6INQUIRY
.AllocationLength
= INQUIRYDATABUFFERSIZE
;
3624 /* Call the driver */
3625 Status
= IoCallDriver(DeviceObject
, Irp
);
3627 /* Wait for it to complete */
3628 if (Status
== STATUS_PENDING
)
3630 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3631 KeWaitForSingleObject(&Event
,
3636 Status
= IoStatusBlock
.Status
;
3639 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status
);
3641 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_SUCCESS
)
3643 /* All fine, copy data over */
3644 RtlCopyMemory(LunInfo
->InquiryData
,
3646 INQUIRYDATABUFFERSIZE
);
3648 Status
= STATUS_SUCCESS
;
3653 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb
.SrbStatus
);
3654 /* Check if the queue is frozen */
3655 if (Srb
.SrbStatus
& SRB_STATUS_QUEUE_FROZEN
)
3657 /* Something weird happened, deal with it (unfreeze the queue) */
3660 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb
.TargetId
);
3662 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3667 /* Clear frozen flag */
3668 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
3670 /* Acquire the spinlock */
3671 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
3673 /* Process the request */
3674 SpiGetNextRequestFromLun(DeviceObject
->DeviceExtension
, LunExtension
);
3676 /* SpiGetNextRequestFromLun() releases the spinlock,
3677 so we just lower irql back to what it was before */
3681 /* Check if data overrun happened */
3682 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
3684 DPRINT("Data overrun at TargetId %d\n", LunInfo
->TargetId
);
3685 /* Nothing dramatic, just copy data, but limiting the size */
3686 RtlCopyMemory(LunInfo
->InquiryData
,
3688 (Srb
.DataTransferLength
> INQUIRYDATABUFFERSIZE
) ?
3689 INQUIRYDATABUFFERSIZE
: Srb
.DataTransferLength
);
3691 Status
= STATUS_SUCCESS
;
3694 else if ((Srb
.SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3695 SenseBuffer
->SenseKey
== SCSI_SENSE_ILLEGAL_REQUEST
)
3697 /* LUN is not valid, but some device responds there.
3698 Mark it as invalid anyway */
3700 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3705 /* Retry a couple of times if no timeout happened */
3706 if ((RetryCount
< 2) &&
3707 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_NO_DEVICE
) &&
3708 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_SELECTION_TIMEOUT
))
3715 /* That's all, go to exit */
3718 /* Set status according to SRB status */
3719 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_FUNCTION
||
3720 SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH
)
3722 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3726 Status
= STATUS_IO_DEVICE_ERROR
;
3734 ExFreePool(InquiryBuffer
);
3735 ExFreePool(SenseBuffer
);
3737 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status
);
3743 /* Scans all SCSI buses */
3745 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3747 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3751 PSCSI_BUS_SCAN_INFO BusScanInfo
;
3752 PSCSI_LUN_INFO LastLunInfo
, LunInfo
, LunInfoExists
;
3753 BOOLEAN DeviceExists
;
3758 DPRINT("SpiScanAdapter() called\n");
3760 /* Scan all buses */
3761 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
3763 DPRINT(" Scanning bus %d\n", Bus
);
3766 /* Get pointer to the scan information */
3767 BusScanInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
];
3771 /* Find the last LUN info in the list */
3772 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3773 LastLunInfo
= LunInfo
;
3775 while (LunInfo
!= NULL
)
3777 LastLunInfo
= LunInfo
;
3778 LunInfo
= LunInfo
->Next
;
3783 /* We need to allocate this buffer */
3784 BusScanInfo
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_BUS_SCAN_INFO
), TAG_SCSIPORT
);
3788 DPRINT1("Out of resources!\n");
3792 /* Store the pointer in the BusScanInfo array */
3793 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
] = BusScanInfo
;
3795 /* Fill this struct (length and bus ids for now) */
3796 BusScanInfo
->Length
= sizeof(SCSI_BUS_SCAN_INFO
);
3797 BusScanInfo
->LogicalUnitsCount
= 0;
3798 BusScanInfo
->BusIdentifier
= DeviceExtension
->PortConfig
->InitiatorBusId
[Bus
];
3799 BusScanInfo
->LunInfo
= NULL
;
3801 /* Set pointer to the last LUN info to NULL */
3805 /* Create LUN information structure */
3806 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3808 if (LunInfo
== NULL
)
3810 DPRINT1("Out of resources!\n");
3814 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3816 /* Create LunExtension */
3817 LunExtension
= SpiAllocateLunExtension (DeviceExtension
);
3819 /* And send INQUIRY to every target */
3820 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
3822 /* TODO: Support scan bottom-up */
3824 /* Skip if it's the same address */
3825 if (Target
== BusScanInfo
->BusIdentifier
)
3828 /* Try to find an existing device here */
3829 DeviceExists
= FALSE
;
3830 LunInfoExists
= BusScanInfo
->LunInfo
;
3832 /* Find matching address on this bus */
3833 while (LunInfoExists
)
3835 if (LunInfoExists
->TargetId
== Target
)
3837 DeviceExists
= TRUE
;
3841 /* Advance to the next one */
3842 LunInfoExists
= LunInfoExists
->Next
;
3845 /* No need to bother rescanning, since we already did that before */
3849 /* Scan all logical units */
3850 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
3852 if ((!LunExtension
) || (!LunInfo
))
3855 /* Add extension to the list */
3856 Hint
= (Target
+ Lun
) % LUS_NUMBER
;
3857 LunExtension
->Next
= DeviceExtension
->LunExtensionList
[Hint
];
3858 DeviceExtension
->LunExtensionList
[Hint
] = LunExtension
;
3860 /* Fill Path, Target, Lun fields */
3861 LunExtension
->PathId
= LunInfo
->PathId
= (UCHAR
)Bus
;
3862 LunExtension
->TargetId
= LunInfo
->TargetId
= (UCHAR
) Target
;
3863 LunExtension
->Lun
= LunInfo
->Lun
= (UCHAR
)Lun
;
3865 /* Set flag to prevent race conditions */
3866 LunExtension
->Flags
|= SCSI_PORT_SCAN_IN_PROGRESS
;
3868 /* Zero LU extension contents */
3869 if (DeviceExtension
->LunExtensionSize
)
3871 RtlZeroMemory(LunExtension
+ 1,
3872 DeviceExtension
->LunExtensionSize
);
3875 /* Finally send the inquiry command */
3876 Status
= SpiSendInquiry(DeviceExtension
->DeviceObject
, LunInfo
);
3878 if (NT_SUCCESS(Status
))
3880 /* Let's see if we really found a device */
3881 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3883 /* Check if this device is unsupported */
3884 if (InquiryData
->DeviceTypeQualifier
== DEVICE_QUALIFIER_NOT_SUPPORTED
)
3886 DeviceExtension
->LunExtensionList
[Hint
] =
3887 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3892 /* Clear the "in scan" flag */
3893 LunExtension
->Flags
&= ~SCSI_PORT_SCAN_IN_PROGRESS
;
3895 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3896 InquiryData
->DeviceType
, Bus
, Target
, Lun
);
3898 /* Add this info to the linked list */
3899 LunInfo
->Next
= NULL
;
3901 LastLunInfo
->Next
= LunInfo
;
3903 BusScanInfo
->LunInfo
= LunInfo
;
3905 /* Store the last LUN info */
3906 LastLunInfo
= LunInfo
;
3908 /* Store DeviceObject */
3909 LunInfo
->DeviceObject
= DeviceExtension
->DeviceObject
;
3911 /* Allocate another buffer */
3912 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3916 DPRINT1("Out of resources!\n");
3920 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3922 /* Create a new LU extension */
3923 LunExtension
= SpiAllocateLunExtension(DeviceExtension
);
3929 /* Remove this LUN from the list */
3930 DeviceExtension
->LunExtensionList
[Hint
] =
3931 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3933 /* Decide whether we are continuing or not */
3934 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
3942 /* Free allocated buffers */
3944 ExFreePool(LunExtension
);
3947 ExFreePool(LunInfo
);
3949 /* Sum what we found */
3950 BusScanInfo
->LogicalUnitsCount
+= (UCHAR
) DevicesFound
;
3951 DPRINT(" Found %d devices on bus %d\n", DevicesFound
, Bus
);
3954 DPRINT ("SpiScanAdapter() done\n");
3959 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3962 ULONG InquiryDataSize
;
3963 PSCSI_LUN_INFO LunInfo
;
3964 ULONG BusCount
, LunCount
, Length
;
3965 PIO_STACK_LOCATION IrpStack
;
3966 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
3967 PSCSI_INQUIRY_DATA InquiryData
;
3968 PSCSI_BUS_DATA BusData
;
3972 DPRINT("SpiGetInquiryData() called\n");
3974 /* Get pointer to the buffer */
3975 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3976 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3978 /* Initialize bus and LUN counters */
3979 BusCount
= DeviceExtension
->BusesConfig
->NumberOfBuses
;
3982 /* Calculate total number of LUNs */
3983 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3984 LunCount
+= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3986 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
3988 ((sizeof(SCSI_INQUIRY_DATA
) - 1 + INQUIRYDATABUFFERSIZE
+
3989 sizeof(ULONG
) - 1) & ~(sizeof(ULONG
) - 1));
3991 /* Calculate data size */
3992 Length
= sizeof(SCSI_ADAPTER_BUS_INFO
) + (BusCount
- 1) *
3993 sizeof(SCSI_BUS_DATA
);
3995 Length
+= InquiryDataSize
* LunCount
;
3997 /* Check, if all data is going to fit into provided buffer */
3998 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< Length
)
4000 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4001 return STATUS_BUFFER_TOO_SMALL
;
4004 /* Store data size in the IRP */
4005 Irp
->IoStatus
.Information
= Length
;
4007 DPRINT("Data size: %lu\n", Length
);
4009 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
4011 AdapterBusInfo
->NumberOfBuses
= (UCHAR
)BusCount
;
4013 /* Point InquiryData to the corresponding place inside Buffer */
4014 InquiryData
= (PSCSI_INQUIRY_DATA
)(Buffer
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
4015 (BusCount
- 1) * sizeof(SCSI_BUS_DATA
));
4018 for (Bus
= 0; Bus
< BusCount
; Bus
++)
4020 BusData
= &AdapterBusInfo
->BusData
[Bus
];
4022 /* Calculate and save an offset of the inquiry data */
4023 BusData
->InquiryDataOffset
= (ULONG
)((PUCHAR
)InquiryData
- Buffer
);
4025 /* Get a pointer to the LUN information structure */
4026 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
4028 /* Store Initiator Bus Id */
4029 BusData
->InitiatorBusId
=
4030 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->BusIdentifier
;
4032 /* Store LUN count */
4033 BusData
->NumberOfLogicalUnits
=
4034 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
4037 while (LunInfo
!= NULL
)
4039 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
4040 Bus
, LunInfo
->TargetId
, LunInfo
->Lun
);
4042 /* Fill InquiryData with values */
4043 InquiryData
->PathId
= LunInfo
->PathId
;
4044 InquiryData
->TargetId
= LunInfo
->TargetId
;
4045 InquiryData
->Lun
= LunInfo
->Lun
;
4046 InquiryData
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
4047 InquiryData
->DeviceClaimed
= LunInfo
->DeviceClaimed
;
4048 InquiryData
->NextInquiryDataOffset
=
4049 (ULONG
)((PUCHAR
)InquiryData
+ InquiryDataSize
- Buffer
);
4051 /* Copy data in it */
4052 RtlCopyMemory(InquiryData
->InquiryData
,
4053 LunInfo
->InquiryData
,
4054 INQUIRYDATABUFFERSIZE
);
4056 /* Move to the next LUN */
4057 LunInfo
= LunInfo
->Next
;
4058 InquiryData
= (PSCSI_INQUIRY_DATA
) ((PCHAR
)InquiryData
+ InquiryDataSize
);
4061 /* Either mark the end, or set offset to 0 */
4062 if (BusData
->NumberOfLogicalUnits
!= 0)
4063 ((PSCSI_INQUIRY_DATA
) ((PCHAR
) InquiryData
- InquiryDataSize
))->NextInquiryDataOffset
= 0;
4065 BusData
->InquiryDataOffset
= 0;
4068 /* Finish with success */
4069 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4070 return STATUS_SUCCESS
;
4073 static PSCSI_REQUEST_BLOCK_INFO
4074 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4080 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4082 if (QueueTag
== SP_UNTAGGED
)
4084 /* Untagged request, get LU and return pointer to SrbInfo */
4085 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4090 /* Return NULL in case of error */
4094 /* Return the pointer to SrbInfo */
4095 return &LunExtension
->SrbInfo
;
4099 /* Make sure the tag is valid, if it is - return the data */
4100 if (QueueTag
> DeviceExtension
->SrbDataCount
|| QueueTag
< 1)
4103 return &DeviceExtension
->SrbInfo
[QueueTag
-1];
4108 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4109 IN PSCSI_REQUEST_BLOCK InitialSrb
)
4111 PSCSI_REQUEST_BLOCK Srb
;
4114 PIO_STACK_LOCATION IrpStack
;
4115 LARGE_INTEGER LargeInt
;
4118 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb
);
4121 Srb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
) + sizeof(PVOID
), TAG_SCSIPORT
);
4122 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
4125 LargeInt
.QuadPart
= (LONGLONG
) 1;
4126 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_READ
,
4127 DeviceExtension
->DeviceObject
,
4128 InitialSrb
->SenseInfoBuffer
,
4129 InitialSrb
->SenseInfoBufferLength
,
4133 IoSetCompletionRoutine(Irp
,
4134 (PIO_COMPLETION_ROUTINE
)SpiCompletionRoutine
,
4142 DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb
);
4146 IrpStack
= IoGetNextIrpStackLocation(Irp
);
4147 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
4149 /* Put Srb address into Irp... */
4150 IrpStack
->Parameters
.Others
.Argument1
= (PVOID
)Srb
;
4152 /* ...and vice versa */
4153 Srb
->OriginalRequest
= Irp
;
4156 Ptr
= (PVOID
*)(Srb
+1);
4159 /* Build CDB for REQUEST SENSE */
4161 Cdb
= (PCDB
)Srb
->Cdb
;
4163 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
4164 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= 0;
4165 Cdb
->CDB6INQUIRY
.Reserved1
= 0;
4166 Cdb
->CDB6INQUIRY
.PageCode
= 0;
4167 Cdb
->CDB6INQUIRY
.IReserved
= 0;
4168 Cdb
->CDB6INQUIRY
.AllocationLength
= (UCHAR
)InitialSrb
->SenseInfoBufferLength
;
4169 Cdb
->CDB6INQUIRY
.Control
= 0;
4172 Srb
->TargetId
= InitialSrb
->TargetId
;
4173 Srb
->Lun
= InitialSrb
->Lun
;
4174 Srb
->PathId
= InitialSrb
->PathId
;
4176 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4177 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
4179 /* Timeout will be 2 seconds */
4180 Srb
->TimeOutValue
= 2;
4182 /* No auto request sense */
4183 Srb
->SenseInfoBufferLength
= 0;
4184 Srb
->SenseInfoBuffer
= NULL
;
4186 /* Set necessary flags */
4187 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_BYPASS_FROZEN_QUEUE
|
4188 SRB_FLAGS_DISABLE_DISCONNECT
;
4190 /* Transfer disable synch transfer flag */
4191 if (InitialSrb
->SrbFlags
& SRB_FLAGS_DISABLE_SYNCH_TRANSFER
)
4192 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4194 Srb
->DataBuffer
= InitialSrb
->SenseInfoBuffer
;
4196 /* Fill the transfer length */
4197 Srb
->DataTransferLength
= InitialSrb
->SenseInfoBufferLength
;
4199 /* Clear statuses */
4200 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
4203 /* Call the driver */
4204 (VOID
)IoCallDriver(DeviceExtension
->DeviceObject
, Irp
);
4206 DPRINT("SpiSendRequestSense() done\n");
4213 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4214 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
4215 OUT PBOOLEAN NeedToCallStartIo
)
4217 PSCSI_REQUEST_BLOCK Srb
;
4218 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4221 //ULONG SequenceNumber;
4224 Irp
= Srb
->OriginalRequest
;
4226 /* Get Lun extension */
4227 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4232 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
&&
4233 DeviceExtension
->MapBuffers
&&
4236 /* MDL is shared if transfer is broken into smaller parts */
4237 Srb
->DataBuffer
= (PCCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
4238 ((PCCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
4240 /* In case of data going in, flush the buffers */
4241 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
4243 KeFlushIoBuffers(Irp
->MdlAddress
,
4249 /* Flush adapter if needed */
4250 if (SrbInfo
->BaseOfMapRegister
)
4252 /* TODO: Implement */
4256 /* Clear the request */
4257 SrbInfo
->Srb
= NULL
;
4259 /* If disconnect is disabled... */
4260 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
4262 /* Acquire the spinlock since we mess with flags */
4263 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4265 /* Set corresponding flag */
4266 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
4268 /* Clear the timer if needed */
4269 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
))
4270 DeviceExtension
->TimerCount
= -1;
4272 /* Spinlock is not needed anymore */
4273 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4275 if (!(DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
) &&
4276 !(DeviceExtension
->Flags
& SCSI_PORT_DEVICE_BUSY
) &&
4277 !(*NeedToCallStartIo
))
4279 /* We're not busy, but we have a request pending */
4280 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4284 /* Scatter/gather */
4285 if (Srb
->SrbFlags
& SRB_FLAGS_SGLIST_FROM_POOL
)
4287 /* TODO: Implement */
4291 /* Acquire spinlock (we're freeing SrbExtension) */
4292 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4294 /* Free it (if needed) */
4295 if (Srb
->SrbExtension
)
4297 if (Srb
->SenseInfoBuffer
!= NULL
&& DeviceExtension
->SupportsAutoSense
)
4299 ASSERT(Srb
->SenseInfoBuffer
== NULL
|| SrbInfo
->SaveSenseRequest
!= NULL
);
4301 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)
4303 /* Copy sense data to the buffer */
4304 RtlCopyMemory(SrbInfo
->SaveSenseRequest
,
4305 Srb
->SenseInfoBuffer
,
4306 Srb
->SenseInfoBufferLength
);
4309 /* And restore the pointer */
4310 Srb
->SenseInfoBuffer
= SrbInfo
->SaveSenseRequest
;
4313 /* Put it into the free srb extensions list */
4314 *((PVOID
*)Srb
->SrbExtension
) = DeviceExtension
->FreeSrbExtensions
;
4315 DeviceExtension
->FreeSrbExtensions
= Srb
->SrbExtension
;
4318 /* Save transfer length in the IRP */
4319 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
4321 //SequenceNumber = SrbInfo->SequenceNumber;
4322 SrbInfo
->SequenceNumber
= 0;
4324 /* Decrement the queue count */
4325 LunExtension
->QueueCount
--;
4327 /* Free Srb, if needed*/
4328 if (Srb
->QueueTag
!= SP_UNTAGGED
)
4330 /* Put it into the free list */
4331 SrbInfo
->Requests
.Blink
= NULL
;
4332 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
4333 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
4336 /* SrbInfo is not used anymore */
4339 if (DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
)
4341 /* Clear the flag */
4342 DeviceExtension
->Flags
&= ~SCSI_PORT_REQUEST_PENDING
;
4344 /* Note the caller about StartIo */
4345 *NeedToCallStartIo
= TRUE
;
4348 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
4350 /* Start the packet */
4351 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4353 if (!(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
) &&
4354 LunExtension
->RequestTimeout
== -1)
4356 /* Start the next packet */
4357 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4361 /* Release the spinlock */
4362 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4365 DPRINT("IoCompleting request IRP 0x%p\n", Irp
);
4367 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4369 /* Decrement number of active requests, and analyze the result */
4370 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4373 !DeviceExtension
->MapRegisters
&&
4374 DeviceExtension
->AdapterObject
!= NULL
)
4376 /* Nullify map registers */
4377 DeviceExtension
->MapRegisterBase
= NULL
;
4378 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4381 /* Exit, we're done */
4385 /* Decrement number of active requests, and analyze the result */
4386 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
4389 !DeviceExtension
->MapRegisters
&&
4390 DeviceExtension
->AdapterObject
!= NULL
)
4392 /* Result is negative, so this is a slave, free map registers */
4393 DeviceExtension
->MapRegisterBase
= NULL
;
4394 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
4397 /* Convert status */
4398 Irp
->IoStatus
.Status
= SpiStatusSrbToNt(Srb
->SrbStatus
);
4400 /* It's not a bypass, it's busy or the queue is full? */
4401 if ((Srb
->ScsiStatus
== SCSISTAT_BUSY
||
4402 Srb
->SrbStatus
== SRB_STATUS_BUSY
||
4403 Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
) &&
4404 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
))
4407 DPRINT("Busy SRB status %x\n", Srb
->SrbStatus
);
4409 /* Requeu, if needed */
4410 if (LunExtension
->Flags
& (LUNEX_FROZEN_QUEUE
| LUNEX_BUSY
))
4412 DPRINT("it's being requeued\n");
4414 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4415 Srb
->ScsiStatus
= 0;
4417 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4418 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
4421 /* It's a big f.ck up if we got here */
4422 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
4423 Srb
->ScsiStatus
= SCSISTAT_BUSY
;
4429 /* Release the spinlock */
4430 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4433 else if (LunExtension
->AttemptCount
++ < 20)
4435 /* LUN is still busy */
4436 Srb
->ScsiStatus
= 0;
4437 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
4439 LunExtension
->BusyRequest
= Irp
;
4440 LunExtension
->Flags
|= LUNEX_BUSY
;
4442 /* Release the spinlock */
4443 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4448 /* Freeze the queue*/
4449 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4450 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4452 /* "Unfull" the queue */
4453 LunExtension
->Flags
&= ~LUNEX_FULL_QUEUE
;
4455 /* Release the spinlock */
4456 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4458 /* Return status that the device is not ready */
4459 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
4460 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4466 /* Start the next request, if LUN is idle, and this is sense request */
4467 if (((Srb
->ScsiStatus
!= SCSISTAT_CHECK_CONDITION
) ||
4468 (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) ||
4469 !Srb
->SenseInfoBuffer
|| !Srb
->SenseInfoBufferLength
)
4470 && (Srb
->SrbFlags
& SRB_FLAGS_NO_QUEUE_FREEZE
))
4472 if (LunExtension
->RequestTimeout
== -1)
4473 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4475 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4479 /* Freeze the queue */
4480 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
4481 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
4483 /* Do we need a request sense? */
4484 if (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4485 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
4486 Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
)
4488 /* If LUN is busy, we have to requeue it in order to allow request sense */
4489 if (LunExtension
->Flags
& LUNEX_BUSY
)
4491 DPRINT("Requeueing busy request to allow request sense\n");
4493 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
4494 &LunExtension
->BusyRequest
->Tail
.Overlay
.DeviceQueueEntry
,
4497 /* We should never get here */
4500 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4501 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4506 /* Clear busy flags */
4507 LunExtension
->Flags
&= ~(LUNEX_FULL_QUEUE
| LUNEX_BUSY
);
4510 /* Release the spinlock */
4511 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4513 /* Send RequestSense */
4514 SpiSendRequestSense(DeviceExtension
, Srb
);
4520 /* Release the spinlock */
4521 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4524 /* Complete the request */
4525 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4530 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
4534 PSCSI_REQUEST_BLOCK Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
4535 PSCSI_REQUEST_BLOCK InitialSrb
;
4538 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp
);
4540 if ((Srb
->Function
== SRB_FUNCTION_RESET_BUS
) ||
4541 (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
))
4543 /* Deallocate SRB and IRP and exit */
4547 return STATUS_MORE_PROCESSING_REQUIRED
;
4550 /* Get a pointer to the SRB and IRP which were initially sent */
4551 InitialSrb
= *((PVOID
*)(Srb
+1));
4552 InitialIrp
= InitialSrb
->OriginalRequest
;
4554 if ((SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
) ||
4555 (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_DATA_OVERRUN
))
4557 /* Sense data is OK */
4558 InitialSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
4560 /* Set length to be the same */
4561 InitialSrb
->SenseInfoBufferLength
= (UCHAR
)Srb
->DataTransferLength
;
4564 /* Make sure initial SRB's queue is frozen */
4565 ASSERT(InitialSrb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
);
4567 /* Complete this request */
4568 IoCompleteRequest(InitialIrp
, IO_DISK_INCREMENT
);
4570 /* Deallocate everything (internal) */
4573 if (Irp
->MdlAddress
!= NULL
)
4575 MmUnlockPages(Irp
->MdlAddress
);
4576 IoFreeMdl(Irp
->MdlAddress
);
4577 Irp
->MdlAddress
= NULL
;
4581 return STATUS_MORE_PROCESSING_REQUIRED
;
4584 static BOOLEAN NTAPI
4585 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
4586 IN PVOID ServiceContext
)
4588 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4590 DPRINT("ScsiPortIsr() called!\n");
4592 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
4594 /* If interrupts are disabled - we don't expect any */
4595 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_DISABLE_INTERRUPTS
)
4598 /* Call miniport's HwInterrupt routine */
4599 if (DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
) == FALSE
)
4601 /* This interrupt doesn't belong to us */
4605 /* If flag of notification is set - queue a DPC */
4606 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4608 IoRequestDpc(DeviceExtension
->DeviceObject
,
4609 DeviceExtension
->CurrentIrp
,
4618 SpiSaveInterruptData(IN PVOID Context
)
4620 PSCSI_PORT_SAVE_INTERRUPT InterruptContext
= Context
;
4621 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4622 PSCSI_REQUEST_BLOCK Srb
;
4623 PSCSI_REQUEST_BLOCK_INFO SrbInfo
, NextSrbInfo
;
4624 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4627 /* Get pointer to the device extension */
4628 DeviceExtension
= InterruptContext
->DeviceExtension
;
4630 /* If we don't have anything pending - return */
4631 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
))
4634 /* Actually save the interrupt data */
4635 *InterruptContext
->InterruptData
= DeviceExtension
->InterruptData
;
4637 /* Clear the data stored in the device extension */
4638 DeviceExtension
->InterruptData
.Flags
&=
4639 (SCSI_PORT_RESET
| SCSI_PORT_RESET_REQUEST
| SCSI_PORT_DISABLE_INTERRUPTS
);
4640 DeviceExtension
->InterruptData
.CompletedAbort
= NULL
;
4641 DeviceExtension
->InterruptData
.ReadyLun
= NULL
;
4642 DeviceExtension
->InterruptData
.CompletedRequests
= NULL
;
4644 /* Loop through the list of completed requests */
4645 SrbInfo
= InterruptContext
->InterruptData
->CompletedRequests
;
4649 /* Make sure we have SRV */
4650 ASSERT(SrbInfo
->Srb
);
4652 /* Get SRB and LunExtension */
4655 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4660 /* We have to check special cases if request is unsuccessfull*/
4661 if (Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
)
4663 /* Check if we need request sense by a few conditions */
4664 if (Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
&&
4665 Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4666 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
))
4668 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
4670 /* It means: we tried to send REQUEST SENSE, but failed */
4672 Srb
->ScsiStatus
= 0;
4673 Srb
->SrbStatus
= SRB_STATUS_REQUEST_SENSE_FAILED
;
4677 /* Set the corresponding flag, so that REQUEST SENSE
4679 LunExtension
->Flags
|= LUNEX_NEED_REQUEST_SENSE
;
4684 /* Check for a full queue */
4685 if (Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
)
4687 /* TODO: Implement when it's encountered */
4692 /* Let's decide if we need to watch timeout or not */
4693 if (Srb
->QueueTag
== SP_UNTAGGED
)
4699 if (LunExtension
->SrbInfo
.Requests
.Flink
== &SrbInfo
->Requests
)
4704 /* Remove it from the queue */
4705 RemoveEntryList(&SrbInfo
->Requests
);
4710 /* We have to maintain timeout counter */
4711 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
))
4713 LunExtension
->RequestTimeout
= -1;
4717 NextSrbInfo
= CONTAINING_RECORD(LunExtension
->SrbInfo
.Requests
.Flink
,
4718 SCSI_REQUEST_BLOCK_INFO
,
4721 Srb
= NextSrbInfo
->Srb
;
4723 /* Update timeout counter */
4724 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
4728 SrbInfo
= SrbInfo
->CompletedRequests
;
4736 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4737 IN PSCSI_PORT_LUN_EXTENSION LunExtension
)
4739 PIO_STACK_LOCATION IrpStack
;
4741 PKDEVICE_QUEUE_ENTRY Entry
;
4742 PSCSI_REQUEST_BLOCK Srb
;
4745 /* If LUN is not active or queue is more than maximum allowed */
4746 if (LunExtension
->QueueCount
>= LunExtension
->MaxQueueCount
||
4747 !(LunExtension
->Flags
& SCSI_PORT_LU_ACTIVE
))
4749 /* Release the spinlock and exit */
4750 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4754 /* Check if we can get a next request */
4755 if (LunExtension
->Flags
&
4756 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_BUSY
|
4757 LUNEX_FULL_QUEUE
| LUNEX_FROZEN_QUEUE
| LUNEX_REQUEST_PENDING
))
4759 /* Pending requests can only be started if the queue is empty */
4760 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
) &&
4761 !(LunExtension
->Flags
&
4762 (LUNEX_BUSY
| LUNEX_FROZEN_QUEUE
| LUNEX_FULL_QUEUE
| LUNEX_NEED_REQUEST_SENSE
)))
4764 /* Make sure we have SRB */
4765 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
4767 /* Clear active and pending flags */
4768 LunExtension
->Flags
&= ~(LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
);
4770 /* Get next Irp, and clear pending requests list */
4771 NextIrp
= LunExtension
->PendingRequest
;
4772 LunExtension
->PendingRequest
= NULL
;
4774 /* Set attempt counter to zero */
4775 LunExtension
->AttemptCount
= 0;
4777 /* Release the spinlock */
4778 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4780 /* Start the next pending request */
4781 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4787 /* Release the spinlock, without clearing any flags and exit */
4788 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4794 /* Reset active flag */
4795 LunExtension
->Flags
&= ~SCSI_PORT_LU_ACTIVE
;
4797 /* Set attempt counter to zero */
4798 LunExtension
->AttemptCount
= 0;
4800 /* Remove packet from the device queue */
4801 Entry
= KeRemoveByKeyDeviceQueue(&LunExtension
->DeviceQueue
, LunExtension
->SortKey
);
4805 /* Get pointer to the next irp */
4806 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
4808 /* Get point to the SRB */
4809 IrpStack
= IoGetCurrentIrpStackLocation(NextIrp
);
4810 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
4813 LunExtension
->SortKey
= Srb
->QueueSortKey
;
4814 LunExtension
->SortKey
++;
4816 /* Release the spinlock */
4817 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4819 /* Start the next pending request */
4820 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4824 /* Release the spinlock */
4825 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4831 // ScsiPortDpcForIsr
4838 // IN PDEVICE_OBJECT DpcDeviceObject
4840 // IN PVOID DpcContext
4843 ScsiPortDpcForIsr(IN PKDPC Dpc
,
4844 IN PDEVICE_OBJECT DpcDeviceObject
,
4846 IN PVOID DpcContext
)
4848 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DpcDeviceObject
->DeviceExtension
;
4849 SCSI_PORT_INTERRUPT_DATA InterruptData
;
4850 SCSI_PORT_SAVE_INTERRUPT Context
;
4851 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4852 BOOLEAN NeedToStartIo
;
4853 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
4854 LARGE_INTEGER TimerValue
;
4856 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4857 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
4859 /* We need to acquire spinlock */
4860 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4862 RtlZeroMemory(&InterruptData
, sizeof(SCSI_PORT_INTERRUPT_DATA
));
4866 /* Interrupt structure must be snapshotted, and only then analyzed */
4867 Context
.InterruptData
= &InterruptData
;
4868 Context
.DeviceExtension
= DeviceExtension
;
4870 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
4871 SpiSaveInterruptData
,
4874 /* Nothing - just return (don't forget to release the spinlock */
4875 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4876 DPRINT("ScsiPortDpcForIsr() done\n");
4880 /* If flush of adapters is needed - do it */
4881 if (InterruptData
.Flags
& SCSI_PORT_FLUSH_ADAPTERS
)
4883 /* TODO: Implement */
4887 /* Check for IoMapTransfer */
4888 if (InterruptData
.Flags
& SCSI_PORT_MAP_TRANSFER
)
4890 /* TODO: Implement */
4894 /* Check if timer is needed */
4895 if (InterruptData
.Flags
& SCSI_PORT_TIMER_NEEDED
)
4897 /* Save the timer routine */
4898 DeviceExtension
->HwScsiTimer
= InterruptData
.HwScsiTimer
;
4900 if (InterruptData
.MiniportTimerValue
== 0)
4902 /* Cancel the timer */
4903 KeCancelTimer(&DeviceExtension
->MiniportTimer
);
4907 /* Convert timer value */
4908 TimerValue
.QuadPart
= Int32x32To64(InterruptData
.MiniportTimerValue
, -10);
4911 KeSetTimer(&DeviceExtension
->MiniportTimer
,
4913 &DeviceExtension
->MiniportTimerDpc
);
4917 /* If it's ready for the next request */
4918 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4920 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4921 if ((DeviceExtension
->Flags
&
4922 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
)) ==
4923 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
))
4925 /* Clear busy flag set by ScsiPortStartPacket() */
4926 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4928 if (!(InterruptData
.Flags
& SCSI_PORT_RESET
))
4930 /* Ready for next, and no reset is happening */
4931 DeviceExtension
->TimerCount
= -1;
4936 /* Not busy, but not ready for the next request */
4937 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4938 InterruptData
.Flags
&= ~SCSI_PORT_NEXT_REQUEST_READY
;
4943 if (InterruptData
.Flags
& SCSI_PORT_RESET_REPORTED
)
4945 /* Hold for a bit */
4946 DeviceExtension
->TimerCount
= 4;
4949 /* Any ready LUN? */
4950 if (InterruptData
.ReadyLun
!= NULL
)
4953 /* Process all LUNs from the list*/
4956 /* Remove it from the list first (as processed) */
4957 LunExtension
= InterruptData
.ReadyLun
;
4958 InterruptData
.ReadyLun
= LunExtension
->ReadyLun
;
4959 LunExtension
->ReadyLun
= NULL
;
4961 /* Get next request for this LUN */
4962 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4964 /* Still ready requests exist?
4965 If yes - get spinlock, if no - stop here */
4966 if (InterruptData
.ReadyLun
!= NULL
)
4967 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4974 /* Release the spinlock */
4975 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4978 /* If we ready for next packet, start it */
4979 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4980 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4982 NeedToStartIo
= FALSE
;
4984 /* Loop the completed request list */
4985 while (InterruptData
.CompletedRequests
)
4987 /* Remove the request */
4988 SrbInfo
= InterruptData
.CompletedRequests
;
4989 InterruptData
.CompletedRequests
= SrbInfo
->CompletedRequests
;
4990 SrbInfo
->CompletedRequests
= NULL
;
4993 SpiProcessCompletedRequest(DeviceExtension
,
4998 /* Loop abort request list */
4999 while (InterruptData
.CompletedAbort
)
5001 LunExtension
= InterruptData
.CompletedAbort
;
5003 /* Remove the request */
5004 InterruptData
.CompletedAbort
= LunExtension
->CompletedAbortRequests
;
5006 /* Get spinlock since we're going to change flags */
5007 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5009 /* TODO: Put SrbExtension to the list of free extensions */
5013 /* If we need - call StartIo routine */
5016 /* Make sure CurrentIrp is not null! */
5017 ASSERT(DpcDeviceObject
->CurrentIrp
!= NULL
);
5018 ScsiPortStartIo(DpcDeviceObject
, DpcDeviceObject
->CurrentIrp
);
5021 /* Everything has been done, check */
5022 if (InterruptData
.Flags
& SCSI_PORT_ENABLE_INT_REQUEST
)
5024 /* Synchronize using spinlock */
5025 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5027 /* Request an interrupt */
5028 DeviceExtension
->HwInterrupt(DeviceExtension
->MiniPortDeviceExtension
);
5030 ASSERT(DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
);
5032 /* Should interrupts be enabled again? */
5033 if (DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
)
5035 /* Clear this flag */
5036 DeviceExtension
->Flags
&= ~SCSI_PORT_DISABLE_INT_REQUESET
;
5038 /* Call a special routine to do this */
5041 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
5042 SpiEnableInterrupts
,
5047 /* If we need a notification again - loop */
5048 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5051 /* Release the spinlock */
5052 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5055 DPRINT("ScsiPortDpcForIsr() done\n");
5060 SpiProcessTimeout(PVOID ServiceContext
)
5062 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
5063 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
5066 DPRINT("SpiProcessTimeout() entered\n");
5068 DeviceExtension
->TimerCount
= -1;
5070 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
5072 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET
;
5074 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET_REQUEST
)
5076 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET_REQUEST
;
5077 ScsiPortStartPacket(ServiceContext
);
5084 DPRINT("Resetting the bus\n");
5086 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
5088 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
, Bus
);
5090 /* Reset flags and set reset timeout to 4 seconds */
5091 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
5092 DeviceExtension
->TimerCount
= 4;
5095 /* If miniport requested - request a dpc for it */
5096 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5097 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
5106 SpiResetBus(PVOID ServiceContext
)
5108 PRESETBUS_PARAMS ResetParams
= (PRESETBUS_PARAMS
)ServiceContext
;
5109 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5111 /* Perform the bus reset */
5112 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ResetParams
->DeviceExtension
;
5113 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
,
5114 ResetParams
->PathId
);
5116 /* Set flags and start the timer */
5117 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
5118 DeviceExtension
->TimerCount
= 4;
5120 /* If miniport requested - give him a DPC */
5121 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5122 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
5129 // This function handles timeouts and other time delayed processing
5134 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
5135 // IN PVOID Context the Controller extension for the
5136 // controller the device is on
5139 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
5142 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5143 PSCSI_PORT_LUN_EXTENSION LunExtension
;
5147 DPRINT("ScsiPortIoTimer()\n");
5149 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
5151 /* Protect with the spinlock */
5152 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5154 /* Check timeouts */
5155 if (DeviceExtension
->TimerCount
> 0)
5157 /* Decrease the timeout counter */
5158 DeviceExtension
->TimerCount
--;
5160 if (DeviceExtension
->TimerCount
== 0)
5162 /* Timeout, process it */
5163 if (KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
5165 DeviceExtension
->DeviceObject
))
5167 DPRINT("Error happened during processing timeout, but nothing critical\n");
5171 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5173 /* We should exit now, since timeout is processed */
5177 /* Per-Lun scanning of timeouts is needed... */
5178 for (Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
5180 LunExtension
= DeviceExtension
->LunExtensionList
[Lun
];
5182 while (LunExtension
)
5184 if (LunExtension
->Flags
& LUNEX_BUSY
)
5186 if (!(LunExtension
->Flags
&
5187 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_FROZEN_QUEUE
)))
5189 DPRINT("Retrying busy request\n");
5191 /* Clear flags, and retry busy request */
5192 LunExtension
->Flags
&= ~(LUNEX_BUSY
| LUNEX_FULL_QUEUE
);
5193 Irp
= LunExtension
->BusyRequest
;
5195 /* Clearing busy request */
5196 LunExtension
->BusyRequest
= NULL
;
5198 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5200 IoStartPacket(DeviceObject
, Irp
, (PULONG
)NULL
, NULL
);
5202 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5205 else if (LunExtension
->RequestTimeout
== 0)
5207 RESETBUS_PARAMS ResetParams
;
5209 LunExtension
->RequestTimeout
= -1;
5211 DPRINT("Request timed out, resetting bus\n");
5213 /* Pass params to the bus reset routine */
5214 ResetParams
.PathId
= LunExtension
->PathId
;
5215 ResetParams
.DeviceExtension
= DeviceExtension
;
5217 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
5221 DPRINT1("Reset failed\n");
5224 else if (LunExtension
->RequestTimeout
> 0)
5226 /* Decrement the timeout counter */
5227 LunExtension
->RequestTimeout
--;
5230 LunExtension
= LunExtension
->Next
;
5234 /* Release the spinlock */
5235 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5238 /**********************************************************************
5243 * Builds the registry device map of all device which are attached
5244 * to the given SCSI HBA port. The device map is located at:
5245 * \Registry\Machine\DeviceMap\Scsi
5255 * Name of registry driver service key.
5262 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5263 PUNICODE_STRING RegistryPath
)
5265 PSCSI_PORT_LUN_EXTENSION LunExtension
;
5266 OBJECT_ATTRIBUTES ObjectAttributes
;
5267 UNICODE_STRING KeyName
;
5268 UNICODE_STRING ValueName
;
5269 WCHAR NameBuffer
[64];
5272 HANDLE ScsiPortKey
= NULL
;
5273 HANDLE ScsiBusKey
= NULL
;
5274 HANDLE ScsiInitiatorKey
= NULL
;
5275 HANDLE ScsiTargetKey
= NULL
;
5276 HANDLE ScsiLunKey
= NULL
;
5279 ULONG CurrentTarget
;
5286 DPRINT("SpiBuildDeviceMap() called\n");
5288 if (DeviceExtension
== NULL
|| RegistryPath
== NULL
)
5290 DPRINT1("Invalid parameter\n");
5291 return(STATUS_INVALID_PARAMETER
);
5294 /* Open or create the 'Scsi' subkey */
5295 RtlInitUnicodeString(&KeyName
,
5296 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
5297 InitializeObjectAttributes(&ObjectAttributes
,
5299 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
5302 Status
= ZwCreateKey(&ScsiKey
,
5307 REG_OPTION_VOLATILE
,
5309 if (!NT_SUCCESS(Status
))
5311 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5315 /* Create new 'Scsi Port X' subkey */
5316 DPRINT("Scsi Port %lu\n",
5317 DeviceExtension
->PortNumber
);
5319 swprintf(NameBuffer
,
5321 DeviceExtension
->PortNumber
);
5322 RtlInitUnicodeString(&KeyName
,
5324 InitializeObjectAttributes(&ObjectAttributes
,
5329 Status
= ZwCreateKey(&ScsiPortKey
,
5334 REG_OPTION_VOLATILE
,
5337 if (!NT_SUCCESS(Status
))
5339 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5344 * Create port-specific values
5347 /* Set 'DMA Enabled' (REG_DWORD) value */
5348 UlongData
= (ULONG
)!DeviceExtension
->PortCapabilities
.AdapterUsesPio
;
5349 DPRINT(" DMA Enabled = %s\n", (UlongData
) ? "TRUE" : "FALSE");
5350 RtlInitUnicodeString(&ValueName
,
5352 Status
= ZwSetValueKey(ScsiPortKey
,
5358 if (!NT_SUCCESS(Status
))
5360 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status
);
5361 ZwClose(ScsiPortKey
);
5365 /* Set 'Driver' (REG_SZ) value */
5366 DriverName
= wcsrchr(RegistryPath
->Buffer
, L
'\\') + 1;
5367 RtlInitUnicodeString(&ValueName
,
5369 Status
= ZwSetValueKey(ScsiPortKey
,
5374 (ULONG
)((wcslen(DriverName
) + 1) * sizeof(WCHAR
)));
5375 if (!NT_SUCCESS(Status
))
5377 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status
);
5378 ZwClose(ScsiPortKey
);
5382 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
5383 UlongData
= (ULONG
)DeviceExtension
->PortConfig
->BusInterruptLevel
;
5384 DPRINT(" Interrupt = %lu\n", UlongData
);
5385 RtlInitUnicodeString(&ValueName
,
5387 Status
= ZwSetValueKey(ScsiPortKey
,
5393 if (!NT_SUCCESS(Status
))
5395 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status
);
5396 ZwClose(ScsiPortKey
);
5400 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
5401 UlongData
= ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension
->PortConfig
->AccessRanges
)[0].RangeStart
);
5402 DPRINT(" IOAddress = %lx\n", UlongData
);
5403 RtlInitUnicodeString(&ValueName
,
5405 Status
= ZwSetValueKey(ScsiPortKey
,
5411 if (!NT_SUCCESS(Status
))
5413 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status
);
5414 ZwClose(ScsiPortKey
);
5418 /* Enumerate buses */
5419 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
->NumberOfBuses
; BusNumber
++)
5421 /* Create 'Scsi Bus X' key */
5422 DPRINT(" Scsi Bus %lu\n", BusNumber
);
5423 swprintf(NameBuffer
,
5426 RtlInitUnicodeString(&KeyName
,
5428 InitializeObjectAttributes(&ObjectAttributes
,
5433 Status
= ZwCreateKey(&ScsiBusKey
,
5438 REG_OPTION_VOLATILE
,
5440 if (!NT_SUCCESS(Status
))
5442 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5446 /* Create 'Initiator Id X' key */
5447 DPRINT(" Initiator Id %u\n",
5448 DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5449 swprintf(NameBuffer
,
5451 (unsigned int)(UCHAR
)DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
5452 RtlInitUnicodeString(&KeyName
,
5454 InitializeObjectAttributes(&ObjectAttributes
,
5459 Status
= ZwCreateKey(&ScsiInitiatorKey
,
5464 REG_OPTION_VOLATILE
,
5466 if (!NT_SUCCESS(Status
))
5468 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5472 /* FIXME: Are there any initiator values (??) */
5474 ZwClose(ScsiInitiatorKey
);
5475 ScsiInitiatorKey
= NULL
;
5478 /* Enumerate targets */
5479 CurrentTarget
= (ULONG
)-1;
5480 ScsiTargetKey
= NULL
;
5481 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
5483 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
5485 LunExtension
= SpiGetLunExtension(DeviceExtension
,
5489 if (LunExtension
!= NULL
)
5491 if (Target
!= CurrentTarget
)
5493 /* Close old target key */
5494 if (ScsiTargetKey
!= NULL
)
5496 ZwClose(ScsiTargetKey
);
5497 ScsiTargetKey
= NULL
;
5500 /* Create 'Target Id X' key */
5501 DPRINT(" Target Id %lu\n", Target
);
5502 swprintf(NameBuffer
,
5505 RtlInitUnicodeString(&KeyName
,
5507 InitializeObjectAttributes(&ObjectAttributes
,
5512 Status
= ZwCreateKey(&ScsiTargetKey
,
5517 REG_OPTION_VOLATILE
,
5519 if (!NT_SUCCESS(Status
))
5521 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5525 CurrentTarget
= Target
;
5528 /* Create 'Logical Unit Id X' key */
5529 DPRINT(" Logical Unit Id %lu\n", Lun
);
5530 swprintf(NameBuffer
,
5531 L
"Logical Unit Id %lu",
5533 RtlInitUnicodeString(&KeyName
,
5535 InitializeObjectAttributes(&ObjectAttributes
,
5540 Status
= ZwCreateKey(&ScsiLunKey
,
5545 REG_OPTION_VOLATILE
,
5547 if (!NT_SUCCESS(Status
))
5549 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
5553 /* Set 'Identifier' (REG_SZ) value */
5554 swprintf(NameBuffer
,
5556 LunExtension
->InquiryData
.VendorId
,
5557 LunExtension
->InquiryData
.ProductId
,
5558 LunExtension
->InquiryData
.ProductRevisionLevel
);
5559 DPRINT(" Identifier = '%S'\n", NameBuffer
);
5560 RtlInitUnicodeString(&ValueName
,
5562 Status
= ZwSetValueKey(ScsiLunKey
,
5567 (ULONG
)((wcslen(NameBuffer
) + 1) * sizeof(WCHAR
)));
5568 if (!NT_SUCCESS(Status
))
5570 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status
);
5574 /* Set 'Type' (REG_SZ) value */
5575 switch (LunExtension
->InquiryData
.DeviceType
)
5578 TypeName
= L
"DiskPeripheral";
5581 TypeName
= L
"TapePeripheral";
5584 TypeName
= L
"PrinterPeripheral";
5587 TypeName
= L
"WormPeripheral";
5590 TypeName
= L
"CdRomPeripheral";
5593 TypeName
= L
"ScannerPeripheral";
5596 TypeName
= L
"OpticalDiskPeripheral";
5599 TypeName
= L
"MediumChangerPeripheral";
5602 TypeName
= L
"CommunicationPeripheral";
5605 TypeName
= L
"OtherPeripheral";
5608 DPRINT(" Type = '%S'\n", TypeName
);
5609 RtlInitUnicodeString(&ValueName
,
5611 Status
= ZwSetValueKey(ScsiLunKey
,
5616 (ULONG
)((wcslen(TypeName
) + 1) * sizeof(WCHAR
)));
5617 if (!NT_SUCCESS(Status
))
5619 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status
);
5623 ZwClose(ScsiLunKey
);
5628 /* Close old target key */
5629 if (ScsiTargetKey
!= NULL
)
5631 ZwClose(ScsiTargetKey
);
5632 ScsiTargetKey
= NULL
;
5636 ZwClose(ScsiBusKey
);
5641 if (ScsiLunKey
!= NULL
)
5642 ZwClose (ScsiLunKey
);
5644 if (ScsiInitiatorKey
!= NULL
)
5645 ZwClose (ScsiInitiatorKey
);
5647 if (ScsiTargetKey
!= NULL
)
5648 ZwClose (ScsiTargetKey
);
5650 if (ScsiBusKey
!= NULL
)
5651 ZwClose (ScsiBusKey
);
5653 if (ScsiPortKey
!= NULL
)
5654 ZwClose (ScsiPortKey
);
5656 DPRINT("SpiBuildDeviceMap() done\n");
5663 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
5664 IN PVOID DeviceObject
,
5665 IN PVOID SystemArgument1
,
5666 IN PVOID SystemArgument2
)
5668 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
5670 DPRINT("Miniport timer DPC\n");
5672 DeviceExtension
= ((PDEVICE_OBJECT
)DeviceObject
)->DeviceExtension
;
5674 /* Acquire the spinlock */
5675 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
5677 /* Call the timer routine */
5678 if (DeviceExtension
->HwScsiTimer
!= NULL
)
5680 DeviceExtension
->HwScsiTimer(&DeviceExtension
->MiniPortDeviceExtension
);
5683 /* Release the spinlock */
5684 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
5686 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
5688 ScsiPortDpcForIsr(NULL
,
5689 DeviceExtension
->DeviceObject
,
5696 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5697 PHW_INITIALIZATION_DATA HwInitData
,
5698 PCONFIGURATION_INFO InternalConfigInfo
,
5699 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5702 UNICODE_STRING UnicodeString
;
5703 OBJECT_ATTRIBUTES ObjectAttributes
;
5704 PCONFIGURATION_INFORMATION DdkConfigInformation
;
5705 HANDLE RootKey
, Key
;
5707 WCHAR DeviceBuffer
[16];
5708 WCHAR StrBuffer
[512];
5712 /* Zero out the struct if told so */
5715 /* First zero the portconfig */
5716 RtlZeroMemory(ConfigInfo
, sizeof(PORT_CONFIGURATION_INFORMATION
));
5718 /* Then access ranges */
5719 RtlZeroMemory(InternalConfigInfo
->AccessRanges
,
5720 HwInitData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
5722 /* Initialize the struct */
5723 ConfigInfo
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
5724 ConfigInfo
->AdapterInterfaceType
= HwInitData
->AdapterInterfaceType
;
5725 ConfigInfo
->InterruptMode
= Latched
;
5726 ConfigInfo
->DmaChannel
= SP_UNINITIALIZED_VALUE
;
5727 ConfigInfo
->DmaPort
= SP_UNINITIALIZED_VALUE
;
5728 ConfigInfo
->DmaChannel2
= SP_UNINITIALIZED_VALUE
;
5729 ConfigInfo
->DmaPort2
= SP_UNINITIALIZED_VALUE
;
5730 ConfigInfo
->MaximumTransferLength
= SP_UNINITIALIZED_VALUE
;
5731 ConfigInfo
->NumberOfAccessRanges
= HwInitData
->NumberOfAccessRanges
;
5732 ConfigInfo
->MaximumNumberOfTargets
= 8;
5734 /* Store parameters */
5735 ConfigInfo
->NeedPhysicalAddresses
= HwInitData
->NeedPhysicalAddresses
;
5736 ConfigInfo
->MapBuffers
= HwInitData
->MapBuffers
;
5737 ConfigInfo
->AutoRequestSense
= HwInitData
->AutoRequestSense
;
5738 ConfigInfo
->ReceiveEvent
= HwInitData
->ReceiveEvent
;
5739 ConfigInfo
->TaggedQueuing
= HwInitData
->TaggedQueuing
;
5740 ConfigInfo
->MultipleRequestPerLu
= HwInitData
->MultipleRequestPerLu
;
5742 /* Get the disk usage */
5743 DdkConfigInformation
= IoGetConfigurationInformation();
5744 ConfigInfo
->AtdiskPrimaryClaimed
= DdkConfigInformation
->AtDiskPrimaryAddressClaimed
;
5745 ConfigInfo
->AtdiskSecondaryClaimed
= DdkConfigInformation
->AtDiskSecondaryAddressClaimed
;
5747 /* Initiator bus id is not set */
5748 for (Bus
= 0; Bus
< 8; Bus
++)
5749 ConfigInfo
->InitiatorBusId
[Bus
] = (CCHAR
)SP_UNINITIALIZED_VALUE
;
5752 ConfigInfo
->NumberOfPhysicalBreaks
= 17;
5754 /* Clear this information */
5755 InternalConfigInfo
->DisableTaggedQueueing
= FALSE
;
5756 InternalConfigInfo
->DisableMultipleLun
= FALSE
;
5758 /* Store Bus Number */
5759 ConfigInfo
->SystemIoBusNumber
= InternalConfigInfo
->BusNumber
;
5763 if (ConfigInfo
->AdapterInterfaceType
== Internal
)
5765 /* Open registry key for HW database */
5766 InitializeObjectAttributes(&ObjectAttributes
,
5767 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
5768 OBJ_CASE_INSENSITIVE
,
5772 Status
= ZwOpenKey(&RootKey
,
5776 if (NT_SUCCESS(Status
))
5778 /* Create name for it */
5779 swprintf(StrBuffer
, L
"ScsiAdapter\\%lu",
5780 InternalConfigInfo
->AdapterNumber
);
5782 RtlInitUnicodeString(&UnicodeString
, StrBuffer
);
5784 /* Open device key */
5785 InitializeObjectAttributes(&ObjectAttributes
,
5787 OBJ_CASE_INSENSITIVE
,
5791 Status
= ZwOpenKey(&Key
,
5797 if (NT_SUCCESS(Status
))
5799 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5801 DPRINT("Hardware info found at %S\n", StrBuffer
);
5804 SpiParseDeviceInfo(DeviceExtension
,
5810 InternalConfigInfo
->BusNumber
= 0;
5814 /* Try the next adapter */
5815 InternalConfigInfo
->AdapterNumber
++;
5821 /* Info was not found, exit */
5822 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status
);
5823 return STATUS_DEVICE_DOES_NOT_EXIST
;
5828 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status
);
5832 /* Look at device params */
5834 if (InternalConfigInfo
->Parameter
)
5836 ExFreePool(InternalConfigInfo
->Parameter
);
5837 InternalConfigInfo
->Parameter
= NULL
;
5840 if (InternalConfigInfo
->ServiceKey
!= NULL
)
5842 swprintf(DeviceBuffer
, L
"Device%lu", InternalConfigInfo
->AdapterNumber
);
5843 RtlInitUnicodeString(&UnicodeString
, DeviceBuffer
);
5845 /* Open the service key */
5846 InitializeObjectAttributes(&ObjectAttributes
,
5848 OBJ_CASE_INSENSITIVE
,
5849 InternalConfigInfo
->ServiceKey
,
5852 Status
= ZwOpenKey(&Key
,
5857 /* Parse device key */
5858 if (InternalConfigInfo
->DeviceKey
!= NULL
)
5860 SpiParseDeviceInfo(DeviceExtension
,
5861 InternalConfigInfo
->DeviceKey
,
5867 /* Then parse hw info */
5870 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5872 SpiParseDeviceInfo(DeviceExtension
,
5883 /* Adapter not found, go try the next one */
5884 InternalConfigInfo
->AdapterNumber
++;
5893 /* Update the last adapter number */
5894 InternalConfigInfo
->LastAdapterNumber
= InternalConfigInfo
->AdapterNumber
;
5896 /* Do we have this kind of bus at all? */
5898 Status
= IoQueryDeviceDescription(&HwInitData
->AdapterInterfaceType
,
5899 &InternalConfigInfo
->BusNumber
,
5904 SpQueryDeviceCallout
,
5907 /* This bus was not found */
5910 INTERFACE_TYPE InterfaceType
= Eisa
;
5912 /* Check for EISA */
5913 if (HwInitData
->AdapterInterfaceType
== Isa
)
5915 Status
= IoQueryDeviceDescription(&InterfaceType
,
5916 &InternalConfigInfo
->BusNumber
,
5921 SpQueryDeviceCallout
,
5924 /* Return respectively */
5926 return STATUS_SUCCESS
;
5928 return STATUS_DEVICE_DOES_NOT_EXIST
;
5932 return STATUS_DEVICE_DOES_NOT_EXIST
;
5937 return STATUS_SUCCESS
;
5942 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5944 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5945 IN PCONFIGURATION_INFO InternalConfigInfo
,
5948 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
5949 PCM_FULL_RESOURCE_DESCRIPTOR FullResource
;
5950 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
5951 PCM_SCSI_DEVICE_DATA ScsiDeviceData
;
5952 ULONG Length
, Count
, Dma
= 0, Interrupt
= 0;
5953 ULONG Index
= 0, RangeCount
= 0;
5954 UNICODE_STRING UnicodeString
;
5955 ANSI_STRING AnsiString
;
5956 NTSTATUS Status
= STATUS_SUCCESS
;
5959 KeyValueInformation
= (PKEY_VALUE_FULL_INFORMATION
) Buffer
;
5961 /* Loop through all values in the device node */
5964 Status
= ZwEnumerateValueKey(Key
,
5966 KeyValueFullInformation
,
5971 if (!NT_SUCCESS(Status
))
5976 /* Length for DWORD is ok? */
5977 if (KeyValueInformation
->Type
== REG_DWORD
&&
5978 KeyValueInformation
->DataLength
!= sizeof(ULONG
))
5983 /* Get MaximumLogicalUnit */
5984 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumLogicalUnit",
5985 KeyValueInformation
->NameLength
/2) == 0)
5988 if (KeyValueInformation
->Type
!= REG_DWORD
)
5990 DPRINT("Bad data type for MaximumLogicalUnit\n");
5994 DeviceExtension
->MaxLunCount
= *((PUCHAR
)
5995 (Buffer
+ KeyValueInformation
->DataOffset
));
5997 /* Check / reset if needed */
5998 if (DeviceExtension
->MaxLunCount
> SCSI_MAXIMUM_LOGICAL_UNITS
)
5999 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
6001 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension
->MaxLunCount
);
6004 /* Get InitiatorTargetId */
6005 if (_wcsnicmp(KeyValueInformation
->Name
, L
"InitiatorTargetId",
6006 KeyValueInformation
->NameLength
/ 2) == 0)
6009 if (KeyValueInformation
->Type
!= REG_DWORD
)
6011 DPRINT("Bad data type for InitiatorTargetId\n");
6015 ConfigInfo
->InitiatorBusId
[0] = *((PUCHAR
)
6016 (Buffer
+ KeyValueInformation
->DataOffset
));
6018 /* Check / reset if needed */
6019 if (ConfigInfo
->InitiatorBusId
[0] > ConfigInfo
->MaximumNumberOfTargets
- 1)
6020 ConfigInfo
->InitiatorBusId
[0] = (CCHAR
)-1;
6022 DPRINT("InitiatorTargetId = %d\n", ConfigInfo
->InitiatorBusId
[0]);
6026 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ScsiDebug",
6027 KeyValueInformation
->NameLength
/2) == 0)
6029 DPRINT("ScsiDebug key not supported\n");
6032 /* Check for a breakpoint */
6033 if (_wcsnicmp(KeyValueInformation
->Name
, L
"BreakPointOnEntry",
6034 KeyValueInformation
->NameLength
/2) == 0)
6036 DPRINT1("Breakpoint on entry requested!\n");
6040 /* Get DisableSynchronousTransfers */
6041 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableSynchronousTransfers",
6042 KeyValueInformation
->NameLength
/2) == 0)
6044 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6045 DPRINT("Synch transfers disabled\n");
6048 /* Get DisableDisconnects */
6049 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableDisconnects",
6050 KeyValueInformation
->NameLength
/2) == 0)
6052 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
6053 DPRINT("Disconnects disabled\n");
6056 /* Get DisableTaggedQueuing */
6057 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableTaggedQueuing",
6058 KeyValueInformation
->NameLength
/2) == 0)
6060 InternalConfigInfo
->DisableTaggedQueueing
= TRUE
;
6061 DPRINT("Tagged queueing disabled\n");
6064 /* Get DisableMultipleRequests */
6065 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableMultipleRequests",
6066 KeyValueInformation
->NameLength
/2) == 0)
6068 InternalConfigInfo
->DisableMultipleLun
= TRUE
;
6069 DPRINT("Multiple requests disabled\n");
6072 /* Get DriverParameters */
6073 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DriverParameters",
6074 KeyValueInformation
->NameLength
/2) == 0)
6076 /* Skip if nothing */
6077 if (KeyValueInformation
->DataLength
== 0)
6080 /* If there was something previously allocated - free it */
6081 if (InternalConfigInfo
->Parameter
!= NULL
)
6082 ExFreePool(InternalConfigInfo
->Parameter
);
6085 InternalConfigInfo
->Parameter
= ExAllocatePoolWithTag(NonPagedPool
,
6086 KeyValueInformation
->DataLength
, TAG_SCSIPORT
);
6088 if (InternalConfigInfo
->Parameter
!= NULL
)
6090 if (KeyValueInformation
->Type
!= REG_SZ
)
6094 InternalConfigInfo
->Parameter
,
6095 (PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
,
6096 KeyValueInformation
->DataLength
);
6100 /* If it's a unicode string, convert it to ansi */
6101 UnicodeString
.Length
= (USHORT
)KeyValueInformation
->DataLength
;
6102 UnicodeString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
6103 UnicodeString
.Buffer
=
6104 (PWSTR
)((PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
6106 AnsiString
.Length
= 0;
6107 AnsiString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
6108 AnsiString
.Buffer
= (PCHAR
)InternalConfigInfo
->Parameter
;
6110 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
6114 /* In case of error, free the allocated space */
6115 if (!NT_SUCCESS(Status
))
6117 ExFreePool(InternalConfigInfo
->Parameter
);
6118 InternalConfigInfo
->Parameter
= NULL
;
6124 DPRINT("Found driver parameter\n");
6127 /* Get MaximumSGList */
6128 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumSGList",
6129 KeyValueInformation
->NameLength
/2) == 0)
6131 if (KeyValueInformation
->Type
!= REG_DWORD
)
6133 DPRINT("Bad data type for MaximumSGList\n");
6137 ConfigInfo
->NumberOfPhysicalBreaks
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
6140 if (ConfigInfo
->NumberOfPhysicalBreaks
> SCSI_MAXIMUM_PHYSICAL_BREAKS
)
6142 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MAXIMUM_PHYSICAL_BREAKS
;
6144 else if (ConfigInfo
->NumberOfPhysicalBreaks
< SCSI_MINIMUM_PHYSICAL_BREAKS
)
6146 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MINIMUM_PHYSICAL_BREAKS
;
6149 DPRINT("MaximumSGList = %d\n", ConfigInfo
->NumberOfPhysicalBreaks
);
6152 /* Get NumberOfRequests */
6153 if (_wcsnicmp(KeyValueInformation
->Name
, L
"NumberOfRequests",
6154 KeyValueInformation
->NameLength
/2) == 0)
6156 if (KeyValueInformation
->Type
!= REG_DWORD
)
6158 DPRINT("NumberOfRequests has wrong data type\n");
6162 DeviceExtension
->RequestsNumber
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
6165 if (DeviceExtension
->RequestsNumber
< 16)
6167 DeviceExtension
->RequestsNumber
= 16;
6169 else if (DeviceExtension
->RequestsNumber
> 512)
6171 DeviceExtension
->RequestsNumber
= 512;
6174 DPRINT("Number Of Requests = %d\n", DeviceExtension
->RequestsNumber
);
6177 /* Get resource list */
6178 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ResourceList",
6179 KeyValueInformation
->NameLength
/2) == 0 ||
6180 _wcsnicmp(KeyValueInformation
->Name
, L
"Configuration Data",
6181 KeyValueInformation
->NameLength
/2) == 0 )
6183 if (KeyValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
||
6184 KeyValueInformation
->DataLength
< sizeof(REG_FULL_RESOURCE_DESCRIPTOR
))
6186 DPRINT("Bad data type for ResourceList\n");
6191 DPRINT("Found ResourceList\n");
6194 FullResource
= (PCM_FULL_RESOURCE_DESCRIPTOR
)(Buffer
+ KeyValueInformation
->DataOffset
);
6196 /* Copy some info from it */
6197 InternalConfigInfo
->BusNumber
= FullResource
->BusNumber
;
6198 ConfigInfo
->SystemIoBusNumber
= FullResource
->BusNumber
;
6200 /* Loop through it */
6201 for (Count
= 0; Count
< FullResource
->PartialResourceList
.Count
; Count
++)
6203 /* Get partial descriptor */
6205 &FullResource
->PartialResourceList
.PartialDescriptors
[Count
];
6207 /* Check datalength */
6208 if ((ULONG
)((PCHAR
)(PartialDescriptor
+ 1) -
6209 (PCHAR
)FullResource
) > KeyValueInformation
->DataLength
)
6211 DPRINT("Resource data is of incorrect size\n");
6215 switch (PartialDescriptor
->Type
)
6217 case CmResourceTypePort
:
6218 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
6220 DPRINT("Too many access ranges\n");
6224 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= FALSE
;
6225 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Port
.Start
;
6226 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Port
.Length
;
6231 case CmResourceTypeMemory
:
6232 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
6234 DPRINT("Too many access ranges\n");
6238 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= TRUE
;
6239 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Memory
.Start
;
6240 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Memory
.Length
;
6245 case CmResourceTypeInterrupt
:
6249 ConfigInfo
->BusInterruptLevel
=
6250 PartialDescriptor
->u
.Interrupt
.Level
;
6252 ConfigInfo
->BusInterruptVector
=
6253 PartialDescriptor
->u
.Interrupt
.Vector
;
6255 ConfigInfo
->InterruptMode
= (PartialDescriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
) ? Latched
: LevelSensitive
;
6257 else if (Interrupt
== 1)
6259 ConfigInfo
->BusInterruptLevel2
=
6260 PartialDescriptor
->u
.Interrupt
.Level
;
6262 ConfigInfo
->BusInterruptVector2
=
6263 PartialDescriptor
->u
.Interrupt
.Vector
;
6265 ConfigInfo
->InterruptMode2
= (PartialDescriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
) ? Latched
: LevelSensitive
;
6271 case CmResourceTypeDma
:
6275 ConfigInfo
->DmaChannel
= PartialDescriptor
->u
.Dma
.Channel
;
6276 ConfigInfo
->DmaPort
= PartialDescriptor
->u
.Dma
.Port
;
6278 if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8
)
6279 ConfigInfo
->DmaWidth
= Width8Bits
;
6280 else if ((PartialDescriptor
->Flags
& CM_RESOURCE_DMA_16
) ||
6281 (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
6282 ConfigInfo
->DmaWidth
= Width16Bits
;
6283 else if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_32
)
6284 ConfigInfo
->DmaWidth
= Width32Bits
;
6288 ConfigInfo
->DmaChannel2
= PartialDescriptor
->u
.Dma
.Channel
;
6289 ConfigInfo
->DmaPort2
= PartialDescriptor
->u
.Dma
.Port
;
6291 if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8
)
6292 ConfigInfo
->DmaWidth2
= Width8Bits
;
6293 else if ((PartialDescriptor
->Flags
& CM_RESOURCE_DMA_16
) ||
6294 (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_8_AND_16
)) //???
6295 ConfigInfo
->DmaWidth2
= Width16Bits
;
6296 else if (PartialDescriptor
->Flags
& CM_RESOURCE_DMA_32
)
6297 ConfigInfo
->DmaWidth2
= Width32Bits
;
6303 case CmResourceTypeDeviceSpecific
:
6304 if (PartialDescriptor
->u
.DeviceSpecificData
.DataSize
<
6305 sizeof(CM_SCSI_DEVICE_DATA
) ||
6306 (PCHAR
) (PartialDescriptor
+ 1) - (PCHAR
)FullResource
+
6307 PartialDescriptor
->u
.DeviceSpecificData
.DataSize
>
6308 KeyValueInformation
->DataLength
)
6310 DPRINT("Resource data length is incorrect");
6314 /* Set only one field from it */
6315 ScsiDeviceData
= (PCM_SCSI_DEVICE_DATA
) (PartialDescriptor
+1);
6316 ConfigInfo
->InitiatorBusId
[0] = ScsiDeviceData
->HostIdentifier
;
6326 SpQueryDeviceCallout(IN PVOID Context
,
6327 IN PUNICODE_STRING PathName
,
6328 IN INTERFACE_TYPE BusType
,
6330 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
6331 IN CONFIGURATION_TYPE ControllerType
,
6332 IN ULONG ControllerNumber
,
6333 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
6334 IN CONFIGURATION_TYPE PeripheralType
,
6335 IN ULONG PeripheralNumber
,
6336 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
6338 PBOOLEAN Found
= (PBOOLEAN
)Context
;
6339 /* We just set our Found variable to TRUE */
6342 return STATUS_SUCCESS
;
6345 IO_ALLOCATION_ACTION
6347 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject
,
6349 IN PVOID MapRegisterBase
,
6353 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
6355 /* Guard access with the spinlock */
6356 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
6358 /* Save MapRegisterBase we've got here */
6359 DeviceExtension
->MapRegisterBase
= MapRegisterBase
;
6361 /* Start pending request */
6362 KeSynchronizeExecution(DeviceExtension
->Interrupt
[0],
6363 ScsiPortStartPacket
, DeviceObject
);
6365 /* Release spinlock we took */
6366 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
6373 SpiStatusSrbToNt(UCHAR SrbStatus
)
6375 switch (SRB_STATUS(SrbStatus
))
6377 case SRB_STATUS_TIMEOUT
:
6378 case SRB_STATUS_COMMAND_TIMEOUT
:
6379 return STATUS_IO_TIMEOUT
;
6381 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH
:
6382 case SRB_STATUS_BAD_FUNCTION
:
6383 return STATUS_INVALID_DEVICE_REQUEST
;
6385 case SRB_STATUS_NO_DEVICE
:
6386 case SRB_STATUS_INVALID_LUN
:
6387 case SRB_STATUS_INVALID_TARGET_ID
:
6388 case SRB_STATUS_NO_HBA
:
6389 return STATUS_DEVICE_DOES_NOT_EXIST
;
6391 case SRB_STATUS_DATA_OVERRUN
:
6392 return STATUS_BUFFER_OVERFLOW
;
6394 case SRB_STATUS_SELECTION_TIMEOUT
:
6395 return STATUS_DEVICE_NOT_CONNECTED
;
6398 return STATUS_IO_DEVICE_ERROR
;
6401 return STATUS_IO_DEVICE_ERROR
;
6405 #undef ScsiPortConvertPhysicalAddressToUlong
6410 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
6412 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
6413 return(Address
.u
.LowPart
);