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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS Storage Stack
23 * FILE: drivers/storage/scsiport/scsiport.c
24 * PURPOSE: SCSI port driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
26 * Aleksey Bragin (aleksey reactos org)
29 /* INCLUDES *****************************************************************/
45 #include "scsiport_int.h"
52 ULONG InternalDebugLevel
= 0x00;
54 /* TYPES *********************************************************************/
56 /* GLOBALS *******************************************************************/
59 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
60 IN PDEVICE_OBJECT DeviceObject
,
61 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
62 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
63 IN PUNICODE_STRING RegistryPath
,
65 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
);
67 static NTSTATUS STDCALL
68 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
71 static DRIVER_DISPATCH ScsiPortDispatchScsi
;
72 static NTSTATUS STDCALL
73 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
76 static NTSTATUS STDCALL
77 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
80 static DRIVER_STARTIO ScsiPortStartIo
;
82 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
85 static BOOLEAN STDCALL
86 ScsiPortStartPacket(IN OUT PVOID Context
);
89 static PSCSI_PORT_LUN_EXTENSION
90 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
92 static PSCSI_PORT_LUN_EXTENSION
93 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
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 PVOID DeviceExtension
,
116 static KSERVICE_ROUTINE ScsiPortIsr
;
117 static BOOLEAN STDCALL
118 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
119 IN PVOID ServiceContext
);
122 ScsiPortDpcForIsr(IN PKDPC Dpc
,
123 IN PDEVICE_OBJECT DpcDeviceObject
,
125 IN PVOID DpcContext
);
128 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
132 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
133 PUNICODE_STRING RegistryPath
);
136 SpiStatusSrbToNt(UCHAR SrbStatus
);
139 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
140 IN PSCSI_REQUEST_BLOCK Srb
);
142 static IO_COMPLETION_ROUTINE SpiCompletionRoutine
;
144 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
150 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
151 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
152 OUT PBOOLEAN NeedToCallStartIo
);
155 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
156 IN PSCSI_PORT_LUN_EXTENSION LunExtension
);
159 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
160 IN PVOID DeviceObject
,
161 IN PVOID SystemArgument1
,
162 IN PVOID SystemArgument2
);
165 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
166 PHW_INITIALIZATION_DATA HwInitData
,
167 PCONFIGURATION_INFO InternalConfigInfo
,
168 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
172 SpQueryDeviceCallout(IN PVOID Context
,
173 IN PUNICODE_STRING PathName
,
174 IN INTERFACE_TYPE BusType
,
176 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
177 IN CONFIGURATION_TYPE ControllerType
,
178 IN ULONG ControllerNumber
,
179 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
180 IN CONFIGURATION_TYPE PeripheralType
,
181 IN ULONG PeripheralNumber
,
182 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
);
185 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
187 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
188 IN PCONFIGURATION_INFO InternalConfigInfo
,
192 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
193 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
194 IN PPORT_CONFIGURATION_INFORMATION PortConfig
);
196 static PCM_RESOURCE_LIST
197 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
198 PPORT_CONFIGURATION_INFORMATION PortConfig
);
201 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
204 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
208 /* FUNCTIONS *****************************************************************/
210 /**********************************************************************
215 * This function initializes the driver.
222 * System allocated Driver Object for this driver.
225 * Name of registry driver service key.
232 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
233 IN PUNICODE_STRING RegistryPath
)
235 DPRINT("ScsiPort Driver %s\n", VERSION
);
236 return(STATUS_SUCCESS
);
240 /**********************************************************************
245 * Prints debugging messages.
252 * Debug level of the given message.
255 * Pointer to printf()-compatible format string.
258 Additional output data (see printf()).
267 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
268 IN PCHAR DebugMessage
,
274 if (DebugPrintLevel
> InternalDebugLevel
)
277 va_start(ap
, DebugMessage
);
278 vsprintf(Buffer
, DebugMessage
, ap
);
289 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
295 DPRINT("ScsiPortCompleteRequest()\n");
303 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
305 DPRINT("ScsiPortFlushDma()\n");
314 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
315 IN PVOID MappedAddress
)
317 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
318 PMAPPED_ADDRESS NextMa
, LastMa
;
320 //DPRINT("ScsiPortFreeDeviceBase() called\n");
322 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
323 SCSI_PORT_DEVICE_EXTENSION
,
324 MiniPortDeviceExtension
);
327 /* Initialize our pointers */
328 NextMa
= DeviceExtension
->MappedAddressList
;
333 if (NextMa
->MappedAddress
== MappedAddress
)
336 MmUnmapIoSpace(MappedAddress
, NextMa
->NumberOfBytes
);
338 /* Remove it from the list */
339 if (NextMa
== DeviceExtension
->MappedAddressList
)
341 /* Remove the first entry */
342 DeviceExtension
->MappedAddressList
= NextMa
->NextMappedAddress
;
346 LastMa
->NextMappedAddress
= NextMa
->NextMappedAddress
;
349 /* Free the resources and quit */
357 NextMa
= NextMa
->NextMappedAddress
;
367 ScsiPortGetBusData(IN PVOID DeviceExtension
,
368 IN ULONG BusDataType
,
369 IN ULONG SystemIoBusNumber
,
374 return(HalGetBusData(BusDataType
,
386 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
387 IN INTERFACE_TYPE BusType
,
388 IN ULONG SystemIoBusNumber
,
389 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
390 IN ULONG NumberOfBytes
,
391 IN BOOLEAN InIoSpace
)
393 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
394 PHYSICAL_ADDRESS TranslatedAddress
;
395 PMAPPED_ADDRESS DeviceBase
;
399 //DPRINT ("ScsiPortGetDeviceBase() called\n");
401 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
402 SCSI_PORT_DEVICE_EXTENSION
,
403 MiniPortDeviceExtension
);
405 AddressSpace
= (ULONG
)InIoSpace
;
406 if (HalTranslateBusAddress(BusType
,
410 &TranslatedAddress
) == FALSE
)
416 if (AddressSpace
!= 0)
417 return((PVOID
)TranslatedAddress
.u
.LowPart
);
419 MappedAddress
= MmMapIoSpace(TranslatedAddress
,
423 DeviceBase
= ExAllocatePoolWithTag(NonPagedPool
,
424 sizeof(MAPPED_ADDRESS
), TAG_SCSIPORT
);
426 if (DeviceBase
== NULL
)
427 return MappedAddress
;
429 DeviceBase
->MappedAddress
= MappedAddress
;
430 DeviceBase
->NumberOfBytes
= NumberOfBytes
;
431 DeviceBase
->IoAddress
= IoAddress
;
432 DeviceBase
->BusNumber
= SystemIoBusNumber
;
434 /* Link it to the Device Extension list */
435 DeviceBase
->NextMappedAddress
= DeviceExtension
->MappedAddressList
;
436 DeviceExtension
->MappedAddressList
= DeviceBase
;
438 return MappedAddress
;
445 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
452 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
453 PSCSI_PORT_LUN_EXTENSION LunExtension
;
456 DPRINT("ScsiPortGetLogicalUnit() called\n");
458 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
459 SCSI_PORT_DEVICE_EXTENSION
,
460 MiniPortDeviceExtension
);
461 if (IsListEmpty(&DeviceExtension
->LunExtensionListHead
))
464 Entry
= DeviceExtension
->LunExtensionListHead
.Flink
;
465 while (Entry
!= &DeviceExtension
->LunExtensionListHead
)
467 LunExtension
= CONTAINING_RECORD(Entry
,
468 SCSI_PORT_LUN_EXTENSION
,
470 if (LunExtension
->PathId
== PathId
&&
471 LunExtension
->TargetId
== TargetId
&&
472 LunExtension
->Lun
== Lun
)
474 return (PVOID
)&LunExtension
->MiniportLunExtension
;
477 Entry
= Entry
->Flink
;
487 SCSI_PHYSICAL_ADDRESS STDCALL
488 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
489 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
490 IN PVOID VirtualAddress
,
493 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
494 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
495 SCSI_PHYSICAL_ADDRESS NextPhysicalAddress
;
496 ULONG BufferLength
= 0;
500 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
501 HwDeviceExtension
, Srb
, VirtualAddress
, Length
);
503 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
504 SCSI_PORT_DEVICE_EXTENSION
,
505 MiniPortDeviceExtension
);
511 if ((ULONG_PTR
)DeviceExtension
->VirtualAddress
> (ULONG_PTR
)VirtualAddress
)
513 PhysicalAddress
.QuadPart
= 0ULL;
514 return PhysicalAddress
;
517 Offset
= (ULONG_PTR
)VirtualAddress
- (ULONG_PTR
)DeviceExtension
->VirtualAddress
;
518 if (Offset
>= DeviceExtension
->CommonBufferLength
)
520 PhysicalAddress
.QuadPart
= 0ULL;
521 return PhysicalAddress
;
524 PhysicalAddress
.QuadPart
=
525 DeviceExtension
->PhysicalAddress
.QuadPart
+ (ULONGLONG
)Offset
;
526 BufferLength
= DeviceExtension
->CommonBufferLength
- Offset
;
530 EndAddress
= (PVOID
)((ULONG_PTR
)Srb
->DataBuffer
+ Srb
->DataTransferLength
);
531 if (VirtualAddress
== NULL
)
533 VirtualAddress
= Srb
->DataBuffer
;
535 else if (VirtualAddress
< Srb
->DataBuffer
|| VirtualAddress
>= EndAddress
)
537 PhysicalAddress
.QuadPart
= 0LL;
538 return PhysicalAddress
;
541 PhysicalAddress
= MmGetPhysicalAddress(VirtualAddress
);
542 if (PhysicalAddress
.QuadPart
== 0LL)
544 return PhysicalAddress
;
547 Offset
= (ULONG_PTR
)VirtualAddress
& (PAGE_SIZE
- 1);
551 * MmGetPhysicalAddress doesn't return the offset within the page.
552 * We must set the correct offset.
554 PhysicalAddress
.u
.LowPart
= (PhysicalAddress
.u
.LowPart
& ~(PAGE_SIZE
- 1)) + Offset
;
556 BufferLength
+= PAGE_SIZE
- Offset
;
557 while ((ULONG_PTR
)VirtualAddress
+ BufferLength
< (ULONG_PTR
)EndAddress
)
559 NextPhysicalAddress
= MmGetPhysicalAddress((PVOID
)((ULONG_PTR
)VirtualAddress
+ BufferLength
));
560 if (PhysicalAddress
.QuadPart
+ (ULONGLONG
)BufferLength
!= NextPhysicalAddress
.QuadPart
)
564 BufferLength
+= PAGE_SIZE
;
566 if ((ULONG_PTR
)VirtualAddress
+ BufferLength
>= (ULONG_PTR
)EndAddress
)
568 BufferLength
= (ULONG_PTR
)EndAddress
- (ULONG_PTR
)VirtualAddress
;
572 *Length
= BufferLength
;
574 return PhysicalAddress
;
581 PSCSI_REQUEST_BLOCK STDCALL
582 ScsiPortGetSrb(IN PVOID DeviceExtension
,
588 DPRINT1("ScsiPortGetSrb() unimplemented\n");
598 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
599 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
600 IN ULONG NumberOfBytes
)
602 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
603 DEVICE_DESCRIPTION DeviceDescription
;
605 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
606 HwDeviceExtension
, ConfigInfo
, NumberOfBytes
);
608 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
609 SCSI_PORT_DEVICE_EXTENSION
,
610 MiniPortDeviceExtension
);
612 /* Check for allocated common DMA buffer */
613 if (DeviceExtension
->VirtualAddress
!= NULL
)
615 DPRINT1("The HBA has already got a common DMA buffer!\n");
619 /* Check for DMA adapter object */
620 if (DeviceExtension
->AdapterObject
== NULL
)
622 /* Initialize DMA adapter description */
623 RtlZeroMemory(&DeviceDescription
,
624 sizeof(DEVICE_DESCRIPTION
));
625 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION
;
626 DeviceDescription
.Master
= ConfigInfo
->Master
;
627 DeviceDescription
.ScatterGather
= ConfigInfo
->ScatterGather
;
628 DeviceDescription
.DemandMode
= ConfigInfo
->DemandMode
;
629 DeviceDescription
.Dma32BitAddresses
= ConfigInfo
->Dma32BitAddresses
;
630 DeviceDescription
.BusNumber
= ConfigInfo
->SystemIoBusNumber
;
631 DeviceDescription
.DmaChannel
= ConfigInfo
->DmaChannel
;
632 DeviceDescription
.InterfaceType
= ConfigInfo
->AdapterInterfaceType
;
633 DeviceDescription
.DmaWidth
= ConfigInfo
->DmaWidth
;
634 DeviceDescription
.DmaSpeed
= ConfigInfo
->DmaSpeed
;
635 DeviceDescription
.MaximumLength
= ConfigInfo
->MaximumTransferLength
;
636 DeviceDescription
.DmaPort
= ConfigInfo
->DmaPort
;
638 /* Get a DMA adapter object */
639 DeviceExtension
->AdapterObject
= HalGetAdapter(&DeviceDescription
,
640 &DeviceExtension
->MapRegisterCount
);
641 if (DeviceExtension
->AdapterObject
== NULL
)
643 DPRINT1("HalGetAdapter() failed\n");
648 /* Allocate a common DMA buffer */
649 DeviceExtension
->CommonBufferLength
=
650 NumberOfBytes
+ DeviceExtension
->SrbExtensionSize
;
651 DeviceExtension
->VirtualAddress
=
652 HalAllocateCommonBuffer(DeviceExtension
->AdapterObject
,
653 DeviceExtension
->CommonBufferLength
,
654 &DeviceExtension
->PhysicalAddress
,
656 if (DeviceExtension
->VirtualAddress
== NULL
)
658 DPRINT1("HalAllocateCommonBuffer() failed!\n");
659 DeviceExtension
->CommonBufferLength
= 0;
663 return (PVOID
)((ULONG_PTR
)DeviceExtension
->VirtualAddress
+
664 DeviceExtension
->SrbExtensionSize
);
672 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
673 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
675 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
678 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
679 HwDeviceExtension
, PhysicalAddress
.QuadPart
);
681 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
682 SCSI_PORT_DEVICE_EXTENSION
,
683 MiniPortDeviceExtension
);
685 if (DeviceExtension
->PhysicalAddress
.QuadPart
> PhysicalAddress
.QuadPart
)
688 Offset
= (ULONG
)(PhysicalAddress
.QuadPart
- DeviceExtension
->PhysicalAddress
.QuadPart
);
689 if (Offset
>= DeviceExtension
->CommonBufferLength
)
692 return (PVOID
)((ULONG_PTR
)DeviceExtension
->VirtualAddress
+ Offset
);
696 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo
, PUNICODE_STRING RegistryPath
)
698 OBJECT_ATTRIBUTES ObjectAttributes
;
699 UNICODE_STRING KeyName
;
702 /* Open the service key */
703 InitializeObjectAttributes(&ObjectAttributes
,
705 OBJ_CASE_INSENSITIVE
,
709 Status
= ZwOpenKey(&ConfigInfo
->ServiceKey
,
713 if (!NT_SUCCESS(Status
))
715 DPRINT1("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath
, Status
);
716 ConfigInfo
->ServiceKey
= NULL
;
719 /* If we could open driver's service key, then proceed to the Parameters key */
720 if (ConfigInfo
->ServiceKey
!= NULL
)
722 RtlInitUnicodeString(&KeyName
, L
"Parameters");
723 InitializeObjectAttributes(&ObjectAttributes
,
725 OBJ_CASE_INSENSITIVE
,
726 ConfigInfo
->ServiceKey
,
727 (PSECURITY_DESCRIPTOR
) NULL
);
730 Status
= ZwOpenKey(&ConfigInfo
->DeviceKey
,
734 if (NT_SUCCESS(Status
))
736 /* Yes, Parameters key exist, and it must be used instead of
738 ZwClose(ConfigInfo
->ServiceKey
);
739 ConfigInfo
->ServiceKey
= ConfigInfo
->DeviceKey
;
740 ConfigInfo
->DeviceKey
= NULL
;
744 /* Open the Device key */
745 RtlInitUnicodeString(&KeyName
, L
"Device");
746 InitializeObjectAttributes(&ObjectAttributes
,
748 OBJ_CASE_INSENSITIVE
,
749 ConfigInfo
->ServiceKey
,
752 /* We don't check for failure here - not needed */
753 ZwOpenKey(&ConfigInfo
->DeviceKey
,
759 /**********************************************************************
764 * Initializes SCSI port driver specific data.
771 * Pointer to the miniport driver's driver object.
774 * Pointer to the miniport driver's registry path.
776 * HwInitializationData
777 * Pointer to port driver specific configuration data.
780 Miniport driver specific context.
789 ScsiPortInitialize(IN PVOID Argument1
,
791 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
794 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
795 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
796 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
797 PCONFIGURATION_INFORMATION SystemConfig
;
798 PPORT_CONFIGURATION_INFORMATION PortConfig
;
799 PORT_CONFIGURATION_INFORMATION InitialPortConfig
;
800 CONFIGURATION_INFO ConfigInfo
;
801 ULONG DeviceExtensionSize
;
802 ULONG PortConfigSize
;
804 BOOLEAN DeviceFound
= FALSE
;
805 BOOLEAN FirstConfigCall
= TRUE
;
810 PCI_SLOT_NUMBER SlotNumber
;
812 PDEVICE_OBJECT PortDeviceObject
;
813 WCHAR NameBuffer
[80];
814 UNICODE_STRING DeviceName
;
815 WCHAR DosNameBuffer
[80];
816 UNICODE_STRING DosDeviceName
;
817 PIO_SCSI_CAPABILITIES PortCapabilities
;
822 PCM_RESOURCE_LIST ResourceList
;
826 DPRINT ("ScsiPortInitialize() called!\n");
828 /* Check params for validity */
829 if ((HwInitializationData
->HwInitialize
== NULL
) ||
830 (HwInitializationData
->HwStartIo
== NULL
) ||
831 (HwInitializationData
->HwInterrupt
== NULL
) ||
832 (HwInitializationData
->HwFindAdapter
== NULL
) ||
833 (HwInitializationData
->HwResetBus
== NULL
))
835 return STATUS_INVALID_PARAMETER
;
839 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
840 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
841 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
842 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
843 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
844 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
846 /* Obtain configuration information */
847 SystemConfig
= IoGetConfigurationInformation();
849 /* Zero the internal configuration info structure */
850 RtlZeroMemory(&ConfigInfo
, sizeof(CONFIGURATION_INFO
));
852 /* Allocate space for access ranges */
853 if (HwInitializationData
->NumberOfAccessRanges
)
855 ConfigInfo
.AccessRanges
=
856 ExAllocatePoolWithTag(PagedPool
,
857 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
), TAG_SCSIPORT
);
860 if (ConfigInfo
.AccessRanges
== NULL
)
861 return STATUS_INSUFFICIENT_RESOURCES
;
864 /* Open registry keys */
865 SpiInitOpenKeys(&ConfigInfo
, (PUNICODE_STRING
)Argument2
);
867 /* Last adapter number = not known */
868 ConfigInfo
.LastAdapterNumber
= SP_UNINITIALIZED_VALUE
;
870 /* Calculate sizes of DeviceExtension and PortConfig */
871 DeviceExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
872 HwInitializationData
->DeviceExtensionSize
;
874 MaxBus
= (HwInitializationData
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
875 DPRINT("MaxBus: %lu\n", MaxBus
);
879 /* Create a unicode device name */
881 L
"\\Device\\ScsiPort%lu",
882 SystemConfig
->ScsiPortCount
);
883 RtlInitUnicodeString(&DeviceName
, NameBuffer
);
885 DPRINT("Creating device: %wZ\n", &DeviceName
);
887 /* Create the port device */
888 Status
= IoCreateDevice(DriverObject
,
891 FILE_DEVICE_CONTROLLER
,
896 if (!NT_SUCCESS(Status
))
898 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
899 PortDeviceObject
= NULL
;
903 DPRINT ("Created device: %wZ (%p)\n", &DeviceName
, PortDeviceObject
);
905 /* Set the buffering strategy here... */
906 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
907 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
; /* FIXME: Is this really needed? */
909 /* Fill Device Extension */
910 DeviceExtension
= PortDeviceObject
->DeviceExtension
;
911 DeviceExtension
->Length
= DeviceExtensionSize
;
912 DeviceExtension
->DeviceObject
= PortDeviceObject
;
913 DeviceExtension
->PortNumber
= SystemConfig
->ScsiPortCount
;
915 /* Driver's routines... */
916 DeviceExtension
->HwInitialize
= HwInitializationData
->HwInitialize
;
917 DeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
918 DeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
919 DeviceExtension
->HwResetBus
= HwInitializationData
->HwResetBus
;
920 DeviceExtension
->HwDmaStarted
= HwInitializationData
->HwDmaStarted
;
922 /* Extensions sizes */
923 DeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
924 DeviceExtension
->LunExtensionSize
= HwInitializationData
->SpecificLuExtensionSize
;
925 DeviceExtension
->SrbExtensionSize
= HwInitializationData
->SrbExtensionSize
;
927 /* Round Srb extension size to the quadword */
928 DeviceExtension
->SrbExtensionSize
=
929 ~(sizeof(LONGLONG
) - 1) & (DeviceExtension
->SrbExtensionSize
+
930 sizeof(LONGLONG
) - 1);
932 /* Fill some numbers (bus count, lun count, etc) */
933 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
934 DeviceExtension
->RequestsNumber
= 16;
936 /* Initialize the spin lock in the controller extension */
937 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
938 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
940 /* Initialize the DPC object */
941 IoInitializeDpcRequest(PortDeviceObject
,
944 /* Initialize the device timer */
945 DeviceExtension
->TimerCount
= -1;
946 IoInitializeTimer(PortDeviceObject
,
950 /* Initialize miniport timer */
951 KeInitializeTimer(&DeviceExtension
->MiniportTimer
);
952 KeInitializeDpc(&DeviceExtension
->MiniportTimerDpc
,
958 Status
= SpiCreatePortConfig(DeviceExtension
,
959 HwInitializationData
,
964 if (!NT_SUCCESS(Status
))
967 /* Allocate and initialize port configuration info */
968 PortConfigSize
= (sizeof(PORT_CONFIGURATION_INFORMATION
) +
969 HwInitializationData
->NumberOfAccessRanges
*
970 sizeof(ACCESS_RANGE
) + 7) & ~7;
971 DeviceExtension
->PortConfig
= ExAllocatePoolWithTag(NonPagedPool
, PortConfigSize
, TAG_SCSIPORT
);
974 if (DeviceExtension
->PortConfig
== NULL
)
976 Status
= STATUS_INSUFFICIENT_RESOURCES
;
980 PortConfig
= DeviceExtension
->PortConfig
;
982 /* Copy information here */
983 RtlCopyMemory(PortConfig
,
985 sizeof(PORT_CONFIGURATION_INFORMATION
));
988 /* Copy extension sizes into the PortConfig */
989 PortConfig
->SpecificLuExtensionSize
= DeviceExtension
->LunExtensionSize
;
990 PortConfig
->SrbExtensionSize
= DeviceExtension
->SrbExtensionSize
;
992 /* Initialize Access ranges */
993 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
995 PortConfig
->AccessRanges
= (PVOID
)(PortConfig
+1);
997 /* Align to LONGLONG */
998 PortConfig
->AccessRanges
= (PVOID
)((ULONG
)(PortConfig
->AccessRanges
) + 7);
999 PortConfig
->AccessRanges
= (PVOID
)((ULONG
)(PortConfig
->AccessRanges
) & ~7);
1002 RtlCopyMemory(PortConfig
->AccessRanges
,
1003 ConfigInfo
.AccessRanges
,
1004 HwInitializationData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
1007 /* Search for matching PCI device */
1008 if ((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1009 (HwInitializationData
->VendorIdLength
> 0) &&
1010 (HwInitializationData
->VendorId
!= NULL
) &&
1011 (HwInitializationData
->DeviceIdLength
> 0) &&
1012 (HwInitializationData
->DeviceId
!= NULL
))
1014 PortConfig
->BusInterruptLevel
= 0;
1016 /* Get PCI device data */
1017 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1018 HwInitializationData
->VendorIdLength
,
1019 HwInitializationData
->VendorId
,
1020 HwInitializationData
->DeviceIdLength
,
1021 HwInitializationData
->DeviceId
);
1023 if (!SpiGetPciConfigData(DriverObject
,
1025 HwInitializationData
,
1031 /* Continue to the next bus, nothing here */
1032 ConfigInfo
.BusNumber
++;
1033 DeviceExtension
->PortConfig
= NULL
;
1034 ExFreePool(PortConfig
);
1036 goto CreatePortConfig
;
1039 if (!PortConfig
->BusInterruptLevel
)
1041 /* Bypass this slot, because no interrupt was assigned */
1042 DeviceExtension
->PortConfig
= NULL
;
1043 ExFreePool(PortConfig
);
1044 goto CreatePortConfig
;
1049 DPRINT("Non-pci bus\n");
1052 /* Note: HwFindAdapter is called once for each bus */
1054 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
1055 Result
= (HwInitializationData
->HwFindAdapter
)(&DeviceExtension
->MiniPortDeviceExtension
,
1057 0, /* BusInformation */
1058 ConfigInfo
.Parameter
, /* ArgumentString */
1062 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1063 Result
, (Again
) ? "True" : "False");
1065 /* Free MapRegisterBase, it's not needed anymore */
1066 if (DeviceExtension
->MapRegisterBase
!= NULL
)
1068 ExFreePool(DeviceExtension
->MapRegisterBase
);
1069 DeviceExtension
->MapRegisterBase
= NULL
;
1072 /* If result is nothing good... */
1073 if (Result
!= SP_RETURN_FOUND
)
1075 DPRINT("HwFindAdapter() Result: %lu\n", Result
);
1077 if (Result
== SP_RETURN_NOT_FOUND
)
1079 /* We can continue on the next bus */
1080 ConfigInfo
.BusNumber
++;
1083 DeviceExtension
->PortConfig
= NULL
;
1084 ExFreePool(PortConfig
);
1085 goto CreatePortConfig
;
1088 /* Otherwise, break */
1089 Status
= STATUS_INTERNAL_ERROR
;
1093 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1094 PortConfig
->BusInterruptVector
, PortConfig
->InitiatorBusId
[0]);
1096 /* If the SRB extension size was updated */
1097 if (!DeviceExtension
->NonCachedExtension
&&
1098 (PortConfig
->SrbExtensionSize
!= DeviceExtension
->SrbExtensionSize
))
1100 /* Set it (rounding to LONGLONG again) */
1101 DeviceExtension
->SrbExtensionSize
=
1102 (PortConfig
->SrbExtensionSize
+
1103 sizeof(LONGLONG
)) & ~(sizeof(LONGLONG
) - 1);
1106 /* The same with LUN extension size */
1107 if (PortConfig
->SpecificLuExtensionSize
!= DeviceExtension
->LunExtensionSize
)
1108 DeviceExtension
->LunExtensionSize
= PortConfig
->SpecificLuExtensionSize
;
1111 if (!((HwInitializationData
->AdapterInterfaceType
== PCIBus
) &&
1112 (HwInitializationData
->VendorIdLength
> 0) &&
1113 (HwInitializationData
->VendorId
!= NULL
) &&
1114 (HwInitializationData
->DeviceIdLength
> 0) &&
1115 (HwInitializationData
->DeviceId
!= NULL
)))
1117 /* Construct a resource list */
1118 ResourceList
= SpiConfigToResource(DeviceExtension
,
1123 UNICODE_STRING UnicodeString
;
1124 RtlInitUnicodeString(&UnicodeString
, L
"ScsiAdapter");
1125 DPRINT("Reporting resources\n");
1126 Status
= IoReportResourceUsage(&UnicodeString
,
1132 FIELD_OFFSET(CM_RESOURCE_LIST
,
1133 List
[0].PartialResourceList
.PartialDescriptors
) +
1134 ResourceList
->List
[0].PartialResourceList
.Count
1135 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
1138 ExFreePool(ResourceList
);
1140 /* In case of a failure or a conflict, break */
1141 if (Conflict
|| (!NT_SUCCESS(Status
)))
1144 Status
= STATUS_CONFLICTING_ADDRESSES
;
1150 /* Reset the Conflict var */
1153 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1154 if (PortConfig
->MaximumNumberOfTargets
> SCSI_MAXIMUM_TARGETS_PER_BUS
)
1155 DeviceExtension
->MaxTargedIds
= SCSI_MAXIMUM_TARGETS_PER_BUS
;
1157 DeviceExtension
->MaxTargedIds
= PortConfig
->MaximumNumberOfTargets
;
1159 DeviceExtension
->BusNum
= PortConfig
->NumberOfBuses
;
1160 DeviceExtension
->CachesData
= PortConfig
->CachesData
;
1161 DeviceExtension
->ReceiveEvent
= PortConfig
->ReceiveEvent
;
1162 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->TaggedQueuing
;
1163 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
;
1165 /* If something was disabled via registry - apply it */
1166 if (ConfigInfo
.DisableMultipleLun
)
1167 DeviceExtension
->MultipleReqsPerLun
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1169 if (ConfigInfo
.DisableTaggedQueueing
)
1170 DeviceExtension
->SupportsTaggedQueuing
= PortConfig
->MultipleRequestPerLu
= FALSE
;
1172 /* Check if we need to alloc SRB data */
1173 if (DeviceExtension
->SupportsTaggedQueuing
||
1174 DeviceExtension
->MultipleReqsPerLun
)
1176 DeviceExtension
->NeedSrbDataAlloc
= TRUE
;
1180 DeviceExtension
->NeedSrbDataAlloc
= FALSE
;
1183 /* Get a pointer to the port capabilities */
1184 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1186 /* Copy one field there */
1187 DeviceExtension
->MapBuffers
= PortConfig
->MapBuffers
;
1188 PortCapabilities
->AdapterUsesPio
= PortConfig
->MapBuffers
;
1190 if (DeviceExtension
->AdapterObject
== NULL
&&
1191 (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
|| PortConfig
->Master
))
1193 DPRINT1("DMA is not supported yet\n");
1197 if (DeviceExtension
->SrbExtensionBuffer
== NULL
&&
1198 (DeviceExtension
->SrbExtensionSize
!= 0 ||
1199 PortConfig
->AutoRequestSense
))
1201 DeviceExtension
->SupportsAutoSense
= PortConfig
->AutoRequestSense
;
1202 DeviceExtension
->NeedSrbExtensionAlloc
= TRUE
;
1204 //Status = STATUS_UNSUCCESFUL;
1205 /* TODO: Allocate common buffer */
1208 /* Check for failure */
1209 if (!NT_SUCCESS(Status
))
1213 /* Allocate SrbData, if needed */
1214 if (DeviceExtension
->NeedSrbDataAlloc
)
1217 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1219 if (DeviceExtension
->SrbDataCount
!= 0)
1220 Count
= DeviceExtension
->SrbDataCount
;
1222 Count
= DeviceExtension
->RequestsNumber
* 2;
1224 /* Allocate the data */
1225 SrbData
= ExAllocatePoolWithTag(NonPagedPool
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
), TAG_SCSIPORT
);
1226 if (SrbData
== NULL
)
1227 return STATUS_INSUFFICIENT_RESOURCES
;
1229 RtlZeroMemory(SrbData
, Count
* sizeof(SCSI_REQUEST_BLOCK_INFO
));
1231 DeviceExtension
->SrbInfo
= SrbData
;
1232 DeviceExtension
->FreeSrbInfo
= SrbData
;
1233 DeviceExtension
->SrbDataCount
= Count
;
1235 /* Link it to the list */
1238 SrbData
->Requests
.Flink
= (PLIST_ENTRY
)(SrbData
+ 1);
1243 /* Mark the last entry of the list */
1245 SrbData
->Requests
.Flink
= NULL
;
1248 /* Initialize port capabilities */
1249 PortCapabilities
= &DeviceExtension
->PortCapabilities
;
1250 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1251 PortCapabilities
->MaximumTransferLength
= PortConfig
->MaximumTransferLength
;
1253 if (PortConfig
->ReceiveEvent
)
1254 PortCapabilities
->SupportedAsynchronousEvents
|= SRBEV_SCSI_ASYNC_NOTIFICATION
;
1256 PortCapabilities
->TaggedQueuing
= DeviceExtension
->SupportsTaggedQueuing
;
1257 PortCapabilities
->AdapterScansDown
= PortConfig
->AdapterScansDown
;
1259 if (PortConfig
->AlignmentMask
> PortDeviceObject
->AlignmentRequirement
)
1260 PortDeviceObject
->AlignmentRequirement
= PortConfig
->AlignmentMask
;
1262 PortCapabilities
->AlignmentMask
= PortDeviceObject
->AlignmentRequirement
;
1264 if (PortCapabilities
->MaximumPhysicalPages
== 0)
1266 PortCapabilities
->MaximumPhysicalPages
=
1267 BYTES_TO_PAGES(PortCapabilities
->MaximumTransferLength
);
1269 /* Apply miniport's limits */
1270 if (PortConfig
->NumberOfPhysicalBreaks
< PortCapabilities
->MaximumPhysicalPages
)
1272 PortCapabilities
->MaximumPhysicalPages
= PortConfig
->NumberOfPhysicalBreaks
;
1276 /* Deal with interrupts */
1277 if (DeviceExtension
->HwInterrupt
== NULL
||
1278 (PortConfig
->BusInterruptLevel
== 0 && PortConfig
->BusInterruptVector
== 0))
1281 KeInitializeSpinLock(&DeviceExtension
->IrqLock
);
1283 /* FIXME: Use synchronization routine */
1284 ASSERT("No interrupts branch requires changes in synchronization\n");
1286 DeviceExtension
->Interrupt
= (PVOID
)DeviceExtension
;
1287 DPRINT("No interrupts\n");
1292 /* Are 2 interrupts needed? */
1293 if (DeviceExtension
->HwInterrupt
!= NULL
&&
1294 (PortConfig
->BusInterruptLevel
!= 0 || PortConfig
->BusInterruptVector
!= 0) &&
1295 (PortConfig
->BusInterruptLevel2
!= 0 || PortConfig
->BusInterruptVector2
!= 0))
1297 DPRINT1("2 interrupts requested! Not yet supported\n");
1302 BOOLEAN InterruptShareable
;
1304 /* No, only 1 interrupt */
1305 DPRINT("1 interrupt, IRQ is %d\n", PortConfig
->BusInterruptLevel
);
1307 DeviceExtension
->InterruptLevel
= PortConfig
->BusInterruptLevel
;
1309 /* Register an interrupt handler for this device */
1310 MappedIrq
= HalGetInterruptVector(PortConfig
->AdapterInterfaceType
,
1311 PortConfig
->SystemIoBusNumber
,
1312 PortConfig
->BusInterruptLevel
,
1313 PortConfig
->BusInterruptVector
,
1317 /* Determing IRQ sharability as usual */
1318 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1319 PortConfig
->InterruptMode
== LevelSensitive
)
1321 InterruptShareable
= TRUE
;
1325 InterruptShareable
= FALSE
;
1328 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
,
1329 (PKSERVICE_ROUTINE
)ScsiPortIsr
,
1335 PortConfig
->InterruptMode
,
1340 if (!(NT_SUCCESS(Status
)))
1342 DPRINT1("Could not connect interrupt %d\n",
1343 PortConfig
->BusInterruptVector
);
1344 DeviceExtension
->Interrupt
= NULL
;
1351 /* Save IoAddress (from access ranges) */
1352 if (HwInitializationData
->NumberOfAccessRanges
!= 0)
1354 DeviceExtension
->IoAddress
=
1355 ((*(PortConfig
->AccessRanges
))[0]).RangeStart
.LowPart
;
1357 DPRINT("Io Address %x\n", DeviceExtension
->IoAddress
);
1360 /* Set flag that it's allowed to disconnect during this command */
1361 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
1363 /* Initialize counter of active requests (-1 means there are none) */
1364 DeviceExtension
->ActiveRequestCounter
= -1;
1366 /* Analyze what we have about DMA */
1367 if (DeviceExtension
->AdapterObject
!= NULL
&&
1368 PortConfig
->Master
&&
1369 PortConfig
->NeedPhysicalAddresses
)
1371 DeviceExtension
->MapRegisters
= TRUE
;
1375 DeviceExtension
->MapRegisters
= FALSE
;
1378 /* Call HwInitialize at DISPATCH_LEVEL */
1379 KeRaiseIrql(DISPATCH_LEVEL
, &Dirql
);
1381 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1382 DeviceExtension
->HwInitialize
,
1383 DeviceExtension
->MiniPortDeviceExtension
))
1385 DPRINT1("HwInitialize() failed!\n");
1387 Status
= STATUS_ADAPTER_HARDWARE_ERROR
;
1391 /* Check if a notification is needed */
1392 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
1394 /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1395 ScsiPortDpcForIsr(NULL
,
1396 DeviceExtension
->DeviceObject
,
1401 /* Lower irql back to what it was */
1404 /* Start our timer */
1405 IoStartTimer(PortDeviceObject
);
1407 /* Initialize bus scanning information */
1408 DeviceExtension
->BusesConfig
= ExAllocatePoolWithTag(PagedPool
,
1409 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1410 + sizeof(ULONG
), TAG_SCSIPORT
);
1412 if (!DeviceExtension
->BusesConfig
)
1414 DPRINT1("Out of resources!\n");
1415 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1420 RtlZeroMemory(DeviceExtension
->BusesConfig
,
1421 sizeof(PSCSI_BUS_SCAN_INFO
) * DeviceExtension
->PortConfig
->NumberOfBuses
1424 /* Store number of buses there */
1425 DeviceExtension
->BusesConfig
->NumberOfBuses
= (UCHAR
)DeviceExtension
->BusNum
;
1427 /* Scan the adapter for devices */
1428 SpiScanAdapter(DeviceExtension
);
1430 /* Build the registry device map */
1431 SpiBuildDeviceMap(DeviceExtension
,
1432 (PUNICODE_STRING
)Argument2
);
1434 /* Create the dos device link */
1435 swprintf(DosNameBuffer
,
1437 SystemConfig
->ScsiPortCount
);
1438 RtlInitUnicodeString(&DosDeviceName
, DosNameBuffer
);
1439 IoCreateSymbolicLink(&DosDeviceName
, &DeviceName
);
1441 /* Increase the port count */
1442 SystemConfig
->ScsiPortCount
++;
1443 FirstConfigCall
= FALSE
;
1445 /* Increase adapter number and bus number respectively */
1446 ConfigInfo
.AdapterNumber
++;
1449 ConfigInfo
.BusNumber
++;
1451 DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber
, MaxBus
);
1456 /* Clean up the mess */
1457 SpiCleanupAfterInit(DeviceExtension
);
1459 /* Close registry keys */
1460 if (ConfigInfo
.ServiceKey
!= NULL
)
1461 ZwClose(ConfigInfo
.ServiceKey
);
1463 if (ConfigInfo
.DeviceKey
!= NULL
)
1464 ZwClose(ConfigInfo
.DeviceKey
);
1466 if (ConfigInfo
.BusKey
!= NULL
)
1467 ZwClose(ConfigInfo
.BusKey
);
1469 if (ConfigInfo
.AccessRanges
!= NULL
)
1470 ExFreePool(ConfigInfo
.AccessRanges
);
1472 if (ConfigInfo
.Parameter
!= NULL
)
1473 ExFreePool(ConfigInfo
.Parameter
);
1475 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %b!\n",
1476 Status
, DeviceFound
);
1478 return (DeviceFound
== FALSE
) ? Status
: STATUS_SUCCESS
;
1482 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1484 PSCSI_LUN_INFO LunInfo
;
1488 /* Check if we have something to clean up */
1489 if (DeviceExtension
== NULL
)
1492 /* Stop the timer and disconnect the interrupt */
1493 if (DeviceExtension
->Interrupt
)
1495 IoStopTimer(DeviceExtension
->DeviceObject
);
1496 IoDisconnectInterrupt(DeviceExtension
->Interrupt
);
1499 /* Delete ConfigInfo */
1500 if (DeviceExtension
->BusesConfig
)
1502 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
1504 if (!DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
])
1507 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
1511 /* Free current, but save pointer to the next one */
1512 Ptr
= LunInfo
->Next
;
1513 ExFreePool(LunInfo
);
1517 ExFreePool(DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]);
1520 ExFreePool(DeviceExtension
->BusesConfig
);
1523 /* Free PortConfig */
1524 if (DeviceExtension
->PortConfig
)
1525 ExFreePool(DeviceExtension
->PortConfig
);
1528 for(Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
1530 while (DeviceExtension
->LunExtensionList
[Lun
])
1532 Ptr
= DeviceExtension
->LunExtensionList
[Lun
];
1533 DeviceExtension
->LunExtensionList
[Lun
] = DeviceExtension
->LunExtensionList
[Lun
]->Next
;
1539 /* Free common buffer (if it exists) */
1540 if (DeviceExtension
->SrbExtensionBuffer
!= NULL
&&
1541 DeviceExtension
->CommonBufferSize
!= 0)
1543 if (!DeviceExtension
->AdapterObject
)
1545 ExFreePool(DeviceExtension
->SrbExtensionBuffer
);
1550 HalFreeCommonBuffer(DeviceExtension
->AdapterObject
,
1551 DeviceExtension
->CommonBufferSize
,
1552 DeviceExtension
->PhysicalCommonBuffer
,
1553 DeviceExtension
->SrbExtensionBuffer
,
1560 if (DeviceExtension
->SrbInfo
!= NULL
)
1561 ExFreePool(DeviceExtension
->SrbInfo
);
1563 /* Unmap mapped addresses */
1564 while (DeviceExtension
->MappedAddressList
!= NULL
)
1566 MmUnmapIoSpace(DeviceExtension
->MappedAddressList
->MappedAddress
,
1567 DeviceExtension
->MappedAddressList
->NumberOfBytes
);
1569 Ptr
= DeviceExtension
->MappedAddressList
;
1570 DeviceExtension
->MappedAddressList
= DeviceExtension
->MappedAddressList
->NextMappedAddress
;
1575 /* Finally delete the device object */
1576 DPRINT("Deleting device %p\n", DeviceExtension
->DeviceObject
);
1577 IoDeleteDevice(DeviceExtension
->DeviceObject
);
1586 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
1587 IN PSCSI_REQUEST_BLOCK Srb
,
1588 IN PVOID LogicalAddress
,
1591 DPRINT1("ScsiPortIoMapTransfer()\n");
1600 ScsiPortLogError(IN PVOID HwDeviceExtension
,
1601 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
1608 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1610 DPRINT1("ScsiPortLogError() called\n");
1612 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1613 SCSI_PORT_DEVICE_EXTENSION
,
1614 MiniPortDeviceExtension
);
1617 DPRINT("ScsiPortLogError() done\n");
1625 ScsiPortMoveMemory(OUT PVOID Destination
,
1629 RtlMoveMemory(Destination
,
1639 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
1640 IN PVOID HwDeviceExtension
,
1643 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1646 DPRINT("ScsiPortNotification() called\n");
1648 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
1649 SCSI_PORT_DEVICE_EXTENSION
,
1650 MiniPortDeviceExtension
);
1652 DPRINT("DeviceExtension %p\n", DeviceExtension
);
1654 va_start(ap
, HwDeviceExtension
);
1656 switch (NotificationType
)
1658 case RequestComplete
:
1660 PSCSI_REQUEST_BLOCK Srb
;
1661 PSCSI_REQUEST_BLOCK_INFO SrbData
;
1663 Srb
= (PSCSI_REQUEST_BLOCK
) va_arg (ap
, PSCSI_REQUEST_BLOCK
);
1665 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb
);
1667 /* Make sure Srb is allright */
1668 ASSERT(Srb
->SrbStatus
!= SRB_STATUS_PENDING
);
1669 ASSERT(Srb
->Function
!= SRB_FUNCTION_EXECUTE_SCSI
|| Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
|| Srb
->ScsiStatus
== SCSISTAT_GOOD
);
1671 if (!(Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
1673 /* It's been already completed */
1678 /* It's not active anymore */
1679 Srb
->SrbFlags
&= ~SRB_FLAGS_IS_ACTIVE
;
1681 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
1683 /* TODO: Treat it specially */
1688 /* Get the SRB data */
1689 SrbData
= SpiGetSrbData(DeviceExtension
,
1695 /* Make sure there are no CompletedRequests and there is a Srb */
1696 ASSERT(SrbData
->CompletedRequests
== NULL
&& SrbData
->Srb
!= NULL
);
1698 /* If it's a read/write request, make sure it has data inside it */
1699 if ((Srb
->SrbStatus
== SRB_STATUS_SUCCESS
) &&
1700 ((Srb
->Cdb
[0] == SCSIOP_READ
) || (Srb
->Cdb
[0] == SCSIOP_WRITE
)))
1702 ASSERT(Srb
->DataTransferLength
);
1705 SrbData
->CompletedRequests
= DeviceExtension
->InterruptData
.CompletedRequests
;
1706 DeviceExtension
->InterruptData
.CompletedRequests
= SrbData
;
1712 DPRINT("Notify: NextRequest\n");
1713 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NEXT_REQUEST_READY
;
1722 PathId
= (UCHAR
) va_arg (ap
, int);
1723 TargetId
= (UCHAR
) va_arg (ap
, int);
1724 Lun
= (UCHAR
) va_arg (ap
, int);
1726 DPRINT1 ("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1727 PathId
, TargetId
, Lun
);
1728 /* FIXME: Implement it! */
1731 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
1732 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT_LU;
1735 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
1740 DPRINT1("Notify: ResetDetected\n");
1745 DPRINT1 ("Unsupported notification %lu\n", NotificationType
);
1751 /* Request a DPC after we're done with the interrupt */
1752 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_NOTIFICATION_NEEDED
;
1760 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
1761 IN ULONG BusDataType
,
1762 IN ULONG SystemIoBusNumber
,
1763 IN ULONG SlotNumber
,
1768 DPRINT("ScsiPortSetBusDataByOffset()\n");
1769 return(HalSetBusDataByOffset(BusDataType
,
1782 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
1783 IN INTERFACE_TYPE BusType
,
1784 IN ULONG SystemIoBusNumber
,
1785 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
1786 IN ULONG NumberOfBytes
,
1787 IN BOOLEAN InIoSpace
)
1789 DPRINT("ScsiPortValidateRange()\n");
1794 /* INTERNAL FUNCTIONS ********************************************************/
1797 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData
,
1798 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor
,
1799 IN PPORT_CONFIGURATION_INFORMATION PortConfig
)
1801 PACCESS_RANGE AccessRange
;
1802 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData
;
1808 /* Loop through all entries */
1809 for (Index
= 0; Index
< ResourceDescriptor
->PartialResourceList
.Count
; Index
++)
1811 PartialData
= &ResourceDescriptor
->PartialResourceList
.PartialDescriptors
[Index
];
1813 switch (PartialData
->Type
)
1815 case CmResourceTypePort
:
1816 /* Copy access ranges */
1817 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
1819 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
1821 AccessRange
->RangeStart
= PartialData
->u
.Port
.Start
;
1822 AccessRange
->RangeLength
= PartialData
->u
.Port
.Length
;
1824 AccessRange
->RangeInMemory
= FALSE
;
1829 case CmResourceTypeMemory
:
1830 /* Copy access ranges */
1831 if (RangeNumber
< HwInitializationData
->NumberOfAccessRanges
)
1833 AccessRange
= &((*(PortConfig
->AccessRanges
))[RangeNumber
]);
1835 AccessRange
->RangeStart
= PartialData
->u
.Memory
.Start
;
1836 AccessRange
->RangeLength
= PartialData
->u
.Memory
.Length
;
1838 AccessRange
->RangeInMemory
= TRUE
;
1843 case CmResourceTypeInterrupt
:
1844 /* Copy interrupt data */
1845 PortConfig
->BusInterruptLevel
= PartialData
->u
.Interrupt
.Level
;
1846 PortConfig
->BusInterruptVector
= PartialData
->u
.Interrupt
.Vector
;
1848 /* Set interrupt mode accordingly to the resource */
1849 if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LATCHED
)
1851 PortConfig
->InterruptMode
= Latched
;
1853 else if (PartialData
->Flags
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
)
1855 PortConfig
->InterruptMode
= LevelSensitive
;
1859 case CmResourceTypeDma
:
1860 PortConfig
->DmaChannel
= PartialData
->u
.Dma
.Channel
;
1861 PortConfig
->DmaPort
= PartialData
->u
.Dma
.Port
;
1867 static PCM_RESOURCE_LIST
1868 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1869 PPORT_CONFIGURATION_INFORMATION PortConfig
)
1871 PCONFIGURATION_INFORMATION ConfigInfo
;
1872 PCM_RESOURCE_LIST ResourceList
;
1873 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
1874 PACCESS_RANGE AccessRange
;
1876 ULONG ListLength
= 0, i
, FullSize
;
1879 /* Get current Atdisk usage from the system */
1880 ConfigInfo
= IoGetConfigurationInformation();
1882 if (PortConfig
->AtdiskPrimaryClaimed
)
1883 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
1885 if (PortConfig
->AtdiskSecondaryClaimed
)
1886 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
1888 /* Do we use DMA? */
1889 if (PortConfig
->DmaChannel
!= SP_UNINITIALIZED_VALUE
||
1890 PortConfig
->DmaPort
!= SP_UNINITIALIZED_VALUE
)
1900 /* How many interrupts to we have? */
1901 if (DeviceExtension
->HwInterrupt
== NULL
||
1902 (PortConfig
->BusInterruptLevel
== 0 &&
1903 PortConfig
->BusInterruptVector
== 0))
1913 if (DeviceExtension
->HwInterrupt
!= NULL
&&
1914 (PortConfig
->BusInterruptLevel2
!= 0 ||
1915 PortConfig
->BusInterruptVector2
!= 0))
1921 /* How many access ranges do we use? */
1922 AccessRange
= &((*(PortConfig
->AccessRanges
))[0]);
1923 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
1925 if (AccessRange
->RangeLength
!= 0)
1931 /* Allocate the resource list, since we know its size now */
1932 FullSize
= sizeof(CM_RESOURCE_LIST
) + (ListLength
- 1) *
1933 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1935 ResourceList
= (PCM_RESOURCE_LIST
)ExAllocatePoolWithTag(PagedPool
, FullSize
, TAG_SCSIPORT
);
1941 RtlZeroMemory(ResourceList
, FullSize
);
1944 ResourceList
->Count
= 1;
1945 ResourceList
->List
[0].InterfaceType
= PortConfig
->AdapterInterfaceType
;
1946 ResourceList
->List
[0].BusNumber
= PortConfig
->SystemIoBusNumber
;
1947 ResourceList
->List
[0].PartialResourceList
.Count
= ListLength
;
1948 ResourceDescriptor
= ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
;
1950 /* Copy access ranges array over */
1951 for (i
= 0; i
< PortConfig
->NumberOfAccessRanges
; i
++)
1953 AccessRange
= &((*(PortConfig
->AccessRanges
))[i
]);
1955 /* If the range is empty - skip it */
1956 if (AccessRange
->RangeLength
== 0)
1959 if (AccessRange
->RangeInMemory
)
1961 ResourceDescriptor
->Type
= CmResourceTypeMemory
;
1962 ResourceDescriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
;
1966 ResourceDescriptor
->Type
= CmResourceTypePort
;
1967 ResourceDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
1970 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
1972 ResourceDescriptor
->u
.Memory
.Start
= AccessRange
->RangeStart
;
1973 ResourceDescriptor
->u
.Memory
.Length
= AccessRange
->RangeLength
;
1975 ResourceDescriptor
++;
1978 /* If we use interrupt(s), copy them */
1981 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
1983 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
1984 PortConfig
->InterruptMode
== LevelSensitive
)
1986 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
1987 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
1991 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
1992 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
1995 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
1996 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
1997 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
1999 ResourceDescriptor
++;
2003 /* Copy 2nd interrupt
2004 FIXME: Stupid code duplication, remove */
2007 ResourceDescriptor
->Type
= CmResourceTypeInterrupt
;
2009 if (PortConfig
->AdapterInterfaceType
== MicroChannel
||
2010 PortConfig
->InterruptMode
== LevelSensitive
)
2012 ResourceDescriptor
->ShareDisposition
= CmResourceShareShared
;
2013 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
2017 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2018 ResourceDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
2021 ResourceDescriptor
->u
.Interrupt
.Level
= PortConfig
->BusInterruptLevel
;
2022 ResourceDescriptor
->u
.Interrupt
.Vector
= PortConfig
->BusInterruptVector
;
2023 ResourceDescriptor
->u
.Interrupt
.Affinity
= 0;
2025 ResourceDescriptor
++;
2031 ResourceDescriptor
->Type
= CmResourceTypeDma
;
2032 ResourceDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
2033 ResourceDescriptor
->u
.Dma
.Channel
= PortConfig
->DmaChannel
;
2034 ResourceDescriptor
->u
.Dma
.Port
= PortConfig
->DmaPort
;
2035 ResourceDescriptor
->Flags
= 0;
2037 if (PortConfig
->DmaChannel
== SP_UNINITIALIZED_VALUE
)
2038 ResourceDescriptor
->u
.Dma
.Channel
= 0;
2040 if (PortConfig
->DmaPort
== SP_UNINITIALIZED_VALUE
)
2041 ResourceDescriptor
->u
.Dma
.Port
= 0;
2044 return ResourceList
;
2049 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject
,
2050 IN PDEVICE_OBJECT DeviceObject
,
2051 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
2052 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig
,
2053 IN PUNICODE_STRING RegistryPath
,
2055 IN OUT PPCI_SLOT_NUMBER NextSlotNumber
)
2057 PCI_COMMON_CONFIG PciConfig
;
2058 PCI_SLOT_NUMBER SlotNumber
;
2061 ULONG FunctionNumber
;
2062 CHAR VendorIdString
[8];
2063 CHAR DeviceIdString
[8];
2064 UNICODE_STRING UnicodeStr
;
2065 PCM_RESOURCE_LIST ResourceList
;
2068 DPRINT ("SpiGetPciConfiguration() called\n");
2070 RtlZeroMemory(&ResourceList
, sizeof(PCM_RESOURCE_LIST
));
2071 SlotNumber
.u
.AsULONG
= 0;
2073 /* Loop through all devices */
2074 for (DeviceNumber
= NextSlotNumber
->u
.bits
.DeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
2076 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
2078 /* Loop through all functions */
2079 for (FunctionNumber
= NextSlotNumber
->u
.bits
.FunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
2081 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
2083 /* Get PCI config bytes */
2084 DataSize
= HalGetBusData(PCIConfiguration
,
2086 SlotNumber
.u
.AsULONG
,
2090 /* There is nothing there */
2091 if (DataSize
< sizeof(ULONG
))
2094 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
2097 sprintf (VendorIdString
, "%04hx", PciConfig
.VendorID
);
2098 sprintf (DeviceIdString
, "%04hx", PciConfig
.DeviceID
);
2100 if (_strnicmp(VendorIdString
, HwInitializationData
->VendorId
, HwInitializationData
->VendorIdLength
) ||
2101 _strnicmp(DeviceIdString
, HwInitializationData
->DeviceId
, HwInitializationData
->DeviceIdLength
))
2103 /* It is not our device */
2107 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2111 SlotNumber
.u
.bits
.DeviceNumber
,
2112 SlotNumber
.u
.bits
.FunctionNumber
);
2115 RtlInitUnicodeString(&UnicodeStr
, L
"ScsiAdapter");
2116 Status
= HalAssignSlotResources(RegistryPath
,
2122 SlotNumber
.u
.AsULONG
,
2125 if (!NT_SUCCESS(Status
))
2128 /* Create configuration information */
2129 SpiResourceToConfig(HwInitializationData
,
2133 /* Free the resource list */
2134 ExFreePool(ResourceList
);
2136 /* Set dev & fn numbers */
2137 NextSlotNumber
->u
.bits
.DeviceNumber
= DeviceNumber
;
2138 NextSlotNumber
->u
.bits
.FunctionNumber
= FunctionNumber
+ 1;
2140 /* Save the slot number */
2141 PortConfig
->SlotNumber
= SlotNumber
.u
.AsULONG
;
2145 NextSlotNumber
->u
.bits
.FunctionNumber
= 0;
2148 NextSlotNumber
->u
.bits
.DeviceNumber
= 0;
2149 DPRINT ("No device found\n");
2156 /**********************************************************************
2158 * ScsiPortCreateClose
2161 * Answer requests for Create/Close calls: a null operation.
2168 * Pointer to a device object.
2171 * Pointer to an IRP.
2177 static NTSTATUS STDCALL
2178 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
2181 DPRINT("ScsiPortCreateClose()\n");
2183 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2184 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2186 return STATUS_SUCCESS
;
2190 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2193 PSCSI_LUN_INFO LunInfo
;
2194 PIO_STACK_LOCATION IrpStack
;
2195 PDEVICE_OBJECT DeviceObject
;
2196 PSCSI_REQUEST_BLOCK Srb
;
2199 /* Get pointer to the SRB */
2200 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2201 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
2203 /* Check if PathId matches number of buses */
2204 if (DeviceExtension
->BusesConfig
== NULL
||
2205 DeviceExtension
->BusesConfig
->NumberOfBuses
<= Srb
->PathId
)
2207 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2208 return STATUS_DEVICE_DOES_NOT_EXIST
;
2211 /* Get pointer to LunInfo */
2212 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Srb
->PathId
]->LunInfo
;
2214 /* Find matching LunInfo */
2217 if (LunInfo
->PathId
== Srb
->PathId
&&
2218 LunInfo
->TargetId
== Srb
->TargetId
&&
2219 LunInfo
->Lun
== Srb
->Lun
)
2224 LunInfo
= LunInfo
->Next
;
2227 /* If we couldn't find it - exit */
2228 if (LunInfo
== NULL
)
2229 return STATUS_DEVICE_DOES_NOT_EXIST
;
2233 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2235 /* Release, if asked */
2236 if (Srb
->Function
== SRB_FUNCTION_RELEASE_DEVICE
)
2238 LunInfo
->DeviceClaimed
= FALSE
;
2239 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2240 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2242 return STATUS_SUCCESS
;
2245 /* Attach, if not already claimed */
2246 if (LunInfo
->DeviceClaimed
)
2248 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2249 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
2251 return STATUS_DEVICE_BUSY
;
2254 /* Save the device object */
2255 DeviceObject
= LunInfo
->DeviceObject
;
2257 if (Srb
->Function
== SRB_FUNCTION_CLAIM_DEVICE
)
2258 LunInfo
->DeviceClaimed
= TRUE
;
2260 if (Srb
->Function
== SRB_FUNCTION_ATTACH_DEVICE
)
2261 LunInfo
->DeviceObject
= Srb
->DataBuffer
;
2263 Srb
->DataBuffer
= DeviceObject
;
2265 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2266 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2268 return STATUS_SUCCESS
;
2272 /**********************************************************************
2274 * ScsiPortDispatchScsi
2277 * Answer requests for SCSI calls
2283 * Standard dispatch arguments
2289 static NTSTATUS STDCALL
2290 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
2293 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2294 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2295 PIO_STACK_LOCATION Stack
;
2296 PSCSI_REQUEST_BLOCK Srb
;
2298 NTSTATUS Status
= STATUS_SUCCESS
;
2299 PIRP NextIrp
, IrpList
;
2300 PKDEVICE_QUEUE_ENTRY Entry
;
2302 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2305 DeviceExtension
= DeviceObject
->DeviceExtension
;
2306 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2308 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2311 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2312 Status
= STATUS_UNSUCCESSFUL
;
2314 Irp
->IoStatus
.Status
= Status
;
2315 Irp
->IoStatus
.Information
= 0;
2317 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2322 DPRINT("Srb: %p\n", Srb
);
2323 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
2324 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
2326 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2330 if (LunExtension
== NULL
)
2332 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2333 Status
= STATUS_NO_SUCH_DEVICE
;
2335 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2336 Irp
->IoStatus
.Status
= Status
;
2337 Irp
->IoStatus
.Information
= 0;
2339 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2344 switch (Srb
->Function
)
2346 case SRB_FUNCTION_SHUTDOWN
:
2347 case SRB_FUNCTION_FLUSH
:
2348 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2349 if (DeviceExtension
->CachesData
== FALSE
)
2351 /* All success here */
2352 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2353 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2354 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2355 return STATUS_SUCCESS
;
2357 /* Fall through to a usual execute operation */
2359 case SRB_FUNCTION_EXECUTE_SCSI
:
2360 case SRB_FUNCTION_IO_CONTROL
:
2361 /* Mark IRP as pending in all cases */
2362 IoMarkIrpPending(Irp
);
2364 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2366 /* Start IO directly */
2367 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2373 /* We need to be at DISPATCH_LEVEL */
2374 KeRaiseIrql (DISPATCH_LEVEL
, &oldIrql
);
2376 /* Insert IRP into the queue */
2377 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
2378 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
2381 /* It means the queue is empty, and we just start this request */
2382 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
2385 /* Back to the old IRQL */
2386 KeLowerIrql (oldIrql
);
2388 return STATUS_PENDING
;
2390 case SRB_FUNCTION_CLAIM_DEVICE
:
2391 case SRB_FUNCTION_ATTACH_DEVICE
:
2392 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2394 /* Reference device object and keep the device object */
2395 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2398 case SRB_FUNCTION_RELEASE_DEVICE
:
2399 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2401 /* Dereference device object and clear the device object */
2402 Status
= SpiHandleAttachRelease(DeviceExtension
, Irp
);
2405 case SRB_FUNCTION_RELEASE_QUEUE
:
2406 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2408 /* Guard with the spinlock */
2409 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2411 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2413 DPRINT("Queue is not frozen really\n");
2415 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2416 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2417 Status
= STATUS_SUCCESS
;
2422 /* Unfreeze the queue */
2423 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2425 if (LunExtension
->SrbInfo
.Srb
== NULL
)
2427 /* Get next logical unit request */
2428 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
2430 /* SpiGetNextRequestFromLun() releases the spinlock */
2435 DPRINT("The queue has active request\n");
2436 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2440 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2441 Status
= STATUS_SUCCESS
;
2444 case SRB_FUNCTION_FLUSH_QUEUE
:
2445 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2447 /* Guard with the spinlock */
2448 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
2450 if (!(LunExtension
->Flags
& LUNEX_FROZEN_QUEUE
))
2452 DPRINT("Queue is not frozen really\n");
2454 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2455 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2459 /* Make sure there is no active request */
2460 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
2462 /* Compile a list from the device queue */
2464 while ((Entry
= KeRemoveDeviceQueue(&LunExtension
->DeviceQueue
)) != NULL
)
2466 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
2469 Stack
= IoGetCurrentIrpStackLocation(NextIrp
);
2470 Srb
= Stack
->Parameters
.Scsi
.Srb
;
2473 Srb
->SrbStatus
= SRB_STATUS_REQUEST_FLUSHED
;
2474 NextIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2476 /* Add then to the list */
2477 NextIrp
->Tail
.Overlay
.ListEntry
.Flink
= (PLIST_ENTRY
)IrpList
;
2481 /* Unfreeze the queue */
2482 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
2484 /* Release the spinlock */
2485 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, Irql
);
2487 /* Complete those requests */
2491 IrpList
= (PIRP
)NextIrp
->Tail
.Overlay
.ListEntry
.Flink
;
2493 IoCompleteRequest(NextIrp
, 0);
2496 Status
= STATUS_SUCCESS
;
2500 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
2501 Status
= STATUS_NOT_IMPLEMENTED
;
2505 Irp
->IoStatus
.Status
= Status
;
2507 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2513 /**********************************************************************
2515 * ScsiPortDeviceControl
2518 * Answer requests for device control calls
2524 * Standard dispatch arguments
2530 static NTSTATUS STDCALL
2531 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
2534 PIO_STACK_LOCATION Stack
;
2535 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2536 NTSTATUS Status
= STATUS_SUCCESS
;;
2538 DPRINT("ScsiPortDeviceControl()\n");
2540 Irp
->IoStatus
.Information
= 0;
2542 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2543 DeviceExtension
= DeviceObject
->DeviceExtension
;
2545 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
2547 case IOCTL_SCSI_GET_DUMP_POINTERS
:
2549 PDUMP_POINTERS DumpPointers
;
2550 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2551 DumpPointers
= (PDUMP_POINTERS
)Irp
->AssociatedIrp
.SystemBuffer
;
2552 DumpPointers
->DeviceObject
= DeviceObject
;
2554 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
2558 case IOCTL_SCSI_GET_CAPABILITIES
:
2559 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2560 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
== sizeof(PVOID
))
2562 *((PVOID
*)Irp
->AssociatedIrp
.SystemBuffer
) = &DeviceExtension
->PortCapabilities
;
2564 Irp
->IoStatus
.Information
= sizeof(PVOID
);
2565 Status
= STATUS_SUCCESS
;
2569 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(IO_SCSI_CAPABILITIES
))
2571 Status
= STATUS_BUFFER_TOO_SMALL
;
2575 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2576 &DeviceExtension
->PortCapabilities
,
2577 sizeof(IO_SCSI_CAPABILITIES
));
2579 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
2580 Status
= STATUS_SUCCESS
;
2583 case IOCTL_SCSI_GET_INQUIRY_DATA
:
2584 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2586 /* Copy inquiry data to the port device extension */
2587 Status
= SpiGetInquiryData(DeviceExtension
, Irp
);
2591 DPRINT1(" unknown ioctl code: 0x%lX\n",
2592 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
2596 /* Complete the request with the given status */
2597 Irp
->IoStatus
.Status
= Status
;
2598 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2605 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
2608 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2609 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2610 PIO_STACK_LOCATION IrpStack
;
2611 PSCSI_REQUEST_BLOCK Srb
;
2612 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2615 DPRINT("ScsiPortStartIo() called!\n");
2617 DeviceExtension
= DeviceObject
->DeviceExtension
;
2618 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2620 DPRINT("DeviceExtension %p\n", DeviceExtension
);
2622 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2624 /* Apply "default" flags */
2625 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
2627 /* Get LUN extension */
2628 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2633 if (DeviceExtension
->NeedSrbDataAlloc
||
2634 DeviceExtension
->NeedSrbExtensionAlloc
)
2636 /* TODO: Implement */
2642 /* No allocations are needed */
2643 SrbInfo
= &LunExtension
->SrbInfo
;
2644 Srb
->SrbExtension
= NULL
;
2645 Srb
->QueueTag
= SP_UNTAGGED
;
2648 /* Increase sequence number of SRB */
2649 if (!SrbInfo
->SequenceNumber
)
2651 /* Increase global sequence number */
2652 DeviceExtension
->SequenceNumber
++;
2655 SrbInfo
->SequenceNumber
= DeviceExtension
->SequenceNumber
;
2658 /* Check some special SRBs */
2659 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2661 /* Some special handling */
2662 DPRINT1("Abort command! Unimplemented now\n");
2669 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
)
2671 // Store the MDL virtual address in SrbInfo structure
2672 SrbInfo
->DataOffset
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2674 if (DeviceExtension
->MapBuffers
&& Irp
->MdlAddress
)
2676 /* Calculate offset within DataBuffer */
2677 SrbInfo
->DataOffset
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
2678 Srb
->DataBuffer
= SrbInfo
->DataOffset
+
2679 (ULONG
)((PUCHAR
)Srb
->DataBuffer
-
2680 (PUCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2683 if (DeviceExtension
->AdapterObject
)
2686 KeFlushIoBuffers(Irp
->MdlAddress
,
2687 Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? TRUE
: FALSE
,
2691 if (DeviceExtension
->MapRegisters
)
2694 /* Calculate number of needed map registers */
2695 SrbInfo
->NumberOfMapRegisters
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
2697 Srb
->DataTransferLength
);
2699 /* Allocate adapter channel */
2700 Status
= IoAllocateAdapterChannel(DeviceExtension
->AdapterObject
,
2701 DeviceExtension
->DeviceObject
,
2702 SrbInfo
->NumberOfMapRegisters
,
2706 if (!NT_SUCCESS(Status
))
2708 DPRINT1("IoAllocateAdapterChannel() failed!\n");
2710 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
2711 ScsiPortNotification(RequestComplete
,
2712 DeviceExtension
+ 1,
2715 ScsiPortNotification(NextRequest
,
2716 DeviceExtension
+ 1);
2718 /* Request DPC for that work */
2719 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2722 /* Control goes to SpiAdapterControl */
2730 /* Increase active request counter */
2731 CounterResult
= InterlockedIncrement(&DeviceExtension
->ActiveRequestCounter
);
2733 if (CounterResult
== 0 &&
2734 DeviceExtension
->AdapterObject
!= NULL
&&
2735 !DeviceExtension
->MapRegisters
)
2738 IoAllocateAdapterChannel(
2739 DeviceExtension
->AdapterObject
,
2741 DeviceExtension
->PortCapabilities
.MaximumPhysicalPages
,
2742 ScsiPortAllocationRoutine
,
2748 /* TODO: DMA is not implemented yet */
2754 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
2756 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
2757 ScsiPortStartPacket
,
2760 DPRINT("Synchronization failed!\n");
2762 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
2763 Irp
->IoStatus
.Information
= 0;
2764 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
2766 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2769 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
2771 DPRINT("ScsiPortStartIo() done\n");
2775 static BOOLEAN STDCALL
2776 ScsiPortStartPacket(IN OUT PVOID Context
)
2778 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
2779 PIO_STACK_LOCATION IrpStack
;
2780 PSCSI_REQUEST_BLOCK Srb
;
2781 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)Context
;
2782 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2786 DPRINT("ScsiPortStartPacket() called\n");
2788 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
2790 IrpStack
= IoGetCurrentIrpStackLocation(DeviceObject
->CurrentIrp
);
2791 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
2793 /* Get LUN extension */
2794 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2799 /* Check if we are in a reset state */
2800 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
2802 /* Mark the we've got requests while being in the reset state */
2803 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET_REQUEST
;
2807 /* Set the time out value */
2808 DeviceExtension
->TimerCount
= Srb
->TimeOutValue
;
2811 DeviceExtension
->Flags
|= SCSI_PORT_DEVICE_BUSY
;
2813 if (LunExtension
->RequestTimeout
!= -1)
2815 /* Timer already active */
2820 /* It hasn't been initialized yet */
2821 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
2825 if (Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
)
2827 /* Handle bypass-requests */
2829 /* Is this an abort request? */
2830 if (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
)
2832 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
2834 /* Get pointer to SRB info structure */
2835 SrbInfo
= SpiGetSrbData(DeviceExtension
,
2841 /* Check if the request is still "active" */
2842 if (SrbInfo
== NULL
||
2843 SrbInfo
->Srb
== NULL
||
2844 !(SrbInfo
->Srb
->SrbFlags
& SRB_FLAGS_IS_ACTIVE
))
2846 /* It's not, mark it as active then */
2847 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
2850 LunExtension
->RequestTimeout
= -1;
2852 DPRINT("Request has been already completed, but abort request came\n");
2853 Srb
->SrbStatus
= SRB_STATUS_ABORT_FAILED
;
2855 /* Notify about request complete */
2856 ScsiPortNotification(RequestComplete
,
2857 DeviceExtension
->MiniPortDeviceExtension
,
2860 /* and about readiness for the next request */
2861 ScsiPortNotification(NextRequest
,
2862 DeviceExtension
->MiniPortDeviceExtension
);
2864 /* They might ask for some work, so queue the DPC for them */
2865 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2867 /* We're done in this branch */
2873 /* Add number of queued requests */
2874 LunExtension
->QueueCount
++;
2877 /* Bypass requests don't need request sense */
2878 LunExtension
->Flags
&= ~LUNEX_NEED_REQUEST_SENSE
;
2880 /* Is disconnect disabled for this request? */
2881 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
2883 /* Set the corresponding flag */
2884 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
2887 /* Transfer timeout value from Srb to Lun */
2888 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
2892 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
2894 /* It's a disconnect, so no more requests can go */
2895 DeviceExtension
->Flags
&= ~SCSI_PORT_DISCONNECT_ALLOWED
;
2898 LunExtension
->Flags
|= SCSI_PORT_LU_ACTIVE
;
2900 /* Increment queue count */
2901 LunExtension
->QueueCount
++;
2903 /* If it's tagged - special thing */
2904 if (Srb
->QueueTag
!= SP_UNTAGGED
)
2906 /* TODO: Support tagged requests */
2911 /* Mark this Srb active */
2912 Srb
->SrbFlags
|= SRB_FLAGS_IS_ACTIVE
;
2914 /* Call HwStartIo routine */
2915 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
2918 /* If notification is needed, then request a DPC */
2919 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
2920 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
2925 static PSCSI_PORT_LUN_EXTENSION
2926 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
2928 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2929 ULONG LunExtensionSize
;
2931 DPRINT("SpiAllocateLunExtension (%p)\n",
2934 /* Round LunExtensionSize first to the sizeof LONGLONG */
2935 LunExtensionSize
= (DeviceExtension
->LunExtensionSize
+
2936 sizeof(LONGLONG
) - 1) & ~(sizeof(LONGLONG
) - 1);
2938 LunExtensionSize
+= sizeof(SCSI_PORT_LUN_EXTENSION
);
2939 DPRINT("LunExtensionSize %lu\n", LunExtensionSize
);
2941 LunExtension
= ExAllocatePoolWithTag(NonPagedPool
, LunExtensionSize
, TAG_SCSIPORT
);
2942 if (LunExtension
== NULL
)
2944 DPRINT1("Out of resources!\n");
2948 /* Zero everything */
2949 RtlZeroMemory(LunExtension
, LunExtensionSize
);
2951 /* Initialize a list of requests */
2952 InitializeListHead(&LunExtension
->SrbInfo
.Requests
);
2954 /* Initialize timeout counter */
2955 LunExtension
->RequestTimeout
= -1;
2957 /* Set maximum queue size */
2958 LunExtension
->MaxQueueCount
= 256;
2960 /* Initialize request queue */
2961 KeInitializeDeviceQueue (&LunExtension
->DeviceQueue
);
2963 return LunExtension
;
2966 static PSCSI_PORT_LUN_EXTENSION
2967 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
2972 PSCSI_PORT_LUN_EXTENSION LunExtension
;
2974 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
2975 DeviceExtension
, PathId
, TargetId
, Lun
);
2977 /* Get appropriate list */
2978 LunExtension
= DeviceExtension
->LunExtensionList
[(TargetId
+ Lun
) % LUS_NUMBER
];
2980 /* Iterate it until we find what we need */
2981 while (LunExtension
)
2983 if (LunExtension
->TargetId
== TargetId
&&
2984 LunExtension
->Lun
== Lun
&&
2985 LunExtension
->PathId
== PathId
)
2987 /* All matches, return */
2988 return LunExtension
;
2991 /* Advance to the next item */
2992 LunExtension
= LunExtension
->Next
;
2995 /* We did not find anything */
2996 DPRINT("Nothing found\n");
3002 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject
,
3003 IN PSCSI_LUN_INFO LunInfo
)
3005 IO_STATUS_BLOCK IoStatusBlock
;
3006 PIO_STACK_LOCATION IrpStack
;
3011 PINQUIRYDATA InquiryBuffer
;
3012 PSENSE_DATA SenseBuffer
;
3013 BOOLEAN KeepTrying
= TRUE
;
3014 ULONG RetryCount
= 0;
3015 SCSI_REQUEST_BLOCK Srb
;
3017 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3018 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
3020 DPRINT ("SpiSendInquiry() called\n");
3022 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
3024 InquiryBuffer
= ExAllocatePoolWithTag (NonPagedPool
, INQUIRYDATABUFFERSIZE
, TAG_SCSIPORT
);
3025 if (InquiryBuffer
== NULL
)
3026 return STATUS_INSUFFICIENT_RESOURCES
;
3028 SenseBuffer
= ExAllocatePoolWithTag (NonPagedPool
, SENSE_BUFFER_SIZE
, TAG_SCSIPORT
);
3029 if (SenseBuffer
== NULL
)
3031 ExFreePool(InquiryBuffer
);
3032 return STATUS_INSUFFICIENT_RESOURCES
;
3037 /* Initialize event for waiting */
3038 KeInitializeEvent(&Event
,
3043 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN
,
3048 INQUIRYDATABUFFERSIZE
,
3054 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3055 return STATUS_INSUFFICIENT_RESOURCES
;
3059 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3061 Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
3062 Srb
.OriginalRequest
= Irp
;
3063 Srb
.PathId
= LunInfo
->PathId
;
3064 Srb
.TargetId
= LunInfo
->TargetId
;
3065 Srb
.Lun
= LunInfo
->Lun
;
3066 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3067 Srb
.SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3068 Srb
.TimeOutValue
= 4;
3071 Srb
.SenseInfoBuffer
= SenseBuffer
;
3072 Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3074 Srb
.DataBuffer
= InquiryBuffer
;
3075 Srb
.DataTransferLength
= INQUIRYDATABUFFERSIZE
;
3077 /* Attach Srb to the Irp */
3078 IrpStack
= IoGetNextIrpStackLocation (Irp
);
3079 IrpStack
->Parameters
.Scsi
.Srb
= &Srb
;
3082 Cdb
= (PCDB
)Srb
.Cdb
;
3083 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_INQUIRY
;
3084 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= LunInfo
->Lun
;
3085 Cdb
->CDB6INQUIRY
.AllocationLength
= INQUIRYDATABUFFERSIZE
;
3087 /* Call the driver */
3088 Status
= IoCallDriver(DeviceObject
, Irp
);
3090 /* Wait for it to complete */
3091 if (Status
== STATUS_PENDING
)
3093 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3094 KeWaitForSingleObject(&Event
,
3099 Status
= IoStatusBlock
.Status
;
3102 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status
);
3104 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_SUCCESS
)
3106 /* All fine, copy data over */
3107 RtlCopyMemory(LunInfo
->InquiryData
,
3109 INQUIRYDATABUFFERSIZE
);
3111 Status
= STATUS_SUCCESS
;
3116 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb
.SrbStatus
);
3117 /* Check if the queue is frozen */
3118 if (Srb
.SrbStatus
& SRB_STATUS_QUEUE_FROZEN
)
3120 /* Something weird happened, deal with it (unfreeze the queue) */
3123 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb
.TargetId
);
3125 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3130 /* Clear frozen flag */
3131 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
3133 /* Acquire the spinlock */
3134 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
3136 /* Process the request */
3137 SpiGetNextRequestFromLun(DeviceObject
->DeviceExtension
, LunExtension
);
3139 /* SpiGetNextRequestFromLun() releases the spinlock,
3140 so we just lower irql back to what it was before */
3144 /* Check if data overrun happened */
3145 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
3147 DPRINT("Data overrun at TargetId %d\n", LunInfo
->TargetId
);
3148 /* Nothing dramatic, just copy data, but limiting the size */
3149 RtlCopyMemory(LunInfo
->InquiryData
,
3151 (Srb
.DataTransferLength
> INQUIRYDATABUFFERSIZE
) ?
3152 INQUIRYDATABUFFERSIZE
: Srb
.DataTransferLength
);
3154 Status
= STATUS_SUCCESS
;
3157 else if ((Srb
.SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3158 SenseBuffer
->SenseKey
== SCSI_SENSE_ILLEGAL_REQUEST
)
3160 /* LUN is not valid, but some device responds there.
3161 Mark it as invalid anyway */
3163 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3168 /* Retry a couple of times if no timeout happened */
3169 if ((RetryCount
< 2) &&
3170 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_NO_DEVICE
) &&
3171 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_SELECTION_TIMEOUT
))
3178 /* That's all, go to exit */
3181 /* Set status according to SRB status */
3182 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_FUNCTION
||
3183 SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH
)
3185 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3189 Status
= STATUS_IO_DEVICE_ERROR
;
3197 ExFreePool(InquiryBuffer
);
3198 ExFreePool(SenseBuffer
);
3200 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status
);
3206 /* Scans all SCSI buses */
3208 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
3210 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3214 PSCSI_BUS_SCAN_INFO BusScanInfo
;
3215 PSCSI_LUN_INFO LastLunInfo
, LunInfo
, LunInfoExists
;
3216 BOOLEAN DeviceExists
;
3221 DPRINT("SpiScanAdapter() called\n");
3223 /* Scan all buses */
3224 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
3226 DPRINT(" Scanning bus %d\n", Bus
);
3229 /* Get pointer to the scan information */
3230 BusScanInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
];
3234 /* Find the last LUN info in the list */
3235 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3236 LastLunInfo
= LunInfo
;
3238 while (LunInfo
!= NULL
)
3240 LastLunInfo
= LunInfo
;
3241 LunInfo
= LunInfo
->Next
;
3246 /* We need to allocate this buffer */
3247 BusScanInfo
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_BUS_SCAN_INFO
), TAG_SCSIPORT
);
3251 DPRINT1("Out of resources!\n");
3255 /* Store the pointer in the BusScanInfo array */
3256 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
] = BusScanInfo
;
3258 /* Fill this struct (length and bus ids for now) */
3259 BusScanInfo
->Length
= sizeof(SCSI_BUS_SCAN_INFO
);
3260 BusScanInfo
->LogicalUnitsCount
= 0;
3261 BusScanInfo
->BusIdentifier
= DeviceExtension
->PortConfig
->InitiatorBusId
[Bus
];
3262 BusScanInfo
->LunInfo
= NULL
;
3264 /* Set pointer to the last LUN info to NULL */
3268 /* Create LUN information structure */
3269 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3271 if (LunInfo
== NULL
)
3273 DPRINT1("Out of resources!\n");
3277 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3279 /* Create LunExtension */
3280 LunExtension
= SpiAllocateLunExtension (DeviceExtension
);
3282 /* And send INQUIRY to every target */
3283 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
3285 /* TODO: Support scan bottom-up */
3287 /* Skip if it's the same address */
3288 if (Target
== BusScanInfo
->BusIdentifier
)
3291 /* Try to find an existing device here */
3292 DeviceExists
= FALSE
;
3293 LunInfoExists
= BusScanInfo
->LunInfo
;
3295 /* Find matching address on this bus */
3296 while (LunInfoExists
)
3298 if (LunInfoExists
->TargetId
== Target
)
3300 DeviceExists
= TRUE
;
3304 /* Advance to the next one */
3305 LunInfoExists
= LunInfoExists
->Next
;
3308 /* No need to bother rescanning, since we already did that before */
3312 /* Scan all logical units */
3313 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
3318 /* Add extension to the list */
3319 Hint
= (Target
+ Lun
) % LUS_NUMBER
;
3320 LunExtension
->Next
= DeviceExtension
->LunExtensionList
[Hint
];
3321 DeviceExtension
->LunExtensionList
[Hint
] = LunExtension
;
3323 /* Fill Path, Target, Lun fields */
3324 LunExtension
->PathId
= LunInfo
->PathId
= (UCHAR
)Bus
;
3325 LunExtension
->TargetId
= LunInfo
->TargetId
= (UCHAR
) Target
;
3326 LunExtension
->Lun
= LunInfo
->Lun
= (UCHAR
)Lun
;
3328 /* Set flag to prevent race conditions */
3329 LunExtension
->Flags
|= SCSI_PORT_SCAN_IN_PROGRESS
;
3331 /* Zero LU extension contents */
3332 if (DeviceExtension
->LunExtensionSize
)
3334 RtlZeroMemory(LunExtension
+ 1,
3335 DeviceExtension
->LunExtensionSize
);
3338 /* Finally send the inquiry command */
3339 Status
= SpiSendInquiry(DeviceExtension
->DeviceObject
, LunInfo
);
3341 if (NT_SUCCESS(Status
))
3343 /* Let's see if we really found a device */
3344 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3346 /* Check if this device is unsupported */
3347 if (InquiryData
->DeviceTypeQualifier
== DEVICE_QUALIFIER_NOT_SUPPORTED
)
3349 DeviceExtension
->LunExtensionList
[Hint
] =
3350 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3355 /* Clear the "in scan" flag */
3356 LunExtension
->Flags
&= ~SCSI_PORT_SCAN_IN_PROGRESS
;
3358 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3359 InquiryData
->DeviceType
, Bus
, Target
, Lun
);
3361 /* Add this info to the linked list */
3362 LunInfo
->Next
= NULL
;
3364 LastLunInfo
->Next
= LunInfo
;
3366 BusScanInfo
->LunInfo
= LunInfo
;
3368 /* Store the last LUN info */
3369 LastLunInfo
= LunInfo
;
3371 /* Store DeviceObject */
3372 LunInfo
->DeviceObject
= DeviceExtension
->DeviceObject
;
3374 /* Allocate another buffer */
3375 LunInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(SCSI_LUN_INFO
), TAG_SCSIPORT
);
3379 DPRINT1("Out of resources!\n");
3383 RtlZeroMemory(LunInfo
, sizeof(SCSI_LUN_INFO
));
3385 /* Create a new LU extension */
3386 LunExtension
= SpiAllocateLunExtension(DeviceExtension
);
3392 /* Remove this LUN from the list */
3393 DeviceExtension
->LunExtensionList
[Hint
] =
3394 DeviceExtension
->LunExtensionList
[Hint
]->Next
;
3396 /* Decide whether we are continuing or not */
3397 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
3405 /* Free allocated buffers */
3407 ExFreePool(LunExtension
);
3410 ExFreePool(LunInfo
);
3412 /* Sum what we found */
3413 BusScanInfo
->LogicalUnitsCount
+= (UCHAR
) DevicesFound
;
3414 DPRINT(" Found %d devices on bus %d\n", DevicesFound
, Bus
);
3417 DPRINT ("SpiScanAdapter() done\n");
3422 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3425 ULONG InquiryDataSize
;
3426 PSCSI_LUN_INFO LunInfo
;
3427 ULONG BusCount
, LunCount
, Length
;
3428 PIO_STACK_LOCATION IrpStack
;
3429 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
3430 PSCSI_INQUIRY_DATA InquiryData
;
3431 PSCSI_BUS_DATA BusData
;
3435 DPRINT("SpiGetInquiryData() called\n");
3437 /* Get pointer to the buffer */
3438 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3439 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3441 /* Initialize bus and LUN counters */
3442 BusCount
= DeviceExtension
->BusesConfig
->NumberOfBuses
;
3445 /* Calculate total number of LUNs */
3446 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3447 LunCount
+= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3449 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
3451 ((sizeof(SCSI_INQUIRY_DATA
) - 1 + INQUIRYDATABUFFERSIZE
+
3452 sizeof(ULONG
) - 1) & ~(sizeof(ULONG
) - 1));
3454 /* Calculate data size */
3455 Length
= sizeof(SCSI_ADAPTER_BUS_INFO
) + (BusCount
- 1) *
3456 sizeof(SCSI_BUS_DATA
);
3458 Length
+= InquiryDataSize
* LunCount
;
3460 /* Check, if all data is going to fit into provided buffer */
3461 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< Length
)
3463 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3464 return STATUS_BUFFER_TOO_SMALL
;
3467 /* Store data size in the IRP */
3468 Irp
->IoStatus
.Information
= Length
;
3470 DPRINT("Data size: %lu\n", Length
);
3472 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
3474 AdapterBusInfo
->NumberOfBuses
= (UCHAR
)BusCount
;
3476 /* Point InquiryData to the corresponding place inside Buffer */
3477 InquiryData
= (PSCSI_INQUIRY_DATA
)(Buffer
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
3478 (BusCount
- 1) * sizeof(SCSI_BUS_DATA
));
3481 for (Bus
= 0; Bus
< BusCount
; Bus
++)
3483 BusData
= &AdapterBusInfo
->BusData
[Bus
];
3485 /* Calculate and save an offset of the inquiry data */
3486 BusData
->InquiryDataOffset
= (PUCHAR
)InquiryData
- Buffer
;
3488 /* Get a pointer to the LUN information structure */
3489 LunInfo
= DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LunInfo
;
3491 /* Store Initiator Bus Id */
3492 BusData
->InitiatorBusId
=
3493 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->BusIdentifier
;
3495 /* Store LUN count */
3496 BusData
->NumberOfLogicalUnits
=
3497 DeviceExtension
->BusesConfig
->BusScanInfo
[Bus
]->LogicalUnitsCount
;
3500 while (LunInfo
!= NULL
)
3502 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
3503 Bus
, LunInfo
->TargetId
, LunInfo
->Lun
);
3505 /* Fill InquiryData with values */
3506 InquiryData
->PathId
= LunInfo
->PathId
;
3507 InquiryData
->TargetId
= LunInfo
->TargetId
;
3508 InquiryData
->Lun
= LunInfo
->Lun
;
3509 InquiryData
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
3510 InquiryData
->DeviceClaimed
= LunInfo
->DeviceClaimed
;
3511 InquiryData
->NextInquiryDataOffset
=
3512 (PUCHAR
)InquiryData
+ InquiryDataSize
- Buffer
;
3514 /* Copy data in it */
3515 RtlCopyMemory(InquiryData
->InquiryData
,
3516 LunInfo
->InquiryData
,
3517 INQUIRYDATABUFFERSIZE
);
3519 /* Move to the next LUN */
3520 LunInfo
= LunInfo
->Next
;
3521 InquiryData
= (PSCSI_INQUIRY_DATA
) ((PCHAR
)InquiryData
+ InquiryDataSize
);
3524 /* Either mark the end, or set offset to 0 */
3525 if (BusData
->NumberOfLogicalUnits
!= 0)
3526 ((PSCSI_INQUIRY_DATA
) ((PCHAR
) InquiryData
- InquiryDataSize
))->NextInquiryDataOffset
= 0;
3528 BusData
->InquiryDataOffset
= 0;
3531 /* Finish with success */
3532 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3533 return STATUS_SUCCESS
;
3536 static PSCSI_REQUEST_BLOCK_INFO
3537 SpiGetSrbData(IN PVOID DeviceExtension
,
3543 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3545 if (QueueTag
== SP_UNTAGGED
)
3547 /* Untagged request, get LU and return pointer to SrbInfo */
3548 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3553 /* Return NULL in case of error */
3557 /* Return the pointer to SrbInfo */
3558 return &LunExtension
->SrbInfo
;
3562 /* TODO: Implement when we have it */
3569 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3570 IN PSCSI_REQUEST_BLOCK InitialSrb
)
3572 PSCSI_REQUEST_BLOCK Srb
;
3575 PIO_STACK_LOCATION IrpStack
;
3576 LARGE_INTEGER LargeInt
;
3579 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb
);
3582 Srb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
) + sizeof(PVOID
), TAG_SCSIPORT
);
3583 RtlZeroMemory(Srb
, sizeof(SCSI_REQUEST_BLOCK
));
3586 LargeInt
.QuadPart
= (LONGLONG
) 1;
3587 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_READ
,
3588 DeviceExtension
->DeviceObject
,
3589 InitialSrb
->SenseInfoBuffer
,
3590 InitialSrb
->SenseInfoBufferLength
,
3594 IoSetCompletionRoutine(Irp
,
3595 (PIO_COMPLETION_ROUTINE
)SpiCompletionRoutine
,
3601 IrpStack
= IoGetNextIrpStackLocation(Irp
);
3602 IrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3604 /* Put Srb address into Irp... */
3605 IrpStack
->Parameters
.Others
.Argument1
= (PVOID
)Srb
;
3607 /* ...and vice versa */
3608 Srb
->OriginalRequest
= Irp
;
3611 Ptr
= (PVOID
*)(Srb
+1);
3614 /* Build CDB for REQUEST SENSE */
3616 Cdb
= (PCDB
)Srb
->Cdb
;
3618 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
3619 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= 0;
3620 Cdb
->CDB6INQUIRY
.Reserved1
= 0;
3621 Cdb
->CDB6INQUIRY
.PageCode
= 0;
3622 Cdb
->CDB6INQUIRY
.IReserved
= 0;
3623 Cdb
->CDB6INQUIRY
.AllocationLength
= (UCHAR
)InitialSrb
->SenseInfoBufferLength
;
3624 Cdb
->CDB6INQUIRY
.Control
= 0;
3627 Srb
->TargetId
= InitialSrb
->TargetId
;
3628 Srb
->Lun
= InitialSrb
->Lun
;
3629 Srb
->PathId
= InitialSrb
->PathId
;
3631 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3632 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
3634 /* Timeout will be 2 seconds */
3635 Srb
->TimeOutValue
= 2;
3637 /* No auto request sense */
3638 Srb
->SenseInfoBufferLength
= 0;
3639 Srb
->SenseInfoBuffer
= NULL
;
3641 /* Set necessary flags */
3642 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_BYPASS_FROZEN_QUEUE
|
3643 SRB_FLAGS_DISABLE_DISCONNECT
;
3645 /* Transfer disable synch transfer flag */
3646 if (InitialSrb
->SrbFlags
& SRB_FLAGS_DISABLE_SYNCH_TRANSFER
)
3647 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3649 Srb
->DataBuffer
= InitialSrb
->SenseInfoBuffer
;
3651 /* Fill the transfer length */
3652 Srb
->DataTransferLength
= InitialSrb
->SenseInfoBufferLength
;
3654 /* Clear statuses */
3655 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
3658 /* Call the driver */
3659 (VOID
)IoCallDriver(DeviceExtension
->DeviceObject
, Irp
);
3661 DPRINT("SpiSendRequestSense() done\n");
3668 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
3669 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo
,
3670 OUT PBOOLEAN NeedToCallStartIo
)
3672 PSCSI_REQUEST_BLOCK Srb
;
3673 PSCSI_PORT_LUN_EXTENSION LunExtension
;
3676 ULONG SequenceNumber
;
3679 Irp
= Srb
->OriginalRequest
;
3681 /* Get Lun extension */
3682 LunExtension
= SpiGetLunExtension(DeviceExtension
,
3687 if (Srb
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
&&
3688 DeviceExtension
->MapBuffers
&&
3691 /* MDL is shared if transfer is broken into smaller parts */
3692 Srb
->DataBuffer
= (PCCHAR
)MmGetMdlVirtualAddress(Irp
->MdlAddress
) +
3693 ((PCCHAR
)Srb
->DataBuffer
- SrbInfo
->DataOffset
);
3695 /* In case of data going in, flush the buffers */
3696 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
3698 KeFlushIoBuffers(Irp
->MdlAddress
,
3705 /* Flush adapter if needed */
3706 if (SrbInfo
->BaseOfMapRegister
)
3708 /* TODO: Implement */
3712 /* Clear the request */
3713 SrbInfo
->Srb
= NULL
;
3715 /* If disconnect is disabled... */
3716 if (Srb
->SrbFlags
& SRB_FLAGS_DISABLE_DISCONNECT
)
3718 /* Acquire the spinlock since we mess with flags */
3719 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3721 /* Set corresponding flag */
3722 DeviceExtension
->Flags
|= SCSI_PORT_DISCONNECT_ALLOWED
;
3724 /* Clear the timer if needed */
3725 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
))
3726 DeviceExtension
->TimerCount
= -1;
3728 /* Spinlock is not needed anymore */
3729 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3731 if (!(DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
) &&
3732 !(DeviceExtension
->Flags
& SCSI_PORT_DEVICE_BUSY
) &&
3733 !(*NeedToCallStartIo
))
3735 /* We're not busy, but we have a request pending */
3736 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
3740 /* Scatter/gather */
3741 if (Srb
->SrbFlags
& SRB_FLAGS_SGLIST_FROM_POOL
)
3743 /* TODO: Implement */
3747 /* Acquire spinlock (we're freeing SrbExtension) */
3748 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
3750 /* Free it (if needed) */
3751 if (Srb
->SrbExtension
)
3753 if (Srb
->SenseInfoBuffer
!= NULL
&& DeviceExtension
->SupportsAutoSense
)
3755 ASSERT(Srb
->SenseInfoBuffer
== NULL
|| SrbInfo
->SaveSenseRequest
!= NULL
);
3757 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)
3759 /* Copy sense data to the buffer */
3760 RtlCopyMemory(SrbInfo
->SaveSenseRequest
,
3761 Srb
->SenseInfoBuffer
,
3762 Srb
->SenseInfoBufferLength
);
3765 /* And restore the pointer */
3766 Srb
->SenseInfoBuffer
= SrbInfo
->SaveSenseRequest
;
3769 /* Put it into the free srb extensions list */
3770 *((PVOID
*)Srb
->SrbExtension
) = DeviceExtension
->FreeSrbExtensions
;
3771 DeviceExtension
->FreeSrbExtensions
= Srb
->SrbExtension
;
3774 /* Save transfer length in the IRP */
3775 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
3777 SequenceNumber
= SrbInfo
->SequenceNumber
;
3778 SrbInfo
->SequenceNumber
= 0;
3780 /* Decrement the queue count */
3781 LunExtension
->QueueCount
--;
3783 /* Free Srb, if needed*/
3784 if (Srb
->QueueTag
!= SP_UNTAGGED
)
3786 /* Put it into the free list */
3787 SrbInfo
->Requests
.Blink
= NULL
;
3788 SrbInfo
->Requests
.Flink
= (PLIST_ENTRY
)DeviceExtension
->FreeSrbInfo
;
3789 DeviceExtension
->FreeSrbInfo
= SrbInfo
;
3792 /* SrbInfo is not used anymore */
3795 if (DeviceExtension
->Flags
& SCSI_PORT_REQUEST_PENDING
)
3797 /* Clear the flag */
3798 DeviceExtension
->Flags
&= ~SCSI_PORT_REQUEST_PENDING
;
3800 /* Note the caller about StartIo */
3801 *NeedToCallStartIo
= TRUE
;
3804 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
3806 /* Start the packet */
3807 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3809 if (!(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
) &&
3810 LunExtension
->RequestTimeout
== -1)
3812 /* Start the next packet */
3813 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
3817 /* Release the spinlock */
3818 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3821 DPRINT("IoCompleting request IRP 0x%08X\n", Irp
);
3823 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
3825 /* Decrement number of active requests, and analyze the result */
3826 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
3829 !DeviceExtension
->MapRegisters
&&
3830 DeviceExtension
->AdapterObject
!= NULL
)
3832 /* Nullify map registers */
3833 DeviceExtension
->MapRegisterBase
= NULL
;
3834 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
3837 /* Exit, we're done */
3841 /* Decrement number of active requests, and analyze the result */
3842 Result
= InterlockedDecrement(&DeviceExtension
->ActiveRequestCounter
);
3845 !DeviceExtension
->MapRegisters
&&
3846 DeviceExtension
->AdapterObject
!= NULL
)
3848 /* Result is negative, so this is a slave, free map registers */
3849 DeviceExtension
->MapRegisterBase
= NULL
;
3850 IoFreeAdapterChannel(DeviceExtension
->AdapterObject
);
3853 /* Convert status */
3854 Irp
->IoStatus
.Status
= SpiStatusSrbToNt(Srb
->SrbStatus
);
3856 /* It's not a bypass, it's busy or the queue is full? */
3857 if ((Srb
->ScsiStatus
== SCSISTAT_BUSY
||
3858 Srb
->SrbStatus
== SRB_STATUS_BUSY
||
3859 Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
) &&
3860 !(Srb
->SrbFlags
& SRB_FLAGS_BYPASS_FROZEN_QUEUE
))
3863 DPRINT("Busy SRB status %x\n", Srb
->SrbStatus
);
3865 /* Requeu, if needed */
3866 if (LunExtension
->Flags
& (LUNEX_FROZEN_QUEUE
| LUNEX_BUSY
))
3868 DPRINT("it's being requeued\n");
3870 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
3871 Srb
->ScsiStatus
= 0;
3873 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
3874 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
3877 /* It's a big f.ck up if we got here */
3878 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
3879 Srb
->ScsiStatus
= SCSISTAT_BUSY
;
3885 /* Release the spinlock */
3886 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3889 else if (LunExtension
->AttemptCount
++ < 20)
3891 /* LUN is still busy */
3892 Srb
->ScsiStatus
= 0;
3893 Srb
->SrbStatus
= SRB_STATUS_PENDING
;
3895 LunExtension
->BusyRequest
= Irp
;
3896 LunExtension
->Flags
|= LUNEX_BUSY
;
3898 /* Release the spinlock */
3899 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3904 /* Freeze the queue*/
3905 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
3906 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
3908 /* "Unfull" the queue */
3909 LunExtension
->Flags
&= ~LUNEX_FULL_QUEUE
;
3911 /* Release the spinlock */
3912 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3914 /* Return status that the device is not ready */
3915 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
3916 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
3922 /* Start the next request, if LUN is idle, and this is sense request */
3923 if (((Srb
->ScsiStatus
!= SCSISTAT_CHECK_CONDITION
) ||
3924 (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) ||
3925 !Srb
->SenseInfoBuffer
|| !Srb
->SenseInfoBufferLength
)
3926 && (Srb
->SrbFlags
& SRB_FLAGS_NO_QUEUE_FREEZE
))
3928 if (LunExtension
->RequestTimeout
== -1)
3929 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
3931 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3935 /* Freeze the queue */
3936 Srb
->SrbStatus
|= SRB_STATUS_QUEUE_FROZEN
;
3937 LunExtension
->Flags
|= LUNEX_FROZEN_QUEUE
;
3939 /* Do we need a request sense? */
3940 if (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
3941 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3942 Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
)
3944 /* If LUN is busy, we have to requeue it in order to allow request sense */
3945 if (LunExtension
->Flags
& LUNEX_BUSY
)
3947 DPRINT("Requeueing busy request to allow request sense\n");
3949 if (!KeInsertByKeyDeviceQueue(&LunExtension
->DeviceQueue
,
3950 &LunExtension
->BusyRequest
->Tail
.Overlay
.DeviceQueueEntry
,
3953 /* We should never get here */
3956 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3957 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
3962 /* Clear busy flags */
3963 LunExtension
->Flags
&= ~(LUNEX_FULL_QUEUE
| LUNEX_BUSY
);
3966 /* Release the spinlock */
3967 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3969 /* Send RequestSense */
3970 SpiSendRequestSense(DeviceExtension
, Srb
);
3976 /* Release the spinlock */
3977 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
3980 /* Complete the request */
3981 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
3986 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
3990 PSCSI_REQUEST_BLOCK Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
3991 PSCSI_REQUEST_BLOCK InitialSrb
;
3994 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp
);
3996 if ((Srb
->Function
== SRB_FUNCTION_RESET_BUS
) ||
3997 (Srb
->Function
== SRB_FUNCTION_ABORT_COMMAND
))
3999 /* Deallocate SRB and IRP and exit */
4003 return STATUS_MORE_PROCESSING_REQUIRED
;
4006 /* Get a pointer to the SRB and IRP which were initially sent */
4007 InitialSrb
= *((PVOID
*)(Srb
+1));
4008 InitialIrp
= InitialSrb
->OriginalRequest
;
4010 if ((SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
) ||
4011 (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_DATA_OVERRUN
))
4013 /* Sense data is OK */
4014 InitialSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
4016 /* Set length to be the same */
4017 InitialSrb
->SenseInfoBufferLength
= (UCHAR
)Srb
->DataTransferLength
;
4020 /* Make sure initial SRB's queue is frozen */
4021 ASSERT(InitialSrb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
);
4023 /* Complete this request */
4024 IoCompleteRequest(InitialIrp
, IO_DISK_INCREMENT
);
4026 /* Deallocate everything (internal) */
4029 if (Irp
->MdlAddress
!= NULL
)
4031 MmUnlockPages(Irp
->MdlAddress
);
4032 IoFreeMdl(Irp
->MdlAddress
);
4033 Irp
->MdlAddress
= NULL
;
4037 return STATUS_MORE_PROCESSING_REQUIRED
;
4042 static BOOLEAN STDCALL
4043 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
4044 IN PVOID ServiceContext
)
4046 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4049 DPRINT("ScsiPortIsr() called!\n");
4051 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
4053 /* If interrupts are disabled - we don't expect any */
4054 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_DISABLE_INTERRUPTS
)
4057 /* Call miniport's HwInterrupt routine */
4058 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
4060 /* If flag of notification is set - queue a DPC */
4061 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4063 IoRequestDpc(DeviceExtension
->DeviceObject
,
4064 DeviceExtension
->CurrentIrp
,
4073 SpiSaveInterruptData(IN PVOID Context
)
4075 PSCSI_PORT_SAVE_INTERRUPT InterruptContext
= Context
;
4076 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4077 PSCSI_REQUEST_BLOCK Srb
;
4078 PSCSI_REQUEST_BLOCK_INFO SrbInfo
, NextSrbInfo
;
4079 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4082 /* Get pointer to the device extension */
4083 DeviceExtension
= InterruptContext
->DeviceExtension
;
4085 /* If we don't have anything pending - return */
4086 if (!(DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
))
4089 /* Actually save the interrupt data */
4090 *InterruptContext
->InterruptData
= DeviceExtension
->InterruptData
;
4092 /* Clear the data stored in the device extension */
4093 DeviceExtension
->InterruptData
.Flags
&=
4094 (SCSI_PORT_RESET
| SCSI_PORT_RESET_REQUEST
| SCSI_PORT_DISABLE_INTERRUPTS
);
4095 DeviceExtension
->InterruptData
.CompletedAbort
= NULL
;
4096 DeviceExtension
->InterruptData
.ReadyLun
= NULL
;
4097 DeviceExtension
->InterruptData
.CompletedRequests
= NULL
;
4099 /* Loop through the list of completed requests */
4100 SrbInfo
= InterruptContext
->InterruptData
->CompletedRequests
;
4104 /* Make sure we have SRV */
4105 ASSERT(SrbInfo
->Srb
);
4107 /* Get SRB and LunExtension */
4110 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4115 /* We have to check special cases if request is unsuccessfull*/
4116 if (Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
)
4118 /* Check if we need request sense by a few conditions */
4119 if (Srb
->SenseInfoBuffer
&& Srb
->SenseInfoBufferLength
&&
4120 Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
&&
4121 !(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
))
4123 if (LunExtension
->Flags
& LUNEX_NEED_REQUEST_SENSE
)
4125 /* It means: we tried to send REQUEST SENSE, but failed */
4127 Srb
->ScsiStatus
= 0;
4128 Srb
->SrbStatus
= SRB_STATUS_REQUEST_SENSE_FAILED
;
4132 /* Set the corresponding flag, so that REQUEST SENSE
4134 LunExtension
->Flags
|= LUNEX_NEED_REQUEST_SENSE
;
4139 /* Check for a full queue */
4140 if (Srb
->ScsiStatus
== SCSISTAT_QUEUE_FULL
)
4142 /* TODO: Implement when it's encountered */
4147 /* Let's decide if we need to watch timeout or not */
4148 if (Srb
->QueueTag
== SP_UNTAGGED
)
4154 if (LunExtension
->SrbInfo
.Requests
.Flink
== &SrbInfo
->Requests
)
4159 /* Remove it from the queue */
4160 RemoveEntryList(&SrbInfo
->Requests
);
4165 /* We have to maintain timeout counter */
4166 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
))
4168 LunExtension
->RequestTimeout
= -1;
4172 NextSrbInfo
= CONTAINING_RECORD(LunExtension
->SrbInfo
.Requests
.Flink
,
4173 SCSI_REQUEST_BLOCK_INFO
,
4176 Srb
= NextSrbInfo
->Srb
;
4178 /* Update timeout counter */
4179 LunExtension
->RequestTimeout
= Srb
->TimeOutValue
;
4183 SrbInfo
= SrbInfo
->CompletedRequests
;
4191 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4192 IN PSCSI_PORT_LUN_EXTENSION LunExtension
)
4194 PIO_STACK_LOCATION IrpStack
;
4196 PKDEVICE_QUEUE_ENTRY Entry
;
4197 PSCSI_REQUEST_BLOCK Srb
;
4200 /* If LUN is not active or queue is more than maximum allowed */
4201 if (LunExtension
->QueueCount
>= LunExtension
->MaxQueueCount
||
4202 !(LunExtension
->Flags
& SCSI_PORT_LU_ACTIVE
))
4204 /* Release the spinlock and exit */
4205 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4209 /* Check if we can get a next request */
4210 if (LunExtension
->Flags
&
4211 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_BUSY
|
4212 LUNEX_FULL_QUEUE
| LUNEX_FROZEN_QUEUE
| LUNEX_REQUEST_PENDING
))
4214 /* Pending requests can only be started if the queue is empty */
4215 if (IsListEmpty(&LunExtension
->SrbInfo
.Requests
) &&
4216 !(LunExtension
->Flags
&
4217 (LUNEX_BUSY
| LUNEX_FROZEN_QUEUE
| LUNEX_FULL_QUEUE
| LUNEX_NEED_REQUEST_SENSE
)))
4219 /* Make sure we have SRB */
4220 ASSERT(LunExtension
->SrbInfo
.Srb
== NULL
);
4222 /* Clear active and pending flags */
4223 LunExtension
->Flags
&= ~(LUNEX_REQUEST_PENDING
| SCSI_PORT_LU_ACTIVE
);
4225 /* Get next Irp, and clear pending requests list */
4226 NextIrp
= LunExtension
->PendingRequest
;
4227 LunExtension
->PendingRequest
= NULL
;
4229 /* Set attempt counter to zero */
4230 LunExtension
->AttemptCount
= 0;
4232 /* Release the spinlock */
4233 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4235 /* Start the next pending request */
4236 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4242 /* Release the spinlock, without clearing any flags and exit */
4243 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4249 /* Reset active flag */
4250 LunExtension
->Flags
&= ~SCSI_PORT_LU_ACTIVE
;
4252 /* Set attempt counter to zero */
4253 LunExtension
->AttemptCount
= 0;
4255 /* Remove packet from the device queue */
4256 Entry
= KeRemoveByKeyDeviceQueue(&LunExtension
->DeviceQueue
, LunExtension
->SortKey
);
4260 /* Get pointer to the next irp */
4261 NextIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
4263 /* Get point to the SRB */
4264 IrpStack
= IoGetCurrentIrpStackLocation(NextIrp
);
4265 Srb
= (PSCSI_REQUEST_BLOCK
)IrpStack
->Parameters
.Others
.Argument1
;
4268 LunExtension
->SortKey
= Srb
->QueueSortKey
;
4269 LunExtension
->SortKey
++;
4271 /* Release the spinlock */
4272 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4274 /* Start the next pending request */
4275 IoStartPacket(DeviceExtension
->DeviceObject
, NextIrp
, (PULONG
)NULL
, NULL
);
4279 /* Release the spinlock */
4280 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4286 // ScsiPortDpcForIsr
4293 // IN PDEVICE_OBJECT DpcDeviceObject
4295 // IN PVOID DpcContext
4298 ScsiPortDpcForIsr(IN PKDPC Dpc
,
4299 IN PDEVICE_OBJECT DpcDeviceObject
,
4301 IN PVOID DpcContext
)
4303 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DpcDeviceObject
->DeviceExtension
;
4304 SCSI_PORT_INTERRUPT_DATA InterruptData
;
4305 SCSI_PORT_SAVE_INTERRUPT Context
;
4306 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4307 BOOLEAN NeedToStartIo
;
4308 PSCSI_REQUEST_BLOCK_INFO SrbInfo
;
4310 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4311 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
4313 /* We need to acquire spinlock */
4314 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4316 RtlZeroMemory(&InterruptData
, sizeof(SCSI_PORT_INTERRUPT_DATA
));
4320 /* Interrupt structure must be snapshotted, and only then analyzed */
4321 Context
.InterruptData
= &InterruptData
;
4322 Context
.DeviceExtension
= DeviceExtension
;
4324 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4325 SpiSaveInterruptData
,
4328 /* Nothing - just return (don't forget to release the spinlock */
4329 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4330 DPRINT("ScsiPortDpcForIsr() done\n");
4334 /* If flush of adapters is needed - do it */
4335 if (InterruptData
.Flags
& SCSI_PORT_FLUSH_ADAPTERS
)
4337 /* TODO: Implement */
4341 /* Check for IoMapTransfer */
4342 if (InterruptData
.Flags
& SCSI_PORT_MAP_TRANSFER
)
4344 /* TODO: Implement */
4348 /* Check if timer is needed */
4349 if (InterruptData
.Flags
& SCIS_PORT_TIMER_NEEDED
)
4351 /* TODO: Implement */
4355 /* If it's ready for the next request */
4356 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4358 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4359 if ((DeviceExtension
->Flags
&
4360 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
)) ==
4361 (SCSI_PORT_DEVICE_BUSY
| SCSI_PORT_DISCONNECT_ALLOWED
))
4363 /* Clear busy flag set by ScsiPortStartPacket() */
4364 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4366 if (!(InterruptData
.Flags
& SCSI_PORT_RESET
))
4368 /* Ready for next, and no reset is happening */
4369 DeviceExtension
->TimerCount
= -1;
4374 /* Not busy, but not ready for the next request */
4375 DeviceExtension
->Flags
&= ~SCSI_PORT_DEVICE_BUSY
;
4376 InterruptData
.Flags
&= ~SCSI_PORT_NEXT_REQUEST_READY
;
4381 if (InterruptData
.Flags
& SCSI_PORT_RESET_REPORTED
)
4383 /* Hold for a bit */
4384 DeviceExtension
->TimerCount
= 4;
4387 /* Any ready LUN? */
4388 if (InterruptData
.ReadyLun
!= NULL
)
4391 /* Process all LUNs from the list*/
4394 /* Remove it from the list first (as processed) */
4395 LunExtension
= InterruptData
.ReadyLun
;
4396 InterruptData
.ReadyLun
= LunExtension
->ReadyLun
;
4397 LunExtension
->ReadyLun
= NULL
;
4399 /* Get next request for this LUN */
4400 SpiGetNextRequestFromLun(DeviceExtension
, LunExtension
);
4402 /* Still ready requests exist?
4403 If yes - get spinlock, if no - stop here */
4404 if (InterruptData
.ReadyLun
!= NULL
)
4405 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4412 /* Release the spinlock */
4413 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4416 /* If we ready for next packet, start it */
4417 if (InterruptData
.Flags
& SCSI_PORT_NEXT_REQUEST_READY
)
4418 IoStartNextPacket(DeviceExtension
->DeviceObject
, FALSE
);
4420 NeedToStartIo
= FALSE
;
4422 /* Loop the completed request list */
4423 while (InterruptData
.CompletedRequests
)
4425 /* Remove the request */
4426 SrbInfo
= InterruptData
.CompletedRequests
;
4427 InterruptData
.CompletedRequests
= SrbInfo
->CompletedRequests
;
4428 SrbInfo
->CompletedRequests
= NULL
;
4431 SpiProcessCompletedRequest(DeviceExtension
,
4436 /* Loop abort request list */
4437 while (InterruptData
.CompletedAbort
)
4439 LunExtension
= InterruptData
.CompletedAbort
;
4441 /* Remove the request */
4442 InterruptData
.CompletedAbort
= LunExtension
->CompletedAbortRequests
;
4444 /* Get spinlock since we're going to change flags */
4445 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4447 /* TODO: Put SrbExtension to the list of free extensions */
4451 /* If we need - call StartIo routine */
4454 /* Make sure CurrentIrp is not null! */
4455 ASSERT(DpcDeviceObject
->CurrentIrp
!= NULL
);
4456 ScsiPortStartIo(DpcDeviceObject
, DpcDeviceObject
->CurrentIrp
);
4459 /* Everything has been done, check */
4460 if (InterruptData
.Flags
& SCSI_PORT_ENABLE_INT_REQUEST
)
4462 /* Synchronize using spinlock */
4463 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4465 /* Request an interrupt */
4466 DeviceExtension
->HwInterrupt(DeviceExtension
->MiniPortDeviceExtension
);
4468 ASSERT(DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
);
4470 /* Should interrupts be enabled again? */
4471 if (DeviceExtension
->Flags
& SCSI_PORT_DISABLE_INT_REQUESET
)
4473 /* Clear this flag */
4474 DeviceExtension
->Flags
&= ~SCSI_PORT_DISABLE_INT_REQUESET
;
4476 /* Call a special routine to do this */
4479 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4480 SpiEnableInterrupts
,
4485 /* If we need a notification again - loop */
4486 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4489 /* Release the spinlock */
4490 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4493 DPRINT("ScsiPortDpcForIsr() done\n");
4498 SpiProcessTimeout(PVOID ServiceContext
)
4500 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
4501 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
4504 DPRINT("SpiProcessTimeout() entered\n");
4506 DeviceExtension
->TimerCount
= -1;
4508 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET
)
4510 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET
;
4512 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_RESET_REQUEST
)
4514 DeviceExtension
->InterruptData
.Flags
&= ~SCSI_PORT_RESET_REQUEST
;
4515 ScsiPortStartPacket(ServiceContext
);
4522 DPRINT("Resetting the bus\n");
4524 for (Bus
= 0; Bus
< DeviceExtension
->BusNum
; Bus
++)
4526 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
, Bus
);
4528 /* Reset flags and set reset timeout to 4 seconds */
4529 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
4530 DeviceExtension
->TimerCount
= 4;
4533 /* If miniport requested - request a dpc for it */
4534 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4535 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
4544 SpiResetBus(PVOID ServiceContext
)
4546 PRESETBUS_PARAMS ResetParams
= (PRESETBUS_PARAMS
)ServiceContext
;
4547 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4549 /* Perform the bus reset */
4550 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ResetParams
->DeviceExtension
;
4551 DeviceExtension
->HwResetBus(DeviceExtension
->MiniPortDeviceExtension
,
4552 ResetParams
->PathId
);
4554 /* Set flags and start the timer */
4555 DeviceExtension
->InterruptData
.Flags
|= SCSI_PORT_RESET
;
4556 DeviceExtension
->TimerCount
= 4;
4558 /* If miniport requested - give him a DPC */
4559 if (DeviceExtension
->InterruptData
.Flags
& SCSI_PORT_NOTIFICATION_NEEDED
)
4560 IoRequestDpc(DeviceExtension
->DeviceObject
, NULL
, NULL
);
4567 // This function handles timeouts and other time delayed processing
4572 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
4573 // IN PVOID Context the Controller extension for the
4574 // controller the device is on
4577 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
4580 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
4581 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4585 DPRINT("ScsiPortIoTimer()\n");
4587 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
4589 /* Protect with the spinlock */
4590 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4592 /* Check timeouts */
4593 if (DeviceExtension
->TimerCount
> 0)
4595 /* Decrease the timeout counter */
4596 DeviceExtension
->TimerCount
--;
4598 if (DeviceExtension
->TimerCount
== 0)
4600 /* Timeout, process it */
4601 if (KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4603 DeviceExtension
->DeviceObject
))
4605 DPRINT("Error happened during processing timeout, but nothing critical\n");
4609 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4611 /* We should exit now, since timeout is processed */
4615 /* Per-Lun scanning of timeouts is needed... */
4616 for (Lun
= 0; Lun
< LUS_NUMBER
; Lun
++)
4618 LunExtension
= DeviceExtension
->LunExtensionList
[Lun
];
4620 while (LunExtension
)
4622 if (LunExtension
->Flags
& LUNEX_BUSY
)
4624 if (!(LunExtension
->Flags
&
4625 (LUNEX_NEED_REQUEST_SENSE
| LUNEX_FROZEN_QUEUE
)))
4627 DPRINT("Retrying busy request\n");
4629 /* Clear flags, and retry busy request */
4630 LunExtension
->Flags
&= ~(LUNEX_BUSY
| LUNEX_FULL_QUEUE
);
4631 Irp
= LunExtension
->BusyRequest
;
4633 /* Clearing busy request */
4634 LunExtension
->BusyRequest
= NULL
;
4636 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4638 IoStartPacket(DeviceObject
, Irp
, (PULONG
)NULL
, NULL
);
4640 KeAcquireSpinLockAtDpcLevel(&DeviceExtension
->SpinLock
);
4643 else if (LunExtension
->RequestTimeout
== 0)
4645 RESETBUS_PARAMS ResetParams
;
4647 LunExtension
->RequestTimeout
= -1;
4649 DPRINT("Request timed out, resetting bus\n");
4651 /* Pass params to the bus reset routine */
4652 ResetParams
.PathId
= LunExtension
->PathId
;
4653 ResetParams
.DeviceExtension
= DeviceExtension
;
4655 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
4659 DPRINT1("Reset failed\n");
4662 else if (LunExtension
->RequestTimeout
> 0)
4664 /* Decrement the timeout counter */
4665 LunExtension
->RequestTimeout
--;
4668 LunExtension
= LunExtension
->Next
;
4672 /* Release the spinlock */
4673 KeReleaseSpinLockFromDpcLevel(&DeviceExtension
->SpinLock
);
4676 /**********************************************************************
4681 * Builds the registry device map of all device which are attached
4682 * to the given SCSI HBA port. The device map is located at:
4683 * \Registry\Machine\DeviceMap\Scsi
4693 * Name of registry driver service key.
4700 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
4701 PUNICODE_STRING RegistryPath
)
4703 PSCSI_PORT_LUN_EXTENSION LunExtension
;
4704 OBJECT_ATTRIBUTES ObjectAttributes
;
4705 UNICODE_STRING KeyName
;
4706 UNICODE_STRING ValueName
;
4707 WCHAR NameBuffer
[64];
4710 HANDLE ScsiPortKey
= NULL
;
4711 HANDLE ScsiBusKey
= NULL
;
4712 HANDLE ScsiInitiatorKey
= NULL
;
4713 HANDLE ScsiTargetKey
= NULL
;
4714 HANDLE ScsiLunKey
= NULL
;
4717 ULONG CurrentTarget
;
4724 DPRINT("SpiBuildDeviceMap() called\n");
4726 if (DeviceExtension
== NULL
|| RegistryPath
== NULL
)
4728 DPRINT1("Invalid parameter\n");
4729 return(STATUS_INVALID_PARAMETER
);
4732 /* Open or create the 'Scsi' subkey */
4733 RtlInitUnicodeString(&KeyName
,
4734 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
4735 InitializeObjectAttributes(&ObjectAttributes
,
4737 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
4740 Status
= ZwCreateKey(&ScsiKey
,
4745 REG_OPTION_VOLATILE
,
4747 if (!NT_SUCCESS(Status
))
4749 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4753 /* Create new 'Scsi Port X' subkey */
4754 DPRINT("Scsi Port %lu\n",
4755 DeviceExtension
->PortNumber
);
4757 swprintf(NameBuffer
,
4759 DeviceExtension
->PortNumber
);
4760 RtlInitUnicodeString(&KeyName
,
4762 InitializeObjectAttributes(&ObjectAttributes
,
4767 Status
= ZwCreateKey(&ScsiPortKey
,
4772 REG_OPTION_VOLATILE
,
4775 if (!NT_SUCCESS(Status
))
4777 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4782 * Create port-specific values
4785 /* Set 'DMA Enabled' (REG_DWORD) value */
4786 UlongData
= (ULONG
)!DeviceExtension
->PortCapabilities
.AdapterUsesPio
;
4787 DPRINT(" DMA Enabled = %s\n", (UlongData
) ? "TRUE" : "FALSE");
4788 RtlInitUnicodeString(&ValueName
,
4790 Status
= ZwSetValueKey(ScsiPortKey
,
4796 if (!NT_SUCCESS(Status
))
4798 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status
);
4799 ZwClose(ScsiPortKey
);
4803 /* Set 'Driver' (REG_SZ) value */
4804 DriverName
= wcsrchr(RegistryPath
->Buffer
, L
'\\') + 1;
4805 RtlInitUnicodeString(&ValueName
,
4807 Status
= ZwSetValueKey(ScsiPortKey
,
4812 (wcslen(DriverName
) + 1) * sizeof(WCHAR
));
4813 if (!NT_SUCCESS(Status
))
4815 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status
);
4816 ZwClose(ScsiPortKey
);
4820 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
4821 UlongData
= (ULONG
)DeviceExtension
->PortConfig
->BusInterruptLevel
;
4822 DPRINT(" Interrupt = %lu\n", UlongData
);
4823 RtlInitUnicodeString(&ValueName
,
4825 Status
= ZwSetValueKey(ScsiPortKey
,
4831 if (!NT_SUCCESS(Status
))
4833 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status
);
4834 ZwClose(ScsiPortKey
);
4838 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
4839 UlongData
= ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension
->PortConfig
->AccessRanges
)[0].RangeStart
);
4840 DPRINT(" IOAddress = %lx\n", UlongData
);
4841 RtlInitUnicodeString(&ValueName
,
4843 Status
= ZwSetValueKey(ScsiPortKey
,
4849 if (!NT_SUCCESS(Status
))
4851 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status
);
4852 ZwClose(ScsiPortKey
);
4856 /* Enumerate buses */
4857 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
->NumberOfBuses
; BusNumber
++)
4859 /* Create 'Scsi Bus X' key */
4860 DPRINT(" Scsi Bus %lu\n", BusNumber
);
4861 swprintf(NameBuffer
,
4864 RtlInitUnicodeString(&KeyName
,
4866 InitializeObjectAttributes(&ObjectAttributes
,
4871 Status
= ZwCreateKey(&ScsiBusKey
,
4876 REG_OPTION_VOLATILE
,
4878 if (!NT_SUCCESS(Status
))
4880 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4884 /* Create 'Initiator Id X' key */
4885 DPRINT(" Initiator Id %u\n",
4886 DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
4887 swprintf(NameBuffer
,
4889 (unsigned int)(UCHAR
)DeviceExtension
->PortConfig
->InitiatorBusId
[BusNumber
]);
4890 RtlInitUnicodeString(&KeyName
,
4892 InitializeObjectAttributes(&ObjectAttributes
,
4897 Status
= ZwCreateKey(&ScsiInitiatorKey
,
4902 REG_OPTION_VOLATILE
,
4904 if (!NT_SUCCESS(Status
))
4906 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4910 /* FIXME: Are there any initiator values (??) */
4912 ZwClose(ScsiInitiatorKey
);
4913 ScsiInitiatorKey
= NULL
;
4916 /* Enumerate targets */
4917 CurrentTarget
= (ULONG
)-1;
4918 ScsiTargetKey
= NULL
;
4919 for (Target
= 0; Target
< DeviceExtension
->PortConfig
->MaximumNumberOfTargets
; Target
++)
4921 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
4923 LunExtension
= SpiGetLunExtension(DeviceExtension
,
4927 if (LunExtension
!= NULL
)
4929 if (Target
!= CurrentTarget
)
4931 /* Close old target key */
4932 if (ScsiTargetKey
!= NULL
)
4934 ZwClose(ScsiTargetKey
);
4935 ScsiTargetKey
= NULL
;
4938 /* Create 'Target Id X' key */
4939 DPRINT(" Target Id %lu\n", Target
);
4940 swprintf(NameBuffer
,
4943 RtlInitUnicodeString(&KeyName
,
4945 InitializeObjectAttributes(&ObjectAttributes
,
4950 Status
= ZwCreateKey(&ScsiTargetKey
,
4955 REG_OPTION_VOLATILE
,
4957 if (!NT_SUCCESS(Status
))
4959 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4963 CurrentTarget
= Target
;
4966 /* Create 'Logical Unit Id X' key */
4967 DPRINT(" Logical Unit Id %lu\n", Lun
);
4968 swprintf(NameBuffer
,
4969 L
"Logical Unit Id %lu",
4971 RtlInitUnicodeString(&KeyName
,
4973 InitializeObjectAttributes(&ObjectAttributes
,
4978 Status
= ZwCreateKey(&ScsiLunKey
,
4983 REG_OPTION_VOLATILE
,
4985 if (!NT_SUCCESS(Status
))
4987 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
4991 /* Set 'Identifier' (REG_SZ) value */
4992 swprintf(NameBuffer
,
4994 LunExtension
->InquiryData
.VendorId
,
4995 LunExtension
->InquiryData
.ProductId
,
4996 LunExtension
->InquiryData
.ProductRevisionLevel
);
4997 DPRINT(" Identifier = '%S'\n", NameBuffer
);
4998 RtlInitUnicodeString(&ValueName
,
5000 Status
= ZwSetValueKey(ScsiLunKey
,
5005 (wcslen(NameBuffer
) + 1) * sizeof(WCHAR
));
5006 if (!NT_SUCCESS(Status
))
5008 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status
);
5012 /* Set 'Type' (REG_SZ) value */
5013 switch (LunExtension
->InquiryData
.DeviceType
)
5016 TypeName
= L
"DiskPeripheral";
5019 TypeName
= L
"TapePeripheral";
5022 TypeName
= L
"PrinterPeripheral";
5025 TypeName
= L
"WormPeripheral";
5028 TypeName
= L
"CdRomPeripheral";
5031 TypeName
= L
"ScannerPeripheral";
5034 TypeName
= L
"OpticalDiskPeripheral";
5037 TypeName
= L
"MediumChangerPeripheral";
5040 TypeName
= L
"CommunicationPeripheral";
5043 TypeName
= L
"OtherPeripheral";
5046 DPRINT(" Type = '%S'\n", TypeName
);
5047 RtlInitUnicodeString(&ValueName
,
5049 Status
= ZwSetValueKey(ScsiLunKey
,
5054 (wcslen(TypeName
) + 1) * sizeof(WCHAR
));
5055 if (!NT_SUCCESS(Status
))
5057 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status
);
5061 ZwClose(ScsiLunKey
);
5066 /* Close old target key */
5067 if (ScsiTargetKey
!= NULL
)
5069 ZwClose(ScsiTargetKey
);
5070 ScsiTargetKey
= NULL
;
5074 ZwClose(ScsiBusKey
);
5079 if (ScsiLunKey
!= NULL
)
5080 ZwClose (ScsiLunKey
);
5082 if (ScsiInitiatorKey
!= NULL
)
5083 ZwClose (ScsiInitiatorKey
);
5085 if (ScsiTargetKey
!= NULL
)
5086 ZwClose (ScsiTargetKey
);
5088 if (ScsiBusKey
!= NULL
)
5089 ZwClose (ScsiBusKey
);
5091 if (ScsiPortKey
!= NULL
)
5092 ZwClose (ScsiPortKey
);
5094 DPRINT("SpiBuildDeviceMap() done\n");
5101 SpiMiniportTimerDpc(IN
struct _KDPC
*Dpc
,
5102 IN PVOID DeviceObject
,
5103 IN PVOID SystemArgument1
,
5104 IN PVOID SystemArgument2
)
5106 DPRINT1("Miniport timer DPC\n");
5110 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5111 PHW_INITIALIZATION_DATA HwInitData
,
5112 PCONFIGURATION_INFO InternalConfigInfo
,
5113 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5116 UNICODE_STRING UnicodeString
;
5117 OBJECT_ATTRIBUTES ObjectAttributes
;
5118 PCONFIGURATION_INFORMATION DdkConfigInformation
;
5119 HANDLE RootKey
, Key
;
5121 WCHAR DeviceBuffer
[16];
5122 WCHAR StrBuffer
[512];
5126 /* Zero out the struct if told so */
5129 /* First zero the portconfig */
5130 RtlZeroMemory(ConfigInfo
, sizeof(PORT_CONFIGURATION_INFORMATION
));
5132 /* Then access ranges */
5133 RtlZeroMemory(InternalConfigInfo
->AccessRanges
,
5134 HwInitData
->NumberOfAccessRanges
* sizeof(ACCESS_RANGE
));
5136 /* Initialize the struct */
5137 ConfigInfo
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
5138 ConfigInfo
->AdapterInterfaceType
= HwInitData
->AdapterInterfaceType
;
5139 ConfigInfo
->InterruptMode
= Latched
;
5140 ConfigInfo
->DmaChannel
= SP_UNINITIALIZED_VALUE
;
5141 ConfigInfo
->DmaPort
= SP_UNINITIALIZED_VALUE
;
5142 ConfigInfo
->MaximumTransferLength
= SP_UNINITIALIZED_VALUE
;
5143 ConfigInfo
->NumberOfAccessRanges
= HwInitData
->NumberOfAccessRanges
;
5144 ConfigInfo
->MaximumNumberOfTargets
= 8;
5146 /* Store parameters */
5147 ConfigInfo
->NeedPhysicalAddresses
= HwInitData
->NeedPhysicalAddresses
;
5148 ConfigInfo
->MapBuffers
= HwInitData
->MapBuffers
;
5149 ConfigInfo
->AutoRequestSense
= HwInitData
->AutoRequestSense
;
5150 ConfigInfo
->ReceiveEvent
= HwInitData
->ReceiveEvent
;
5151 ConfigInfo
->TaggedQueuing
= HwInitData
->TaggedQueuing
;
5152 ConfigInfo
->MultipleRequestPerLu
= HwInitData
->MultipleRequestPerLu
;
5154 /* Get the disk usage */
5155 DdkConfigInformation
= IoGetConfigurationInformation();
5156 ConfigInfo
->AtdiskPrimaryClaimed
= DdkConfigInformation
->AtDiskPrimaryAddressClaimed
;
5157 ConfigInfo
->AtdiskSecondaryClaimed
= DdkConfigInformation
->AtDiskSecondaryAddressClaimed
;
5159 /* Initiator bus id is not set */
5160 for (Bus
= 0; Bus
< 8; Bus
++)
5161 ConfigInfo
->InitiatorBusId
[Bus
] = (CCHAR
)SP_UNINITIALIZED_VALUE
;
5164 ConfigInfo
->NumberOfPhysicalBreaks
= 17;
5166 /* Clear this information */
5167 InternalConfigInfo
->DisableTaggedQueueing
= FALSE
;
5168 InternalConfigInfo
->DisableMultipleLun
= FALSE
;
5170 /* Store Bus Number */
5171 ConfigInfo
->SystemIoBusNumber
= InternalConfigInfo
->BusNumber
;
5175 if (ConfigInfo
->AdapterInterfaceType
== Internal
)
5177 /* Open registry key for HW database */
5178 InitializeObjectAttributes(&ObjectAttributes
,
5179 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
5180 OBJ_CASE_INSENSITIVE
,
5184 Status
= ZwOpenKey(&RootKey
,
5188 if (NT_SUCCESS(Status
))
5190 /* Create name for it */
5191 swprintf(StrBuffer
, L
"ScsiAdapter\\%lu",
5192 InternalConfigInfo
->AdapterNumber
);
5194 RtlInitUnicodeString(&UnicodeString
, StrBuffer
);
5196 /* Open device key */
5197 InitializeObjectAttributes(&ObjectAttributes
,
5199 OBJ_CASE_INSENSITIVE
,
5203 Status
= ZwOpenKey(&Key
,
5209 if (NT_SUCCESS(Status
))
5211 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5213 DPRINT("Hardware info found at %S\n", StrBuffer
);
5216 SpiParseDeviceInfo(DeviceExtension
,
5222 InternalConfigInfo
->BusNumber
= 0;
5226 /* Try the next adapter */
5227 InternalConfigInfo
->AdapterNumber
++;
5233 /* Info was not found, exit */
5234 return STATUS_DEVICE_DOES_NOT_EXIST
;
5240 /* Look at device params */
5242 if (InternalConfigInfo
->Parameter
)
5244 ExFreePool(InternalConfigInfo
->Parameter
);
5245 InternalConfigInfo
->Parameter
= NULL
;
5248 if (InternalConfigInfo
->ServiceKey
!= NULL
)
5250 swprintf(DeviceBuffer
, L
"Device%lu", InternalConfigInfo
->AdapterNumber
);
5251 RtlInitUnicodeString(&UnicodeString
, DeviceBuffer
);
5253 /* Open the service key */
5254 InitializeObjectAttributes(&ObjectAttributes
,
5256 OBJ_CASE_INSENSITIVE
,
5257 InternalConfigInfo
->ServiceKey
,
5260 Status
= ZwOpenKey(&Key
,
5265 /* Parse device key */
5266 if (InternalConfigInfo
->DeviceKey
!= NULL
)
5268 SpiParseDeviceInfo(DeviceExtension
,
5269 InternalConfigInfo
->DeviceKey
,
5275 /* Then parse hw info */
5278 if (InternalConfigInfo
->LastAdapterNumber
!= InternalConfigInfo
->AdapterNumber
)
5280 SpiParseDeviceInfo(DeviceExtension
,
5291 /* Adapter not found, go try the next one */
5292 InternalConfigInfo
->AdapterNumber
++;
5301 /* Update the last adapter number */
5302 InternalConfigInfo
->LastAdapterNumber
= InternalConfigInfo
->AdapterNumber
;
5304 /* Do we have this kind of bus at all? */
5306 Status
= IoQueryDeviceDescription(&HwInitData
->AdapterInterfaceType
,
5307 &InternalConfigInfo
->BusNumber
,
5312 SpQueryDeviceCallout
,
5315 /* This bus was not found */
5318 INTERFACE_TYPE InterfaceType
= Eisa
;
5320 /* Check for EISA */
5321 if (HwInitData
->AdapterInterfaceType
== Isa
)
5323 Status
= IoQueryDeviceDescription(&InterfaceType
,
5324 &InternalConfigInfo
->BusNumber
,
5329 SpQueryDeviceCallout
,
5332 /* Return respectively */
5334 return STATUS_SUCCESS
;
5336 return STATUS_DEVICE_DOES_NOT_EXIST
;
5340 return STATUS_DEVICE_DOES_NOT_EXIST
;
5345 return STATUS_SUCCESS
;
5350 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
5352 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
5353 IN PCONFIGURATION_INFO InternalConfigInfo
,
5356 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
5357 PCM_FULL_RESOURCE_DESCRIPTOR FullResource
;
5358 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
5359 PCM_SCSI_DEVICE_DATA ScsiDeviceData
;
5360 ULONG Length
, Count
;
5361 ULONG Index
= 0, RangeCount
= 0;
5362 UNICODE_STRING UnicodeString
;
5363 ANSI_STRING AnsiString
;
5364 NTSTATUS Status
= STATUS_SUCCESS
;
5367 KeyValueInformation
= (PKEY_VALUE_FULL_INFORMATION
) Buffer
;
5369 /* Loop through all values in the device node */
5372 Status
= ZwEnumerateValueKey(Key
,
5374 KeyValueFullInformation
,
5379 if (!NT_SUCCESS(Status
))
5384 /* Length for DWORD is ok? */
5385 if (KeyValueInformation
->Type
== REG_DWORD
&&
5386 KeyValueInformation
->DataLength
!= sizeof(ULONG
))
5391 /* Get MaximumLogicalUnit */
5392 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumLogicalUnit",
5393 KeyValueInformation
->NameLength
/2) == 0)
5396 if (KeyValueInformation
->Type
!= REG_DWORD
)
5398 DPRINT("Bad data type for MaximumLogicalUnit\n");
5402 DeviceExtension
->MaxLunCount
= *((PUCHAR
)
5403 (Buffer
+ KeyValueInformation
->DataOffset
));
5405 /* Check / reset if needed */
5406 if (DeviceExtension
->MaxLunCount
> SCSI_MAXIMUM_LOGICAL_UNITS
)
5407 DeviceExtension
->MaxLunCount
= SCSI_MAXIMUM_LOGICAL_UNITS
;
5409 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension
->MaxLunCount
);
5412 /* Get InitiatorTargetId */
5413 if (_wcsnicmp(KeyValueInformation
->Name
, L
"InitiatorTargetId",
5414 KeyValueInformation
->NameLength
/ 2) == 0)
5417 if (KeyValueInformation
->Type
!= REG_DWORD
)
5419 DPRINT("Bad data type for InitiatorTargetId\n");
5423 ConfigInfo
->InitiatorBusId
[0] = *((PUCHAR
)
5424 (Buffer
+ KeyValueInformation
->DataOffset
));
5426 /* Check / reset if needed */
5427 if (ConfigInfo
->InitiatorBusId
[0] > ConfigInfo
->MaximumNumberOfTargets
- 1)
5428 ConfigInfo
->InitiatorBusId
[0] = (CCHAR
)-1;
5430 DPRINT("InitiatorTargetId = %d\n", ConfigInfo
->InitiatorBusId
[0]);
5434 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ScsiDebug",
5435 KeyValueInformation
->NameLength
/2) == 0)
5437 DPRINT("ScsiDebug key not supported\n");
5440 /* Check for a breakpoint */
5441 if (_wcsnicmp(KeyValueInformation
->Name
, L
"BreakPointOnEntry",
5442 KeyValueInformation
->NameLength
/2) == 0)
5444 DPRINT1("Breakpoint on entry requested!\n");
5448 /* Get DisableSynchronousTransfers */
5449 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableSynchronousTransfers",
5450 KeyValueInformation
->NameLength
/2) == 0)
5452 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5453 DPRINT("Synch transfers disabled\n");
5456 /* Get DisableDisconnects */
5457 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableDisconnects",
5458 KeyValueInformation
->NameLength
/2) == 0)
5460 DeviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
5461 DPRINT("Disconnects disabled\n");
5464 /* Get DisableTaggedQueuing */
5465 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableTaggedQueuing",
5466 KeyValueInformation
->NameLength
/2) == 0)
5468 InternalConfigInfo
->DisableTaggedQueueing
= TRUE
;
5469 DPRINT("Tagged queueing disabled\n");
5472 /* Get DisableMultipleRequests */
5473 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DisableMultipleRequests",
5474 KeyValueInformation
->NameLength
/2) == 0)
5476 InternalConfigInfo
->DisableMultipleLun
= TRUE
;
5477 DPRINT("Multiple requests disabled\n");
5480 /* Get DriverParameters */
5481 if (_wcsnicmp(KeyValueInformation
->Name
, L
"DriverParameters",
5482 KeyValueInformation
->NameLength
/2) == 0)
5484 /* Skip if nothing */
5485 if (KeyValueInformation
->DataLength
== 0)
5488 /* If there was something previously allocated - free it */
5489 if (InternalConfigInfo
->Parameter
!= NULL
)
5490 ExFreePool(InternalConfigInfo
->Parameter
);
5493 InternalConfigInfo
->Parameter
= ExAllocatePoolWithTag(NonPagedPool
,
5494 KeyValueInformation
->DataLength
, TAG_SCSIPORT
);
5496 if (InternalConfigInfo
->Parameter
!= NULL
)
5498 if (KeyValueInformation
->Type
!= REG_SZ
)
5502 InternalConfigInfo
->Parameter
,
5503 (PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
,
5504 KeyValueInformation
->DataLength
);
5508 /* If it's a unicode string, convert it to ansi */
5509 UnicodeString
.Length
= (USHORT
)KeyValueInformation
->DataLength
;
5510 UnicodeString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
5511 UnicodeString
.Buffer
=
5512 (PWSTR
)((PCCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
5514 AnsiString
.Length
= 0;
5515 AnsiString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
5516 AnsiString
.Buffer
= (PCHAR
)InternalConfigInfo
->Parameter
;
5518 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
5522 /* In case of error, free the allocated space */
5523 if (!NT_SUCCESS(Status
))
5525 ExFreePool(InternalConfigInfo
->Parameter
);
5526 InternalConfigInfo
->Parameter
= NULL
;
5532 DPRINT("Found driver parameter\n");
5535 /* Get MaximumSGList */
5536 if (_wcsnicmp(KeyValueInformation
->Name
, L
"MaximumSGList",
5537 KeyValueInformation
->NameLength
/2) == 0)
5539 if (KeyValueInformation
->Type
!= REG_DWORD
)
5541 DPRINT("Bad data type for MaximumSGList\n");
5545 ConfigInfo
->NumberOfPhysicalBreaks
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
5548 if (ConfigInfo
->NumberOfPhysicalBreaks
> SCSI_MAXIMUM_PHYSICAL_BREAKS
)
5550 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MAXIMUM_PHYSICAL_BREAKS
;
5552 else if (ConfigInfo
->NumberOfPhysicalBreaks
< SCSI_MINIMUM_PHYSICAL_BREAKS
)
5554 ConfigInfo
->NumberOfPhysicalBreaks
= SCSI_MINIMUM_PHYSICAL_BREAKS
;
5557 DPRINT("MaximumSGList = %d\n", ConfigInfo
->NumberOfPhysicalBreaks
);
5560 /* Get NumberOfRequests */
5561 if (_wcsnicmp(KeyValueInformation
->Name
, L
"NumberOfRequests",
5562 KeyValueInformation
->NameLength
/2) == 0)
5564 if (KeyValueInformation
->Type
!= REG_DWORD
)
5566 DPRINT("NumberOfRequests has wrong data type\n");
5570 DeviceExtension
->RequestsNumber
= *((PUCHAR
)(Buffer
+ KeyValueInformation
->DataOffset
));
5573 if (DeviceExtension
->RequestsNumber
< 16)
5575 DeviceExtension
->RequestsNumber
= 16;
5577 else if (DeviceExtension
->RequestsNumber
> 512)
5579 DeviceExtension
->RequestsNumber
= 512;
5582 DPRINT("Number Of Requests = %d\n", DeviceExtension
->RequestsNumber
);
5585 /* Get resource list */
5586 if (_wcsnicmp(KeyValueInformation
->Name
, L
"ResourceList",
5587 KeyValueInformation
->NameLength
/2) == 0 ||
5588 _wcsnicmp(KeyValueInformation
->Name
, L
"Configuration Data",
5589 KeyValueInformation
->NameLength
/2) == 0 )
5591 if (KeyValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
||
5592 KeyValueInformation
->DataLength
< sizeof(REG_FULL_RESOURCE_DESCRIPTOR
))
5594 DPRINT("Bad data type for ResourceList\n");
5599 DPRINT("Found ResourceList\n");
5602 FullResource
= (PCM_FULL_RESOURCE_DESCRIPTOR
)(Buffer
+ KeyValueInformation
->DataOffset
);
5604 /* Copy some info from it */
5605 InternalConfigInfo
->BusNumber
= FullResource
->BusNumber
;
5606 ConfigInfo
->SystemIoBusNumber
= FullResource
->BusNumber
;
5608 /* Loop through it */
5609 for (Count
= 0; Count
< FullResource
->PartialResourceList
.Count
; Count
++)
5611 /* Get partial descriptor */
5613 &FullResource
->PartialResourceList
.PartialDescriptors
[Count
];
5615 /* Check datalength */
5616 if ((ULONG
)((PCHAR
)(PartialDescriptor
+ 1) -
5617 (PCHAR
)FullResource
) > KeyValueInformation
->DataLength
)
5619 DPRINT("Resource data is of incorrect size\n");
5623 switch (PartialDescriptor
->Type
)
5625 case CmResourceTypePort
:
5626 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
5628 DPRINT("Too many access ranges\n");
5632 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= FALSE
;
5633 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Port
.Start
;
5634 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Port
.Length
;
5639 case CmResourceTypeMemory
:
5640 if (RangeCount
>= ConfigInfo
->NumberOfAccessRanges
)
5642 DPRINT("Too many access ranges\n");
5646 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeInMemory
= TRUE
;
5647 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeStart
= PartialDescriptor
->u
.Memory
.Start
;
5648 InternalConfigInfo
->AccessRanges
[RangeCount
].RangeLength
= PartialDescriptor
->u
.Memory
.Length
;
5653 case CmResourceTypeInterrupt
:
5654 ConfigInfo
->BusInterruptLevel
=
5655 PartialDescriptor
->u
.Interrupt
.Level
;
5657 ConfigInfo
->BusInterruptVector
=
5658 PartialDescriptor
->u
.Interrupt
.Vector
;
5661 case CmResourceTypeDma
:
5662 ConfigInfo
->DmaChannel
= PartialDescriptor
->u
.Dma
.Channel
;
5663 ConfigInfo
->DmaPort
= PartialDescriptor
->u
.Dma
.Port
;
5666 case CmResourceTypeDeviceSpecific
:
5667 if (PartialDescriptor
->u
.DeviceSpecificData
.DataSize
<
5668 sizeof(CM_SCSI_DEVICE_DATA
) ||
5669 (PCHAR
) (PartialDescriptor
+ 1) - (PCHAR
)FullResource
+
5670 PartialDescriptor
->u
.DeviceSpecificData
.DataSize
>
5671 KeyValueInformation
->DataLength
)
5673 DPRINT("Resource data length is incorrect");
5677 /* Set only one field from it */
5678 ScsiDeviceData
= (PCM_SCSI_DEVICE_DATA
) (PartialDescriptor
+1);
5679 ConfigInfo
->InitiatorBusId
[0] = ScsiDeviceData
->HostIdentifier
;
5690 SpQueryDeviceCallout(IN PVOID Context
,
5691 IN PUNICODE_STRING PathName
,
5692 IN INTERFACE_TYPE BusType
,
5694 IN PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
5695 IN CONFIGURATION_TYPE ControllerType
,
5696 IN ULONG ControllerNumber
,
5697 IN PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
5698 IN CONFIGURATION_TYPE PeripheralType
,
5699 IN ULONG PeripheralNumber
,
5700 IN PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
5702 PBOOLEAN Found
= (PBOOLEAN
)Context
;
5703 /* We just set our Found variable to TRUE */
5706 return STATUS_SUCCESS
;
5713 SpiStatusSrbToNt(UCHAR SrbStatus
)
5715 switch (SRB_STATUS(SrbStatus
))
5717 case SRB_STATUS_TIMEOUT
:
5718 case SRB_STATUS_COMMAND_TIMEOUT
:
5719 return STATUS_IO_TIMEOUT
;
5721 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH
:
5722 case SRB_STATUS_BAD_FUNCTION
:
5723 return STATUS_INVALID_DEVICE_REQUEST
;
5725 case SRB_STATUS_NO_DEVICE
:
5726 case SRB_STATUS_INVALID_LUN
:
5727 case SRB_STATUS_INVALID_TARGET_ID
:
5728 case SRB_STATUS_NO_HBA
:
5729 return STATUS_DEVICE_DOES_NOT_EXIST
;
5731 case SRB_STATUS_DATA_OVERRUN
:
5732 return STATUS_BUFFER_OVERFLOW
;
5734 case SRB_STATUS_SELECTION_TIMEOUT
:
5735 return STATUS_DEVICE_NOT_CONNECTED
;
5738 return STATUS_IO_DEVICE_ERROR
;
5741 return STATUS_IO_DEVICE_ERROR
;
5745 #undef ScsiPortConvertPhysicalAddressToUlong
5750 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
5752 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
5753 return(Address
.u
.LowPart
);