* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* $Id$
- *
+/*
* COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: services/storage/scsiport/scsiport.c
+ * PROJECT: ReactOS Storage Stack
+ * FILE: drivers/storage/scsiport/scsiport.c
* PURPOSE: SCSI port driver
* PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
- * Hartmut Birr
+ * Aleksey Bragin (aleksey reactos org)
*/
/* INCLUDES *****************************************************************/
#include <ntddstor.h>
#include <ntdddisk.h>
#include <stdio.h>
+#include <stdarg.h>
+#ifndef NDEBUG
#define NDEBUG
+#endif
#include <debug.h>
#include "scsiport_int.h"
-/* TYPES *********************************************************************/
+ULONG InternalDebugLevel = 0x00;
-#define IRP_FLAG_COMPLETE 0x00000001
-#define IRP_FLAG_NEXT 0x00000002
-#define IRP_FLAG_NEXT_LU 0x00000004
+/* TYPES *********************************************************************/
/* GLOBALS *******************************************************************/
-static ULONG InternalDebugLevel = 0;
-
-static VOID
-SpiProcessRequests(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- PIRP NextIrp);
-
-static VOID
-SpiStartIo(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- PIRP Irp);
-
static BOOLEAN
-SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
- IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
- IN ULONG BusNumber,
- IN OUT PPCI_SLOT_NUMBER NextSlotNumber);
-
-static NTSTATUS STDCALL
+SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
+ IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
+ IN PUNICODE_STRING RegistryPath,
+ IN ULONG BusNumber,
+ IN OUT PPCI_SLOT_NUMBER NextSlotNumber);
+
+static NTSTATUS NTAPI
ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
-static NTSTATUS STDCALL
+static DRIVER_DISPATCH ScsiPortDispatchScsi;
+static NTSTATUS NTAPI
ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
-static NTSTATUS STDCALL
+static NTSTATUS NTAPI
ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
-static BOOLEAN STDCALL
+static DRIVER_STARTIO ScsiPortStartIo;
+static VOID NTAPI
+ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+static BOOLEAN NTAPI
ScsiPortStartPacket(IN OUT PVOID Context);
+IO_ALLOCATION_ACTION
+NTAPI
+SpiAdapterControl(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+ PVOID MapRegisterBase, PVOID Context);
static PSCSI_PORT_LUN_EXTENSION
-SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- IN UCHAR PathId,
- IN UCHAR TargetId,
- IN UCHAR Lun);
-
-static VOID
-SpiRemoveLunExtension (IN PSCSI_PORT_LUN_EXTENSION LunExtension);
+SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
static PSCSI_PORT_LUN_EXTENSION
SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR TargetId,
IN UCHAR Lun);
+static PSCSI_REQUEST_BLOCK_INFO
+SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ PSCSI_PORT_LUN_EXTENSION LunExtension,
+ PSCSI_REQUEST_BLOCK Srb);
+
static NTSTATUS
SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
- IN OUT PSCSI_REQUEST_BLOCK Srb,
- IN OUT PIO_STATUS_BLOCK IoStatusBlock,
- IN OUT PKEVENT Event);
+ IN PSCSI_LUN_INFO LunInfo);
static VOID
SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
-static ULONG
+static NTSTATUS
SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo);
+ IN PIRP Irp);
-static BOOLEAN STDCALL
+static PSCSI_REQUEST_BLOCK_INFO
+SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN UCHAR QueueTag);
+
+static BOOLEAN NTAPI
ScsiPortIsr(IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext);
-static VOID STDCALL
-ScsiPortDpc(IN PKDPC Dpc,
- IN PDEVICE_OBJECT DpcDeviceObject,
- IN PIRP DpcIrp,
- IN PVOID DpcContext);
+static VOID NTAPI
+ScsiPortDpcForIsr(IN PKDPC Dpc,
+ IN PDEVICE_OBJECT DpcDeviceObject,
+ IN PIRP DpcIrp,
+ IN PVOID DpcContext);
-static VOID STDCALL
+static VOID NTAPI
ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
PVOID Context);
-static PSCSI_REQUEST_BLOCK
-ScsiPortInitSenseRequestSrb(PSCSI_REQUEST_BLOCK OriginalSrb);
+IO_ALLOCATION_ACTION
+NTAPI
+ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context);
static NTSTATUS
SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
PUNICODE_STRING RegistryPath);
+static NTSTATUS
+SpiStatusSrbToNt(UCHAR SrbStatus);
+
+static VOID
+SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb);
+
+static IO_COMPLETION_ROUTINE SpiCompletionRoutine;
+NTSTATUS NTAPI
+SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context);
+
+static VOID
+NTAPI
+SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
+ OUT PBOOLEAN NeedToCallStartIo);
+
+VOID NTAPI
+SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_PORT_LUN_EXTENSION LunExtension);
+
+VOID NTAPI
+SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
+ IN PVOID DeviceObject,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2);
+
+static NTSTATUS
+SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ PHW_INITIALIZATION_DATA HwInitData,
+ PCONFIGURATION_INFO InternalConfigInfo,
+ PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ BOOLEAN FirstCall);
+
+NTSTATUS NTAPI
+SpQueryDeviceCallout(IN PVOID Context,
+ IN PUNICODE_STRING PathName,
+ IN INTERFACE_TYPE BusType,
+ IN ULONG BusNumber,
+ IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
+ IN CONFIGURATION_TYPE ControllerType,
+ IN ULONG ControllerNumber,
+ IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
+ IN CONFIGURATION_TYPE PeripheralType,
+ IN ULONG PeripheralNumber,
+ IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation);
+
static VOID
-SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- PSCSI_REQUEST_BLOCK Srb);
+SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN HANDLE Key,
+ IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN PCONFIGURATION_INFO InternalConfigInfo,
+ IN PUCHAR Buffer);
static VOID
-SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- PSCSI_REQUEST_BLOCK Srb);
+SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
+ IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
+ IN PPORT_CONFIGURATION_INFORMATION PortConfig);
+static PCM_RESOURCE_LIST
+SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ PPORT_CONFIGURATION_INFORMATION PortConfig);
+
+static VOID
+SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
+
+static NTSTATUS
+SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ PIRP Irp);
static NTSTATUS
-SpiScsiMiniport(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp);
+SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize);
+
+
/* FUNCTIONS *****************************************************************/
* Status.
*/
-NTSTATUS STDCALL
+NTSTATUS NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
- DPRINT("ScsiPort Driver %s\n", VERSION);
- return(STATUS_SUCCESS);
+ DPRINT("ScsiPort Driver %s\n", VERSION);
+ return(STATUS_SUCCESS);
}
IN PCHAR DebugMessage,
...)
{
- char Buffer[256];
- va_list ap;
+ char Buffer[256];
+ va_list ap;
- if (DebugPrintLevel >= InternalDebugLevel)
- return;
+ if (DebugPrintLevel > InternalDebugLevel)
+ return;
- va_start(ap, DebugMessage);
- vsprintf(Buffer, DebugMessage, ap);
- va_end(ap);
+ va_start(ap, DebugMessage);
+ vsprintf(Buffer, DebugMessage, ap);
+ va_end(ap);
- DbgPrint(Buffer);
+ DbgPrint(Buffer);
}
+/* An internal helper function for ScsiPortCompleteRequest */
+VOID
+NTAPI
+SpiCompleteRequest(IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
+ IN UCHAR SrbStatus)
+{
+ PSCSI_REQUEST_BLOCK Srb;
+
+ /* Get current SRB */
+ Srb = SrbInfo->Srb;
+
+ /* Return if there is no SRB or it is not active */
+ if (!Srb || !(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) return;
+
+ /* Set status */
+ Srb->SrbStatus = SrbStatus;
+
+ /* Set data transfered to 0 */
+ Srb->DataTransferLength = 0;
+
+ /* Notify */
+ ScsiPortNotification(RequestComplete,
+ HwDeviceExtension,
+ Srb);
+}
/*
* @unimplemented
*/
-VOID STDCALL
+VOID NTAPI
ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
- IN UCHAR PathId,
- IN UCHAR TargetId,
- IN UCHAR Lun,
- IN UCHAR SrbStatus)
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN UCHAR SrbStatus)
{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- PSCSI_PORT_LUN_EXTENSION LunExtension;
- PLIST_ENTRY Entry;
- PIRP Irp;
- PSCSI_REQUEST_BLOCK Srb;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+ PLIST_ENTRY ListEntry;
+ ULONG BusNumber;
+ ULONG Target;
- DPRINT("ScsiPortCompleteRequest(HwDeviceExtension %x, PathId %d, TargetId %d, Lun %d, SrbStatus %x)\n",
- HwDeviceExtension, PathId, TargetId, Lun, SrbStatus);
+ DPRINT("ScsiPortCompleteRequest() called\n");
- DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
- SCSI_PORT_DEVICE_EXTENSION,
- MiniPortDeviceExtension);
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
- Entry = DeviceExtension->LunExtensionListHead.Flink;
- while (Entry != &DeviceExtension->LunExtensionListHead)
+ /* Go through all buses */
+ for (BusNumber = 0; BusNumber < 8; BusNumber++)
{
- LunExtension = CONTAINING_RECORD(Entry,
- SCSI_PORT_LUN_EXTENSION,
- List);
-
-
-
- if (PathId == (UCHAR)SP_UNTAGGED ||
- (PathId == LunExtension->PathId && TargetId == (UCHAR)SP_UNTAGGED) ||
- (PathId == LunExtension->PathId && TargetId == LunExtension->TargetId && Lun == (UCHAR)SP_UNTAGGED) ||
- (PathId == LunExtension->PathId && TargetId == LunExtension->TargetId && Lun == LunExtension->Lun))
+ /* Go through all targets */
+ for (Target = 0; Target < DeviceExtension->MaxTargedIds; Target++)
{
- Irp = LunExtension->NextIrp;
- while (Irp)
- {
- Srb = (PSCSI_REQUEST_BLOCK)Irp->Tail.Overlay.DriverContext[3];
- if (Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)
- {
- Srb->SrbStatus = SrbStatus;
- ScsiPortNotification(RequestComplete,
- HwDeviceExtension,
- Srb);
- }
- Irp = Irp->Tail.Overlay.DriverContext[1];
- }
- }
- Entry = Entry->Flink;
- }
-}
-
+ /* Get logical unit list head */
+ LunExtension = DeviceExtension->LunExtensionList[Target % 8];
-/*
- * @implemented
- */
-#undef ScsiPortConvertPhysicalAddressToUlong
-ULONG STDCALL
-ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
-{
- DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
- return(Address.u.LowPart);
+ /* Go through all logical units */
+ while (LunExtension)
+ {
+ /* Now match what caller asked with what we are at now */
+ if ((PathId == SP_UNTAGGED || PathId == LunExtension->PathId) &&
+ (TargetId == SP_UNTAGGED || TargetId == LunExtension->TargetId) &&
+ (Lun == SP_UNTAGGED || Lun == LunExtension->Lun))
+ {
+ /* Yes, that's what caller asked for. Complete abort requests */
+ if (LunExtension->CompletedAbortRequests)
+ {
+ /* TODO: Save SrbStatus in this request */
+ DPRINT1("Completing abort request without setting SrbStatus!\n");
+
+ /* Issue a notification request */
+ ScsiPortNotification(RequestComplete,
+ HwDeviceExtension,
+ LunExtension->CompletedAbortRequests);
+ }
+
+ /* Complete the request using our helper */
+ SpiCompleteRequest(HwDeviceExtension,
+ &LunExtension->SrbInfo,
+ SrbStatus);
+
+ /* Go through the queue and complete everything there too */
+ ListEntry = LunExtension->SrbInfo.Requests.Flink;
+ while (ListEntry != &LunExtension->SrbInfo.Requests)
+ {
+ /* Get the actual SRB info entry */
+ SrbInfo = CONTAINING_RECORD(ListEntry,
+ SCSI_REQUEST_BLOCK_INFO,
+ Requests);
+
+ /* Complete it */
+ SpiCompleteRequest(HwDeviceExtension,
+ SrbInfo,
+ SrbStatus);
+
+ /* Advance to the next request in queue */
+ ListEntry = SrbInfo->Requests.Flink;
+ }
+ }
+
+ /* Advance to the next one */
+ LunExtension = LunExtension->Next;
+ }
+ }
+ }
}
-
/*
* @unimplemented
*/
-VOID STDCALL
+VOID NTAPI
ScsiPortFlushDma(IN PVOID HwDeviceExtension)
{
DPRINT("ScsiPortFlushDma()\n");
/*
* @implemented
*/
-VOID STDCALL
+VOID NTAPI
ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
IN PVOID MappedAddress)
{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- PSCSI_PORT_DEVICE_BASE DeviceBase;
- PLIST_ENTRY Entry;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PMAPPED_ADDRESS NextMa, LastMa;
- DPRINT("ScsiPortFreeDeviceBase() called\n");
+ //DPRINT("ScsiPortFreeDeviceBase() called\n");
- DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
- SCSI_PORT_DEVICE_EXTENSION,
- MiniPortDeviceExtension);
- if (IsListEmpty(&DeviceExtension->DeviceBaseListHead))
- return;
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
+
+ /* Initialize our pointers */
+ NextMa = DeviceExtension->MappedAddressList;
+ LastMa = NextMa;
- Entry = DeviceExtension->DeviceBaseListHead.Flink;
- while (Entry != &DeviceExtension->DeviceBaseListHead)
+ while (NextMa)
{
- DeviceBase = CONTAINING_RECORD(Entry,
- SCSI_PORT_DEVICE_BASE,
- List);
- if (DeviceBase->MappedAddress == MappedAddress)
- {
- MmUnmapIoSpace(DeviceBase->MappedAddress,
- DeviceBase->NumberOfBytes);
- RemoveEntryList(Entry);
- ExFreePool(DeviceBase);
+ if (NextMa->MappedAddress == MappedAddress)
+ {
+ /* Unmap it first */
+ MmUnmapIoSpace(MappedAddress, NextMa->NumberOfBytes);
- return;
- }
+ /* Remove it from the list */
+ if (NextMa == DeviceExtension->MappedAddressList)
+ {
+ /* Remove the first entry */
+ DeviceExtension->MappedAddressList = NextMa->NextMappedAddress;
+ }
+ else
+ {
+ LastMa->NextMappedAddress = NextMa->NextMappedAddress;
+ }
- Entry = Entry->Flink;
+ /* Free the resources and quit */
+ ExFreePool(NextMa);
+
+ return;
+ }
+ else
+ {
+ LastMa = NextMa;
+ NextMa = NextMa->NextMappedAddress;
+ }
}
}
/*
* @implemented
*/
-ULONG STDCALL
+ULONG NTAPI
ScsiPortGetBusData(IN PVOID DeviceExtension,
IN ULONG BusDataType,
IN ULONG SystemIoBusNumber,
IN PVOID Buffer,
IN ULONG Length)
{
- return(HalGetBusData(BusDataType,
- SystemIoBusNumber,
- SlotNumber,
- Buffer,
- Length));
+ DPRINT("ScsiPortGetBusData()\n");
+
+ if (Length)
+ {
+ /* If Length is non-zero, just forward the call to
+ HalGetBusData() function */
+ return HalGetBusData(BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ Buffer,
+ Length);
+ }
+
+ /* We have a more complex case here */
+ UNIMPLEMENTED;
+ return 0;
}
+/*
+ * @implemented
+ */
+ULONG NTAPI
+ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
+ IN ULONG BusDataType,
+ IN ULONG SystemIoBusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length)
+{
+ DPRINT("ScsiPortSetBusDataByOffset()\n");
+ return HalSetBusDataByOffset(BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length);
+}
/*
* @implemented
*/
-PVOID STDCALL
+PVOID NTAPI
ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
IN INTERFACE_TYPE BusType,
IN ULONG SystemIoBusNumber,
IN ULONG NumberOfBytes,
IN BOOLEAN InIoSpace)
{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- PHYSICAL_ADDRESS TranslatedAddress;
- PSCSI_PORT_DEVICE_BASE DeviceBase;
- ULONG AddressSpace;
- PVOID MappedAddress;
-
- DPRINT ("ScsiPortGetDeviceBase() called\n");
-
- AddressSpace = (ULONG)InIoSpace;
- if (HalTranslateBusAddress(BusType,
- SystemIoBusNumber,
- IoAddress,
- &AddressSpace,
- &TranslatedAddress) == FALSE)
- return NULL;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PHYSICAL_ADDRESS TranslatedAddress;
+ PMAPPED_ADDRESS DeviceBase;
+ ULONG AddressSpace;
+ PVOID MappedAddress;
+
+ //DPRINT ("ScsiPortGetDeviceBase() called\n");
+
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
+
+ AddressSpace = (ULONG)InIoSpace;
+ if (HalTranslateBusAddress(BusType,
+ SystemIoBusNumber,
+ IoAddress,
+ &AddressSpace,
+ &TranslatedAddress) == FALSE)
+ {
+ return NULL;
+ }
- /* i/o space */
- if (AddressSpace != 0)
- return((PVOID)TranslatedAddress.u.LowPart);
+ /* i/o space */
+ if (AddressSpace != 0)
+ return((PVOID)(ULONG_PTR)TranslatedAddress.QuadPart);
- MappedAddress = MmMapIoSpace(TranslatedAddress,
- NumberOfBytes,
- MmNonCached);
+ MappedAddress = MmMapIoSpace(TranslatedAddress,
+ NumberOfBytes,
+ FALSE);
- DeviceBase = ExAllocatePool(NonPagedPool,
- sizeof(SCSI_PORT_DEVICE_BASE));
- if (DeviceBase == NULL)
- return(MappedAddress);
+ DeviceBase = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(MAPPED_ADDRESS), TAG_SCSIPORT);
- DeviceBase->MappedAddress = MappedAddress;
- DeviceBase->NumberOfBytes = NumberOfBytes;
- DeviceBase->IoAddress = IoAddress;
- DeviceBase->SystemIoBusNumber = SystemIoBusNumber;
+ if (DeviceBase == NULL)
+ return MappedAddress;
- DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
- SCSI_PORT_DEVICE_EXTENSION,
- MiniPortDeviceExtension);
+ DeviceBase->MappedAddress = MappedAddress;
+ DeviceBase->NumberOfBytes = NumberOfBytes;
+ DeviceBase->IoAddress = IoAddress;
+ DeviceBase->BusNumber = SystemIoBusNumber;
- InsertHeadList(&DeviceExtension->DeviceBaseListHead,
- &DeviceBase->List);
+ /* Link it to the Device Extension list */
+ DeviceBase->NextMappedAddress = DeviceExtension->MappedAddressList;
+ DeviceExtension->MappedAddressList = DeviceBase;
- return(MappedAddress);
+ return MappedAddress;
}
-
/*
- * @implemented
+ * @unimplemented
*/
-PVOID STDCALL
+PVOID NTAPI
ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
IN UCHAR PathId,
IN UCHAR TargetId,
IN UCHAR Lun)
{
+ UNIMPLEMENTED;
+#if 0
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
PSCSI_PORT_LUN_EXTENSION LunExtension;
PLIST_ENTRY Entry;
Entry = Entry->Flink;
}
-
+#endif
return NULL;
}
/*
- * @unimplemented
+ * @implemented
*/
-SCSI_PHYSICAL_ADDRESS STDCALL
+SCSI_PHYSICAL_ADDRESS NTAPI
ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
- IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
- IN PVOID VirtualAddress,
- OUT ULONG *Length)
+ IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
+ IN PVOID VirtualAddress,
+ OUT ULONG *Length)
{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- SCSI_PHYSICAL_ADDRESS PhysicalAddress;
- SCSI_PHYSICAL_ADDRESS NextPhysicalAddress;
- ULONG BufferLength = 0;
- ULONG Offset;
- PVOID EndAddress;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ SCSI_PHYSICAL_ADDRESS PhysicalAddress;
+ ULONG BufferLength = 0;
+ ULONG Offset;
+ PSCSI_SG_ADDRESS SGList;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo;
- DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
- HwDeviceExtension, Srb, VirtualAddress, Length);
+ DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
+ HwDeviceExtension, Srb, VirtualAddress, Length);
- DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
- SCSI_PORT_DEVICE_EXTENSION,
- MiniPortDeviceExtension);
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
- if (Length != NULL)
+ if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress)
{
- *Length = 0;
+ /* Simply look it up in the allocated common buffer */
+ Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer;
+
+ BufferLength = DeviceExtension->CommonBufferLength - Offset;
+ PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset;
}
- if (Srb == NULL)
+ else if (DeviceExtension->MapRegisters)
{
- EndAddress = (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + DeviceExtension->CommonBufferLength);
- if (VirtualAddress >= DeviceExtension->VirtualAddress && VirtualAddress < EndAddress)
- {
- Offset = (ULONG_PTR)VirtualAddress - (ULONG_PTR)DeviceExtension->VirtualAddress;
- PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset;
- BufferLength = (ULONG_PTR)EndAddress - (ULONG_PTR)VirtualAddress;
- }
- else
+ /* Scatter-gather list must be used */
+ SrbInfo = SpiGetSrbData(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ Srb->QueueTag);
+
+ SGList = SrbInfo->ScatterGather;
+
+ /* Find needed item in the SG list */
+ Offset = (PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer;
+ while (Offset >= SGList->Length)
{
- /*
- * The given virtual address is not within the range
- * of the drivers uncached extension or srb extension.
- */
- /*
- * FIXME:
- * Check if the address is a sense info buffer of an active srb.
- */
- PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
- if (PhysicalAddress.QuadPart == 0LL)
- {
- CHECKPOINT;
- return PhysicalAddress;
- }
- BufferLength = PAGE_SIZE - PhysicalAddress.u.LowPart % PAGE_SIZE;
- }
- }
- else
- {
- EndAddress = (PVOID)((ULONG_PTR)Srb->DataBuffer + Srb->DataTransferLength);
- if (VirtualAddress == NULL)
- {
- VirtualAddress = Srb->DataBuffer;
- }
- else if (VirtualAddress < Srb->DataBuffer || VirtualAddress >= EndAddress)
- {
- EndAddress = (PVOID)((ULONG_PTR)Srb->SenseInfoBuffer + Srb->SenseInfoBufferLength);
- if (VirtualAddress < Srb->SenseInfoBuffer || VirtualAddress >= EndAddress)
- {
- PhysicalAddress.QuadPart = 0LL;
- CHECKPOINT;
- return PhysicalAddress;
- }
- }
-
- PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
- if (PhysicalAddress.QuadPart == 0LL)
- {
- CHECKPOINT;
- return PhysicalAddress;
- }
+ Offset -= SGList->Length;
+ SGList++;
+ }
- BufferLength = PAGE_SIZE - (ULONG_PTR)VirtualAddress % PAGE_SIZE;
- while ((ULONG_PTR)VirtualAddress + BufferLength < (ULONG_PTR)EndAddress)
- {
- NextPhysicalAddress = MmGetPhysicalAddress((PVOID)((ULONG_PTR)VirtualAddress + BufferLength));
- if (PhysicalAddress.QuadPart + BufferLength != NextPhysicalAddress.QuadPart)
- {
- break;
- }
- BufferLength += PAGE_SIZE;
- }
- if ((ULONG_PTR)VirtualAddress + BufferLength >= (ULONG_PTR)EndAddress)
- {
- BufferLength = (ULONG)((ULONG_PTR)EndAddress - (ULONG_PTR)VirtualAddress);
- }
+ /* We're done, store length and physical address */
+ BufferLength = SGList->Length - Offset;
+ PhysicalAddress.QuadPart = SGList->PhysicalAddress.QuadPart + Offset;
}
- if (Length != NULL)
+ else
{
- *Length = BufferLength;
+ /* Nothing */
+ *Length = 0;
+ PhysicalAddress.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE);
}
- DPRINT("Address %I64x, Length %d\n", PhysicalAddress.QuadPart, BufferLength);
- return PhysicalAddress;
+
+ *Length = BufferLength;
+ return PhysicalAddress;
}
/*
* @unimplemented
*/
-PSCSI_REQUEST_BLOCK STDCALL
-ScsiPortGetSrb(IN PVOID HwDeviceExtension,
+PSCSI_REQUEST_BLOCK NTAPI
+ScsiPortGetSrb(IN PVOID DeviceExtension,
IN UCHAR PathId,
IN UCHAR TargetId,
IN UCHAR Lun,
/*
* @implemented
*/
-PVOID STDCALL
+PVOID NTAPI
ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
IN ULONG NumberOfBytes)
{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- DEVICE_DESCRIPTION DeviceDescription;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ DEVICE_DESCRIPTION DeviceDescription;
+ ULONG MapRegistersCount;
+ NTSTATUS Status;
- DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
- HwDeviceExtension, ConfigInfo, NumberOfBytes);
+ DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
+ HwDeviceExtension, ConfigInfo, NumberOfBytes);
- DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
- SCSI_PORT_DEVICE_EXTENSION,
- MiniPortDeviceExtension);
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
- /* Check for allocated common DMA buffer */
- if (DeviceExtension->VirtualAddress != NULL)
- {
- DPRINT1("The HBA has already got a common DMA buffer!\n");
- return NULL;
- }
-
- /* Check for DMA adapter object */
- if (DeviceExtension->AdapterObject == NULL)
- {
- /* Initialize DMA adapter description */
- RtlZeroMemory(&DeviceDescription,
- sizeof(DEVICE_DESCRIPTION));
- DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
- DeviceDescription.Master = ConfigInfo->Master;
- DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
- DeviceDescription.DemandMode = ConfigInfo->DemandMode;
- DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
- DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
- DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
- DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
- DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
- DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
- DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
- DeviceDescription.DmaPort = ConfigInfo->DmaPort;
-
- /* Get a DMA adapter object */
- DeviceExtension->AdapterObject = HalGetAdapter(&DeviceDescription,
- &DeviceExtension->MapRegisterCount);
- if (DeviceExtension->AdapterObject == NULL)
- {
- DPRINT1("HalGetAdapter() failed\n");
- return NULL;
- }
+ /* Check for allocated common DMA buffer */
+ if (DeviceExtension->SrbExtensionBuffer != NULL)
+ {
+ DPRINT1("The HBA has already got a common DMA buffer!\n");
+ return NULL;
}
- if (DeviceExtension->SrbExtensionSize > 0)
+
+ /* Check for DMA adapter object */
+ if (DeviceExtension->AdapterObject == NULL)
{
- PVOID Buffer;
- DeviceExtension->CurrentSrbExtensions = 0;
- if (DeviceExtension->PortConfig->MultipleRequestPerLu)
+ /* Initialize DMA adapter description */
+ RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ DeviceDescription.Master = ConfigInfo->Master;
+ DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
+ DeviceDescription.DemandMode = ConfigInfo->DemandMode;
+ DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
+ DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
+ DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
+ DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
+ DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
+ DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
+ DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
+ DeviceDescription.DmaPort = ConfigInfo->DmaPort;
+
+ /* Get a DMA adapter object */
+ DeviceExtension->AdapterObject =
+ HalGetAdapter(&DeviceDescription, &MapRegistersCount);
+
+ /* Fail in case of error */
+ if (DeviceExtension->AdapterObject == NULL)
{
- DeviceExtension->MaxSrbExtensions = 1024;
- }
- else
+ DPRINT1("HalGetAdapter() failed\n");
+ return NULL;
+ }
+
+ /* Set number of physical breaks */
+ if (ConfigInfo->NumberOfPhysicalBreaks != 0 &&
+ MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks)
{
- DeviceExtension->MaxSrbExtensions = 32;
- }
- Buffer = ExAllocatePool(NonPagedPool, ROUND_UP(DeviceExtension->MaxSrbExtensions / 8, sizeof(ULONG)));
- if (Buffer == NULL)
+ DeviceExtension->PortCapabilities.MaximumPhysicalPages =
+ ConfigInfo->NumberOfPhysicalBreaks;
+ }
+ else
{
- KEBUGCHECK(0);
- return NULL;
+ DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount;
}
- RtlInitializeBitMap(&DeviceExtension->SrbExtensionAllocMap, Buffer, DeviceExtension->MaxSrbExtensions);
- RtlClearAllBits(&DeviceExtension->SrbExtensionAllocMap);
}
- /* Allocate a common DMA buffer */
- DeviceExtension->CommonBufferLength =
- NumberOfBytes + PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * DeviceExtension->MaxSrbExtensions);
- DeviceExtension->VirtualAddress =
- HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
- DeviceExtension->CommonBufferLength,
- &DeviceExtension->PhysicalAddress,
- FALSE);
- if (DeviceExtension->VirtualAddress == NULL)
+ /* Update auto request sense feature */
+ DeviceExtension->SupportsAutoSense = ConfigInfo->AutoRequestSense;
+
+ /* Update Srb extension size */
+ if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize)
+ DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize;
+
+ /* Update Srb extension alloc flag */
+ if (ConfigInfo->AutoRequestSense || DeviceExtension->SrbExtensionSize)
+ DeviceExtension->NeedSrbExtensionAlloc = TRUE;
+
+ /* Allocate a common DMA buffer */
+ Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status);
+ return NULL;
+ }
+
+ return DeviceExtension->NonCachedExtension;
+}
+
+static NTSTATUS
+SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize)
+{
+ PVOID *SrbExtension, CommonBuffer;
+ ULONG CommonBufferLength, BufSize;
+
+ /* If size is 0, set it to 16 */
+ if (!DeviceExtension->SrbExtensionSize)
+ DeviceExtension->SrbExtensionSize = 16;
+
+ /* Calculate size */
+ BufSize = DeviceExtension->SrbExtensionSize;
+
+ /* Add autosense data size if needed */
+ if (DeviceExtension->SupportsAutoSense)
+ BufSize += sizeof(SENSE_DATA);
+
+
+ /* Round it */
+ BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
+
+ /* Sum up into the total common buffer length, and round it to page size */
+ CommonBufferLength =
+ ROUND_TO_PAGES(NonCachedSize + BufSize * DeviceExtension->RequestsNumber);
+
+ /* Allocate it */
+ if (!DeviceExtension->AdapterObject)
+ {
+ /* From nonpaged pool if there is no DMA */
+ CommonBuffer = ExAllocatePoolWithTag(NonPagedPool, CommonBufferLength, TAG_SCSIPORT);
+ }
+ else
+ {
+ /* Perform a full request since we have a DMA adapter*/
+ CommonBuffer = HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
+ CommonBufferLength,
+ &DeviceExtension->PhysicalAddress,
+ FALSE );
+ }
+
+ /* Fail in case of error */
+ if (!CommonBuffer)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Zero it */
+ RtlZeroMemory(CommonBuffer, CommonBufferLength);
+
+ /* Store its size in Device Extension */
+ DeviceExtension->CommonBufferLength = CommonBufferLength;
+
+ /* SrbExtension buffer is located at the beginning of the buffer */
+ DeviceExtension->SrbExtensionBuffer = CommonBuffer;
+
+ /* Non-cached extension buffer is located at the end of
+ the common buffer */
+ if (NonCachedSize)
+ {
+ CommonBufferLength -= NonCachedSize;
+ DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength;
+ }
+ else
+ {
+ DeviceExtension->NonCachedExtension = NULL;
+ }
+
+ if (DeviceExtension->NeedSrbExtensionAlloc)
{
- DPRINT1("HalAllocateCommonBuffer() failed!\n");
- DeviceExtension->CommonBufferLength = 0;
- return NULL;
+ /* Look up how many SRB data structures we need */
+ DeviceExtension->SrbDataCount = CommonBufferLength / BufSize;
+
+ /* Initialize the free SRB extensions list */
+ SrbExtension = (PVOID *)CommonBuffer;
+ DeviceExtension->FreeSrbExtensions = SrbExtension;
+
+ /* Fill the remainding pointers (if we have more than 1 SRB) */
+ while (CommonBufferLength >= 2 * BufSize)
+ {
+ *SrbExtension = (PVOID*)((PCHAR)SrbExtension + BufSize);
+ SrbExtension = *SrbExtension;
+
+ CommonBufferLength -= BufSize;
+ }
}
- return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress +
- PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * DeviceExtension->MaxSrbExtensions));
+ return STATUS_SUCCESS;
}
+
/*
* @implemented
*/
-PVOID STDCALL
+PVOID NTAPI
ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
- IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
+ IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- ULONG Offset;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ ULONG Offset;
- DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
- HwDeviceExtension, PhysicalAddress.QuadPart);
+ DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
+ HwDeviceExtension, PhysicalAddress.QuadPart);
- DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
- SCSI_PORT_DEVICE_EXTENSION,
- MiniPortDeviceExtension);
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
- if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
- return NULL;
+ if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
+ return NULL;
- Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
- if (Offset >= DeviceExtension->CommonBufferLength)
- return NULL;
+ Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
+
+ if (Offset >= DeviceExtension->CommonBufferLength)
+ return NULL;
+
+ return (PVOID)((ULONG_PTR)DeviceExtension->SrbExtensionBuffer + Offset);
+}
+
+static VOID
+SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo, PUNICODE_STRING RegistryPath)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING KeyName;
+ NTSTATUS Status;
+
+ /* Open the service key */
+ InitializeObjectAttributes(&ObjectAttributes,
+ RegistryPath,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = ZwOpenKey(&ConfigInfo->ServiceKey,
+ KEY_READ,
+ &ObjectAttributes);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath, Status);
+ ConfigInfo->ServiceKey = NULL;
+ }
+
+ /* If we could open driver's service key, then proceed to the Parameters key */
+ if (ConfigInfo->ServiceKey != NULL)
+ {
+ RtlInitUnicodeString(&KeyName, L"Parameters");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ ConfigInfo->ServiceKey,
+ (PSECURITY_DESCRIPTOR) NULL);
+
+ /* Try to open it */
+ Status = ZwOpenKey(&ConfigInfo->DeviceKey,
+ KEY_READ,
+ &ObjectAttributes);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* Yes, Parameters key exist, and it must be used instead of
+ the Service key */
+ ZwClose(ConfigInfo->ServiceKey);
+ ConfigInfo->ServiceKey = ConfigInfo->DeviceKey;
+ ConfigInfo->DeviceKey = NULL;
+ }
+ }
- return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + Offset);
+ if (ConfigInfo->ServiceKey != NULL)
+ {
+ /* Open the Device key */
+ RtlInitUnicodeString(&KeyName, L"Device");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ ConfigInfo->ServiceKey,
+ NULL);
+
+ /* We don't check for failure here - not needed */
+ ZwOpenKey(&ConfigInfo->DeviceKey,
+ KEY_READ,
+ &ObjectAttributes);
+ }
}
* @implemented
*/
-ULONG STDCALL
+ULONG NTAPI
ScsiPortInitialize(IN PVOID Argument1,
IN PVOID Argument2,
IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
IN PVOID HwContext)
{
- PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
-// PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- PCONFIGURATION_INFORMATION SystemConfig;
- PPORT_CONFIGURATION_INFORMATION PortConfig;
- ULONG DeviceExtensionSize;
- ULONG PortConfigSize;
- BOOLEAN Again;
- BOOLEAN DeviceFound = FALSE;
- ULONG i;
- ULONG Result;
- NTSTATUS Status;
- ULONG MaxBus;
- ULONG BusNumber;
- PCI_SLOT_NUMBER SlotNumber;
+ PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
+ PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL;
+ PCONFIGURATION_INFORMATION SystemConfig;
+ PPORT_CONFIGURATION_INFORMATION PortConfig;
+ PORT_CONFIGURATION_INFORMATION InitialPortConfig;
+ CONFIGURATION_INFO ConfigInfo;
+ ULONG DeviceExtensionSize;
+ ULONG PortConfigSize;
+ BOOLEAN Again;
+ BOOLEAN DeviceFound = FALSE;
+ BOOLEAN FirstConfigCall = TRUE;
+ ULONG Result;
+ NTSTATUS Status;
+ ULONG MaxBus;
+ ULONG BusNumber = 0;
+ PCI_SLOT_NUMBER SlotNumber;
+
+ PDEVICE_OBJECT PortDeviceObject;
+ WCHAR NameBuffer[80];
+ UNICODE_STRING DeviceName;
+ WCHAR DosNameBuffer[80];
+ UNICODE_STRING DosDeviceName;
+ PIO_SCSI_CAPABILITIES PortCapabilities;
+ ULONG MappedIrq;
+ KIRQL Dirql;
+ KAFFINITY Affinity;
+
+ PCM_RESOURCE_LIST ResourceList;
+ BOOLEAN Conflict;
+
+
+ DPRINT ("ScsiPortInitialize() called!\n");
+
+ /* Check params for validity */
+ if ((HwInitializationData->HwInitialize == NULL) ||
+ (HwInitializationData->HwStartIo == NULL) ||
+ (HwInitializationData->HwInterrupt == NULL) ||
+ (HwInitializationData->HwFindAdapter == NULL) ||
+ (HwInitializationData->HwResetBus == NULL))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
- PDEVICE_OBJECT PortDeviceObject;
- WCHAR NameBuffer[80];
- UNICODE_STRING DeviceName;
- WCHAR DosNameBuffer[80];
- UNICODE_STRING DosDeviceName;
- PIO_SCSI_CAPABILITIES PortCapabilities;
- ULONG MappedIrq;
- KIRQL Dirql;
- KAFFINITY Affinity;
+ /* Set handlers */
+ DriverObject->DriverStartIo = ScsiPortStartIo;
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
+ DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ScsiPortDeviceControl;
+ DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
+ /* Obtain configuration information */
+ SystemConfig = IoGetConfigurationInformation();
- DPRINT ("ScsiPortInitialize() called!\n");
-#if 0
- DPRINT1("HwInitializationDataSize: %d\n", HwInitializationData->HwInitializationDataSize);
- DPRINT1("AdapterInterfaceType: %d\n", HwInitializationData->AdapterInterfaceType);
- DPRINT1("HwInitialize: %x\n", HwInitializationData->HwInitialize);
- DPRINT1("HwStartIo: %x\n", HwInitializationData->HwStartIo);
- DPRINT1("HwInterrupt: %x\n", HwInitializationData->HwInterrupt);
- DPRINT1("HwFindAdapter: %x\n", HwInitializationData->HwFindAdapter);
- DPRINT1("HwResetBus: %x\n", HwInitializationData->HwResetBus);
- DPRINT1("HwDmaStarted: %x\n", HwInitializationData->HwDmaStarted);
- DPRINT1("HwAdapterState: %x\n", HwInitializationData->HwAdapterState);
- DPRINT1("DeviceExtensionSize: %d\n", HwInitializationData->DeviceExtensionSize);
- DPRINT1("SpecificLuExtensionSize: %d\n", HwInitializationData->SpecificLuExtensionSize);
- DPRINT1("SrbExtensionSize: %d\n", HwInitializationData->SrbExtensionSize);
- DPRINT1("NumberOfAccessRanges: %d\n", HwInitializationData->NumberOfAccessRanges);
- DPRINT1("Reserved: %x\n", HwInitializationData->Reserved);
- DPRINT1("MapBuffers: %d\n", HwInitializationData->MapBuffers);
- DPRINT1("NeedPhysicalAddresses: %d\n", HwInitializationData->NeedPhysicalAddresses);
- DPRINT1("TaggedQueueing: %d\n", HwInitializationData->TaggedQueueing);
- DPRINT1("AutoRequestSense: %d\n", HwInitializationData->AutoRequestSense);
- DPRINT1("MultipleRequestPerLu: %d\n", HwInitializationData->MultipleRequestPerLu);
- DPRINT1("ReceiveEvent: %d\n", HwInitializationData->ReceiveEvent);
- DPRINT1("VendorIdLength: %d\n", HwInitializationData->VendorIdLength);
- DPRINT1("VendorId: %x\n", HwInitializationData->VendorId);
- DPRINT1("ReservedUshort: %d\n", HwInitializationData->ReservedUshort);
- DPRINT1("DeviceIdLength: %d\n", HwInitializationData->DeviceIdLength);
- DPRINT1("DeviceId: %x\n", HwInitializationData->DeviceId);
-#endif
- if ((HwInitializationData->HwInitialize == NULL) ||
- (HwInitializationData->HwStartIo == NULL) ||
- (HwInitializationData->HwInterrupt == NULL) ||
- (HwInitializationData->HwFindAdapter == NULL) ||
- (HwInitializationData->HwResetBus == NULL))
- return(STATUS_INVALID_PARAMETER);
-
- DriverObject->DriverStartIo = NULL;
- DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
- DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
- DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
- DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
-
- SystemConfig = IoGetConfigurationInformation();
-
- DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
- HwInitializationData->DeviceExtensionSize;
- PortConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION) +
- HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE);
-
-
- MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
- DPRINT("MaxBus: %lu\n", MaxBus);
-
- PortDeviceObject = NULL;
- BusNumber = 0;
- SlotNumber.u.AsULONG = 0;
- while (TRUE)
- {
- /* Create a unicode device name */
- swprintf (NameBuffer,
- L"\\Device\\ScsiPort%lu",
- SystemConfig->ScsiPortCount);
- RtlInitUnicodeString (&DeviceName,
- NameBuffer);
-
- DPRINT("Creating device: %wZ\n", &DeviceName);
-
- /* Create the port device */
- Status = IoCreateDevice (DriverObject,
- DeviceExtensionSize,
- &DeviceName,
- FILE_DEVICE_CONTROLLER,
- 0,
- FALSE,
- &PortDeviceObject);
- if (!NT_SUCCESS(Status))
- {
- DbgPrint ("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
- PortDeviceObject = NULL;
- goto ByeBye;
- }
+ /* Zero the internal configuration info structure */
+ RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO));
- DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
-
- /* Increase the stacksize. We reenter our device on IOCTL_SCSI_MINIPORT */
- PortDeviceObject->StackSize++;
-
- /* Set the buffering strategy here... */
- PortDeviceObject->Flags |= DO_DIRECT_IO;
- PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
-
- DeviceExtension = PortDeviceObject->DeviceExtension;
- RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
- DeviceExtension->Length = DeviceExtensionSize;
- DeviceExtension->DeviceObject = PortDeviceObject;
- DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
-
- DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
- DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
- DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
- DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
- DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
-
- DeviceExtension->AdapterObject = NULL;
- DeviceExtension->MapRegisterCount = 0;
- DeviceExtension->PhysicalAddress.QuadPart = 0ULL;
- DeviceExtension->VirtualAddress = NULL;
- DeviceExtension->CommonBufferLength = 0;
-
- /* Initialize the device base list */
- InitializeListHead (&DeviceExtension->DeviceBaseListHead);
-
- /* Initialize the irp lists */
- InitializeListHead (&DeviceExtension->PendingIrpListHead);
- DeviceExtension->NextIrp = NULL;
- DeviceExtension->PendingIrpCount = 0;
- DeviceExtension->ActiveIrpCount = 0;
-
- /* Initialize LUN-Extension list */
- InitializeListHead (&DeviceExtension->LunExtensionListHead);
-
- /* Initialize the spin lock in the controller extension */
- KeInitializeSpinLock (&DeviceExtension->Lock);
-
- /* Initialize the DPC object */
- IoInitializeDpcRequest (PortDeviceObject,
- ScsiPortDpc);
-
- /* Initialize the device timer */
- DeviceExtension->TimerState = IDETimerIdle;
- DeviceExtension->TimerCount = 0;
- IoInitializeTimer (PortDeviceObject,
- ScsiPortIoTimer,
- DeviceExtension);
-
- /* Allocate and initialize port configuration info */
- DeviceExtension->PortConfig = ExAllocatePool (NonPagedPool,
- PortConfigSize);
- if (DeviceExtension->PortConfig == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ByeBye;
- }
- RtlZeroMemory (DeviceExtension->PortConfig,
- PortConfigSize);
-
- PortConfig = DeviceExtension->PortConfig;
- PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
- PortConfig->SystemIoBusNumber = BusNumber;
- PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
- PortConfig->InterruptMode =
- (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
- PortConfig->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
- PortConfig->NumberOfPhysicalBreaks = SP_UNINITIALIZED_VALUE;
- PortConfig->DmaChannel = SP_UNINITIALIZED_VALUE;
- PortConfig->DmaPort = SP_UNINITIALIZED_VALUE;
- PortConfig->DmaWidth = 0;
- PortConfig->DmaSpeed = Compatible;
- PortConfig->AlignmentMask = 0;
- PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
- PortConfig->NumberOfBuses = 0;
-
- for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
- PortConfig->InitiatorBusId[i] = 255;
-
- PortConfig->ScatterGather = FALSE;
- PortConfig->Master = FALSE;
- PortConfig->CachesData = FALSE;
- PortConfig->AdapterScansDown = FALSE;
- PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
- PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
- PortConfig->Dma32BitAddresses = FALSE;
- PortConfig->DemandMode = FALSE;
- PortConfig->MapBuffers = HwInitializationData->MapBuffers;
- PortConfig->NeedPhysicalAddresses = HwInitializationData->NeedPhysicalAddresses;
- PortConfig->TaggedQueuing = HwInitializationData->TaggedQueuing;
- PortConfig->AutoRequestSense = HwInitializationData->AutoRequestSense;
- PortConfig->MultipleRequestPerLu = HwInitializationData->MultipleRequestPerLu;
- PortConfig->ReceiveEvent = HwInitializationData->ReceiveEvent;
- PortConfig->RealModeInitialized = FALSE;
- PortConfig->BufferAccessScsiPortControlled = FALSE;
- PortConfig->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS;
-// PortConfig->MaximumNumberOfLogicalUnits = SCSI_MAXIMUM_LOGICAL_UNITS;
-
- PortConfig->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
- PortConfig->SpecificLuExtensionSize = HwInitializationData->SpecificLuExtensionSize;
-
- PortConfig->AccessRanges = (ACCESS_RANGE(*)[])(PortConfig + 1);
+ /* Zero starting slot number */
+ SlotNumber.u.AsULONG = 0;
- /* Search for matching PCI device */
- if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
- (HwInitializationData->VendorIdLength > 0) &&
- (HwInitializationData->VendorId != NULL) &&
- (HwInitializationData->DeviceIdLength > 0) &&
- (HwInitializationData->DeviceId != NULL))
- {
- /* Get PCI device data */
- DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
- HwInitializationData->VendorIdLength,
- HwInitializationData->VendorId,
- HwInitializationData->DeviceIdLength,
- HwInitializationData->DeviceId);
-
- if (!SpiGetPciConfigData (HwInitializationData,
- PortConfig,
- BusNumber,
- &SlotNumber))
- {
- Status = STATUS_UNSUCCESSFUL;
- goto ByeBye;
- }
- }
+ /* Allocate space for access ranges */
+ if (HwInitializationData->NumberOfAccessRanges)
+ {
+ ConfigInfo.AccessRanges =
+ ExAllocatePoolWithTag(PagedPool,
+ HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT);
- /* Note: HwFindAdapter is called once for each bus */
- Again = FALSE;
- DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
- Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension,
- HwContext,
- 0, /* BusInformation */
- "", /* ArgumentString */
- PortConfig,
- &Again);
- DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
- Result, (Again) ? "True" : "False");
+ /* Fail if failed */
+ if (ConfigInfo.AccessRanges == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
- if (Result == SP_RETURN_FOUND)
- {
- DPRINT("ScsiPortInitialize(): Found HBA! (%x)\n", PortConfig->BusInterruptVector);
+ /* Open registry keys */
+ SpiInitOpenKeys(&ConfigInfo, (PUNICODE_STRING)Argument2);
-#if 0
- DPRINT1("SystemIoBusNumber: %x\n", PortConfig->SystemIoBusNumber);
- DPRINT1("AdapterInterfaceType: %x\n", PortConfig->AdapterInterfaceType);
- DPRINT1("BusInterruptLevel: %x\n", PortConfig->BusInterruptLevel);
- DPRINT1("BusInterruptVector: %x\n", PortConfig->BusInterruptVector);
- DPRINT1("InterruptMode: %x\n", PortConfig->InterruptMode);
- DPRINT1("MaximumTransferLength: %x\n", PortConfig->MaximumTransferLength);
- DPRINT1("NumberOfPhysicalBreaks: %x\n", PortConfig->NumberOfPhysicalBreaks);
- DPRINT1("DmaChannel: %x\n", PortConfig->DmaChannel);
- DPRINT1("DmaPort: %d\n", PortConfig->DmaPort);
- DPRINT1("DmaWidth: %d\n", PortConfig->DmaWidth);
- DPRINT1("DmaSpeed: %d\n", PortConfig->DmaSpeed);
- DPRINT1("AlignmentMask: %d\n", PortConfig->AlignmentMask);
- DPRINT1("NumberOfAccessRanges: %d\n", PortConfig->NumberOfAccessRanges);
- DPRINT1("NumberOfBuses: %d\n", PortConfig->NumberOfBuses);
- DPRINT1("ScatterGather: %d\n", PortConfig->ScatterGather);
- DPRINT1("Master: %d\n", PortConfig->Master);
- DPRINT1("CachesData: %d\n", PortConfig->CachesData);
- DPRINT1("AdapterScansDown: %d\n", PortConfig->AdapterScansDown);
- DPRINT1("AtdiskPrimaryClaimed: %d\n", PortConfig->AtdiskPrimaryClaimed);
- DPRINT1("AtdiskSecondaryClaimed: %d\n", PortConfig->AtdiskSecondaryClaimed);
- DPRINT1("Dma32BitAddresses: %d\n", PortConfig->Dma32BitAddresses);
- DPRINT1("DemandMode: %d\n", PortConfig->DemandMode);
- DPRINT1("MapBuffers: %d\n", PortConfig->MapBuffers);
- DPRINT1("NeedPhysicalAddresses: %d\n", PortConfig->NeedPhysicalAddresses);
- DPRINT1("TaggedQueuing: %d\n", PortConfig->TaggedQueuing);
- DPRINT1("AutoRequestSense: %d\n", PortConfig->AutoRequestSense);
- DPRINT1("MultipleRequestPerLu: %d\n", PortConfig->MultipleRequestPerLu);
- DPRINT1("ReceiveEvent: %d\n", PortConfig->ReceiveEvent);
- DPRINT1("RealModeInitialized: %d\n", PortConfig->RealModeInitialized);
- DPRINT1("BufferAccessScsiPortControlled: %d\n", PortConfig->BufferAccessScsiPortControlled);
- DPRINT1("MaximumNumberOfTargets: %d\n", PortConfig->MaximumNumberOfTargets);
- DPRINT1("SlotNumber: %d\n", PortConfig->SlotNumber);
- DPRINT1("BusInterruptLevel2: %x\n", PortConfig->BusInterruptLevel2);
- DPRINT1("BusInterruptVector2: %x\n", PortConfig->BusInterruptVector2);
- DPRINT1("InterruptMode2: %x\n", PortConfig->InterruptMode2);
- DPRINT1("DmaChannel2: %d\n", PortConfig->DmaChannel2);
- DPRINT1("DmaPort2: %d\n", PortConfig->DmaPort2);
- DPRINT1("DmaWidth2: %d\n", PortConfig->DmaWidth2);
- DPRINT1("DmaSpeed2: %d\n", PortConfig->DmaSpeed2);
- DPRINT1("DeviceExtensionSize: %d\n", PortConfig->DeviceExtensionSize);
- DPRINT1("SpecificLuExtensionSize: %d\n", PortConfig->SpecificLuExtensionSize);
- DPRINT1("SrbExtensionSize: %d\n", PortConfig->SrbExtensionSize);
+ /* Last adapter number = not known */
+ ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE;
-#endif
+ /* Calculate sizes of DeviceExtension and PortConfig */
+ DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
+ HwInitializationData->DeviceExtensionSize;
- if (DeviceExtension->VirtualAddress == NULL && DeviceExtension->SrbExtensionSize)
- {
- ScsiPortGetUncachedExtension(&DeviceExtension->MiniPortDeviceExtension,
- PortConfig,
- 0);
- }
+ MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
+ DPRINT("MaxBus: %lu\n", MaxBus);
- /* Register an interrupt handler for this device */
- MappedIrq = HalGetInterruptVector(PortConfig->AdapterInterfaceType,
- PortConfig->SystemIoBusNumber,
- PortConfig->BusInterruptLevel,
-#if 1
-/*
- * FIXME:
- * Something is wrong in our interrupt conecting code.
- * The promise Ultra100TX driver returns 0 for BusInterruptVector
- * and a nonzero value for BusInterruptLevel. The driver does only
- * work with this fix.
- */
- PortConfig->BusInterruptLevel,
-#else
- PortConfig->BusInterruptVector,
-#endif
- &Dirql,
- &Affinity);
- DPRINT("AdapterInterfaceType %x, SystemIoBusNumber %x, BusInterruptLevel %x, BusInterruptVector %x\n",
- PortConfig->AdapterInterfaceType, PortConfig->SystemIoBusNumber,
- PortConfig->BusInterruptLevel, PortConfig->BusInterruptVector);
- Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
- ScsiPortIsr,
- DeviceExtension,
- NULL,
- MappedIrq,
- Dirql,
- Dirql,
- PortConfig->InterruptMode,
- TRUE,
- Affinity,
- FALSE);
- if (!NT_SUCCESS(Status))
- {
- DbgPrint("Could not connect interrupt %d\n",
- PortConfig->BusInterruptVector);
- goto ByeBye;
- }
+ while (TRUE)
+ {
+ /* Create a unicode device name */
+ swprintf(NameBuffer,
+ L"\\Device\\ScsiPort%lu",
+ SystemConfig->ScsiPortCount);
+ RtlInitUnicodeString(&DeviceName, NameBuffer);
+
+ DPRINT("Creating device: %wZ\n", &DeviceName);
+
+ /* Create the port device */
+ Status = IoCreateDevice(DriverObject,
+ DeviceExtensionSize,
+ &DeviceName,
+ FILE_DEVICE_CONTROLLER,
+ 0,
+ FALSE,
+ &PortDeviceObject);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
+ PortDeviceObject = NULL;
+ break;
+ }
- if (!(HwInitializationData->HwInitialize)(&DeviceExtension->MiniPortDeviceExtension))
- {
- DbgPrint("HwInitialize() failed!");
- Status = STATUS_UNSUCCESSFUL;
- goto ByeBye;
- }
+ DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
+
+ /* Set the buffering strategy here... */
+ PortDeviceObject->Flags |= DO_DIRECT_IO;
+ PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */
+
+ /* Fill Device Extension */
+ DeviceExtension = PortDeviceObject->DeviceExtension;
+ DeviceExtension->Length = DeviceExtensionSize;
+ DeviceExtension->DeviceObject = PortDeviceObject;
+ DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
+
+ /* Driver's routines... */
+ DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
+ DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
+ DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
+ DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
+ DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
+
+ /* Extensions sizes */
+ DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
+ DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
+ DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
+
+ /* Round Srb extension size to the quadword */
+ DeviceExtension->SrbExtensionSize =
+ ~(sizeof(LONGLONG) - 1) & (DeviceExtension->SrbExtensionSize +
+ sizeof(LONGLONG) - 1);
+
+ /* Fill some numbers (bus count, lun count, etc) */
+ DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
+ DeviceExtension->RequestsNumber = 16;
+
+ /* Initialize the spin lock in the controller extension */
+ KeInitializeSpinLock(&DeviceExtension->IrqLock);
+ KeInitializeSpinLock(&DeviceExtension->SpinLock);
+
+ /* Initialize the DPC object */
+ IoInitializeDpcRequest(PortDeviceObject,
+ ScsiPortDpcForIsr);
+
+ /* Initialize the device timer */
+ DeviceExtension->TimerCount = -1;
+ IoInitializeTimer(PortDeviceObject,
+ ScsiPortIoTimer,
+ DeviceExtension);
+
+ /* Initialize miniport timer */
+ KeInitializeTimer(&DeviceExtension->MiniportTimer);
+ KeInitializeDpc(&DeviceExtension->MiniportTimerDpc,
+ SpiMiniportTimerDpc,
+ PortDeviceObject);
+
+CreatePortConfig:
+
+ Status = SpiCreatePortConfig(DeviceExtension,
+ HwInitializationData,
+ &ConfigInfo,
+ &InitialPortConfig,
+ FirstConfigCall);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status);
+ break;
+ }
- /* Initialize port capabilities */
- DeviceExtension->PortCapabilities = ExAllocatePool(NonPagedPool,
- sizeof(IO_SCSI_CAPABILITIES));
- if (DeviceExtension->PortCapabilities == NULL)
- {
- DbgPrint("Failed to allocate port capabilities!\n");
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ByeBye;
- }
+ /* Allocate and initialize port configuration info */
+ PortConfigSize = (sizeof(PORT_CONFIGURATION_INFORMATION) +
+ HwInitializationData->NumberOfAccessRanges *
+ sizeof(ACCESS_RANGE) + 7) & ~7;
+ DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT);
- PortCapabilities = DeviceExtension->PortCapabilities;
- PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
- if (PortConfig->ScatterGather == FALSE ||
- PortConfig->NumberOfPhysicalBreaks >= (0x100000000LL >> PAGE_SHIFT) ||
- PortConfig->MaximumTransferLength < PortConfig->NumberOfPhysicalBreaks * PAGE_SIZE)
- {
- PortCapabilities->MaximumTransferLength =
- PortConfig->MaximumTransferLength;
- }
- else
- {
- PortCapabilities->MaximumTransferLength =
- PortConfig->NumberOfPhysicalBreaks * PAGE_SIZE;
- }
+ /* Fail if failed */
+ if (DeviceExtension->PortConfig == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
- PortCapabilities->MaximumPhysicalPages =
- PortCapabilities->MaximumTransferLength / PAGE_SIZE;
- PortCapabilities->SupportedAsynchronousEvents = 0; /* FIXME */
- PortCapabilities->AlignmentMask =
- PortConfig->AlignmentMask;
- PortCapabilities->TaggedQueuing =
- PortConfig->TaggedQueuing;
- PortCapabilities->AdapterScansDown =
- PortConfig->AdapterScansDown;
- PortCapabilities->AdapterUsesPio = TRUE; /* FIXME */
-
- /* Scan the adapter for devices */
- SpiScanAdapter (DeviceExtension);
-
- /* Build the registry device map */
- SpiBuildDeviceMap (DeviceExtension,
- (PUNICODE_STRING)Argument2);
-
- /* Create the dos device link */
- swprintf(DosNameBuffer,
- L"\\??\\Scsi%lu:",
- SystemConfig->ScsiPortCount);
- RtlInitUnicodeString(&DosDeviceName,
- DosNameBuffer);
- IoCreateSymbolicLink(&DosDeviceName,
- &DeviceName);
-
- /* Update the system configuration info */
- if (PortConfig->AtdiskPrimaryClaimed == TRUE)
- SystemConfig->AtDiskPrimaryAddressClaimed = TRUE;
- if (PortConfig->AtdiskSecondaryClaimed == TRUE)
- SystemConfig->AtDiskSecondaryAddressClaimed = TRUE;
-
- SystemConfig->ScsiPortCount++;
- PortDeviceObject = NULL;
- DeviceFound = TRUE;
- }
+ PortConfig = DeviceExtension->PortConfig;
+
+ /* Copy information here */
+ RtlCopyMemory(PortConfig,
+ &InitialPortConfig,
+ sizeof(PORT_CONFIGURATION_INFORMATION));
+
+
+ /* Copy extension sizes into the PortConfig */
+ PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize;
+ PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize;
+
+ /* Initialize Access ranges */
+ if (HwInitializationData->NumberOfAccessRanges != 0)
+ {
+ PortConfig->AccessRanges = (PVOID)(PortConfig+1);
+
+ /* Align to LONGLONG */
+ PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) + 7);
+ PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) & ~7);
+
+ /* Copy the data */
+ RtlCopyMemory(PortConfig->AccessRanges,
+ ConfigInfo.AccessRanges,
+ HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
+ }
+
+ /* Search for matching PCI device */
+ if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
+ (HwInitializationData->VendorIdLength > 0) &&
+ (HwInitializationData->VendorId != NULL) &&
+ (HwInitializationData->DeviceIdLength > 0) &&
+ (HwInitializationData->DeviceId != NULL))
+ {
+ PortConfig->BusInterruptLevel = 0;
+
+ /* Get PCI device data */
+ DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
+ HwInitializationData->VendorIdLength,
+ HwInitializationData->VendorId,
+ HwInitializationData->DeviceIdLength,
+ HwInitializationData->DeviceId);
+
+ if (!SpiGetPciConfigData(DriverObject,
+ PortDeviceObject,
+ HwInitializationData,
+ PortConfig,
+ RegistryPath,
+ ConfigInfo.BusNumber,
+ &SlotNumber))
+ {
+ /* Continue to the next bus, nothing here */
+ ConfigInfo.BusNumber++;
+ DeviceExtension->PortConfig = NULL;
+ ExFreePool(PortConfig);
+ Again = FALSE;
+ goto CreatePortConfig;
+ }
+
+ if (!PortConfig->BusInterruptLevel)
+ {
+ /* Bypass this slot, because no interrupt was assigned */
+ DeviceExtension->PortConfig = NULL;
+ ExFreePool(PortConfig);
+ goto CreatePortConfig;
+ }
+ }
else
- {
- DPRINT("HwFindAdapter() Result: %lu\n", Result);
+ {
+ DPRINT("Non-pci bus\n");
+ }
- ExFreePool (PortConfig);
- IoDeleteDevice (PortDeviceObject);
- PortDeviceObject = NULL;
- }
+ /* Note: HwFindAdapter is called once for each bus */
+ Again = FALSE;
+ DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
+ Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension,
+ HwContext,
+ 0, /* BusInformation */
+ ConfigInfo.Parameter, /* ArgumentString */
+ PortConfig,
+ &Again);
+
+ DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
+ Result, (Again) ? "True" : "False");
+
+ /* Free MapRegisterBase, it's not needed anymore */
+ if (DeviceExtension->MapRegisterBase != NULL)
+ {
+ ExFreePool(DeviceExtension->MapRegisterBase);
+ DeviceExtension->MapRegisterBase = NULL;
+ }
+
+ /* If result is nothing good... */
+ if (Result != SP_RETURN_FOUND)
+ {
+ DPRINT("HwFindAdapter() Result: %lu\n", Result);
+
+ if (Result == SP_RETURN_NOT_FOUND)
+ {
+ /* We can continue on the next bus */
+ ConfigInfo.BusNumber++;
+ Again = FALSE;
+
+ DeviceExtension->PortConfig = NULL;
+ ExFreePool(PortConfig);
+ goto CreatePortConfig;
+ }
+
+ /* Otherwise, break */
+ Status = STATUS_INTERNAL_ERROR;
+ break;
+ }
+
+ DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
+ PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]);
+
+ /* If the SRB extension size was updated */
+ if (!DeviceExtension->NonCachedExtension &&
+ (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize))
+ {
+ /* Set it (rounding to LONGLONG again) */
+ DeviceExtension->SrbExtensionSize =
+ (PortConfig->SrbExtensionSize +
+ sizeof(LONGLONG)) & ~(sizeof(LONGLONG) - 1);
+ }
+
+ /* The same with LUN extension size */
+ if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize)
+ DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize;
+
+
+ if (!((HwInitializationData->AdapterInterfaceType == PCIBus) &&
+ (HwInitializationData->VendorIdLength > 0) &&
+ (HwInitializationData->VendorId != NULL) &&
+ (HwInitializationData->DeviceIdLength > 0) &&
+ (HwInitializationData->DeviceId != NULL)))
+ {
+ /* Construct a resource list */
+ ResourceList = SpiConfigToResource(DeviceExtension,
+ PortConfig);
+
+ if (ResourceList)
+ {
+ UNICODE_STRING UnicodeString;
+ RtlInitUnicodeString(&UnicodeString, L"ScsiAdapter");
+ DPRINT("Reporting resources\n");
+ Status = IoReportResourceUsage(&UnicodeString,
+ DriverObject,
+ NULL,
+ 0,
+ PortDeviceObject,
+ ResourceList,
+ FIELD_OFFSET(CM_RESOURCE_LIST,
+ List[0].PartialResourceList.PartialDescriptors) +
+ ResourceList->List[0].PartialResourceList.Count
+ * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ FALSE,
+ &Conflict);
+ ExFreePool(ResourceList);
+
+ /* In case of a failure or a conflict, break */
+ if (Conflict || (!NT_SUCCESS(Status)))
+ {
+ if (Conflict)
+ Status = STATUS_CONFLICTING_ADDRESSES;
+ break;
+ }
+ }
+ }
+
+ /* Reset the Conflict var */
+ Conflict = FALSE;
+
+ /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
+ if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
+ DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
+ else
+ DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets;
+
+ DeviceExtension->BusNum = PortConfig->NumberOfBuses;
+ DeviceExtension->CachesData = PortConfig->CachesData;
+ DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent;
+ DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing;
+ DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu;
+
+ /* If something was disabled via registry - apply it */
+ if (ConfigInfo.DisableMultipleLun)
+ DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE;
+
+ if (ConfigInfo.DisableTaggedQueueing)
+ DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE;
+
+ /* Check if we need to alloc SRB data */
+ if (DeviceExtension->SupportsTaggedQueuing ||
+ DeviceExtension->MultipleReqsPerLun)
+ {
+ DeviceExtension->NeedSrbDataAlloc = TRUE;
+ }
+ else
+ {
+ DeviceExtension->NeedSrbDataAlloc = FALSE;
+ }
+
+ /* Get a pointer to the port capabilities */
+ PortCapabilities = &DeviceExtension->PortCapabilities;
+
+ /* Copy one field there */
+ DeviceExtension->MapBuffers = PortConfig->MapBuffers;
+ PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers;
+
+ if (DeviceExtension->AdapterObject == NULL &&
+ (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master))
+ {
+ DPRINT1("DMA is not supported yet\n");
+ ASSERT(FALSE);
+ }
+
+ if (DeviceExtension->SrbExtensionBuffer == NULL &&
+ (DeviceExtension->SrbExtensionSize != 0 ||
+ PortConfig->AutoRequestSense))
+ {
+ DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense;
+ DeviceExtension->NeedSrbExtensionAlloc = TRUE;
+
+ /* Allocate common buffer */
+ Status = SpiAllocateCommonBuffer(DeviceExtension, 0);
+
+ /* Check for failure */
+ if (!NT_SUCCESS(Status))
+ break;
+ }
+
+ /* Allocate SrbData, if needed */
+ if (DeviceExtension->NeedSrbDataAlloc)
+ {
+ ULONG Count;
+ PSCSI_REQUEST_BLOCK_INFO SrbData;
+
+ if (DeviceExtension->SrbDataCount != 0)
+ Count = DeviceExtension->SrbDataCount;
+ else
+ Count = DeviceExtension->RequestsNumber * 2;
+
+ /* Allocate the data */
+ SrbData = ExAllocatePoolWithTag(NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT);
+ if (SrbData == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO));
+
+ DeviceExtension->SrbInfo = SrbData;
+ DeviceExtension->FreeSrbInfo = SrbData;
+ DeviceExtension->SrbDataCount = Count;
+
+ /* Link it to the list */
+ while (Count > 0)
+ {
+ SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1);
+ SrbData++;
+ Count--;
+ }
+
+ /* Mark the last entry of the list */
+ SrbData--;
+ SrbData->Requests.Flink = NULL;
+ }
+
+ /* Initialize port capabilities */
+ PortCapabilities = &DeviceExtension->PortCapabilities;
+ PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
+ PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength;
+
+ if (PortConfig->ReceiveEvent)
+ PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION;
+
+ PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing;
+ PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown;
+
+ if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement)
+ PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask;
+
+ PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement;
+
+ if (PortCapabilities->MaximumPhysicalPages == 0)
+ {
+ PortCapabilities->MaximumPhysicalPages =
+ BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength);
+
+ /* Apply miniport's limits */
+ if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages)
+ {
+ PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks;
+ }
+ }
+
+ /* Deal with interrupts */
+ if (DeviceExtension->HwInterrupt == NULL ||
+ (PortConfig->BusInterruptLevel == 0 && PortConfig->BusInterruptVector == 0))
+ {
+ /* No interrupts */
+ KeInitializeSpinLock(&DeviceExtension->IrqLock);
+
+ /* FIXME: Use synchronization routine */
+ ASSERT("No interrupts branch requires changes in synchronization\n");
+
+ DeviceExtension->Interrupt = (PVOID)DeviceExtension;
+ DPRINT("No interrupts\n");
+
+ }
+ else
+ {
+ /* Are 2 interrupts needed? */
+ if (DeviceExtension->HwInterrupt != NULL &&
+ (PortConfig->BusInterruptLevel != 0 || PortConfig->BusInterruptVector != 0) &&
+ (PortConfig->BusInterruptLevel2 != 0 || PortConfig->BusInterruptVector2 != 0))
+ {
+ DPRINT1("2 interrupts requested! Not yet supported\n");
+ ASSERT(FALSE);
+ }
+ else
+ {
+ BOOLEAN InterruptShareable;
+
+ /* No, only 1 interrupt */
+ DPRINT("1 interrupt, IRQ is %d\n", PortConfig->BusInterruptLevel);
+
+ DeviceExtension->InterruptLevel = PortConfig->BusInterruptLevel;
+
+ /* Register an interrupt handler for this device */
+ MappedIrq = HalGetInterruptVector(PortConfig->AdapterInterfaceType,
+ PortConfig->SystemIoBusNumber,
+ PortConfig->BusInterruptLevel,
+ PortConfig->BusInterruptVector,
+ &Dirql,
+ &Affinity);
+
+ /* Determing IRQ sharability as usual */
+ if (PortConfig->AdapterInterfaceType == MicroChannel ||
+ PortConfig->InterruptMode == LevelSensitive)
+ {
+ InterruptShareable = TRUE;
+ }
+ else
+ {
+ InterruptShareable = FALSE;
+ }
+
+ Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
+ (PKSERVICE_ROUTINE)ScsiPortIsr,
+ DeviceExtension,
+ NULL,
+ MappedIrq,
+ Dirql,
+ Dirql,
+ PortConfig->InterruptMode,
+ InterruptShareable,
+ Affinity,
+ FALSE);
+
+ if (!(NT_SUCCESS(Status)))
+ {
+ DPRINT1("Could not connect interrupt %d\n",
+ PortConfig->BusInterruptVector);
+ DeviceExtension->Interrupt = NULL;
+ break;
+ }
+
+ }
+ }
+
+ /* Save IoAddress (from access ranges) */
+ if (HwInitializationData->NumberOfAccessRanges != 0)
+ {
+ DeviceExtension->IoAddress =
+ ((*(PortConfig->AccessRanges))[0]).RangeStart.LowPart;
+
+ DPRINT("Io Address %x\n", DeviceExtension->IoAddress);
+ }
+
+ /* Set flag that it's allowed to disconnect during this command */
+ DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
+
+ /* Initialize counter of active requests (-1 means there are none) */
+ DeviceExtension->ActiveRequestCounter = -1;
+
+ /* Analyze what we have about DMA */
+ if (DeviceExtension->AdapterObject != NULL &&
+ PortConfig->Master &&
+ PortConfig->NeedPhysicalAddresses)
+ {
+ DeviceExtension->MapRegisters = TRUE;
+ }
+ else
+ {
+ DeviceExtension->MapRegisters = FALSE;
+ }
+
+ /* Call HwInitialize at DISPATCH_LEVEL */
+ KeRaiseIrql(DISPATCH_LEVEL, &Dirql);
+
+ if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
+ DeviceExtension->HwInitialize,
+ DeviceExtension->MiniPortDeviceExtension))
+ {
+ DPRINT1("HwInitialize() failed!\n");
+ KeLowerIrql(Dirql);
+ Status = STATUS_ADAPTER_HARDWARE_ERROR;
+ break;
+ }
+
+ /* Check if a notification is needed */
+ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
+ {
+ /* Call DPC right away, because we're already at DISPATCH_LEVEL */
+ ScsiPortDpcForIsr(NULL,
+ DeviceExtension->DeviceObject,
+ NULL,
+ NULL);
+ }
+
+ /* Lower irql back to what it was */
+ KeLowerIrql(Dirql);
+
+ /* Start our timer */
+ IoStartTimer(PortDeviceObject);
+
+ /* Initialize bus scanning information */
+ DeviceExtension->BusesConfig = ExAllocatePoolWithTag(PagedPool,
+ sizeof(PSCSI_BUS_SCAN_INFO) * DeviceExtension->PortConfig->NumberOfBuses
+ + sizeof(ULONG), TAG_SCSIPORT);
+
+ if (!DeviceExtension->BusesConfig)
+ {
+ DPRINT1("Out of resources!\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ /* Zero it */
+ RtlZeroMemory(DeviceExtension->BusesConfig,
+ sizeof(PSCSI_BUS_SCAN_INFO) * DeviceExtension->PortConfig->NumberOfBuses
+ + sizeof(ULONG));
+
+ /* Store number of buses there */
+ DeviceExtension->BusesConfig->NumberOfBuses = (UCHAR)DeviceExtension->BusNum;
+
+ /* Scan the adapter for devices */
+ SpiScanAdapter(DeviceExtension);
+
+ /* Build the registry device map */
+ SpiBuildDeviceMap(DeviceExtension,
+ (PUNICODE_STRING)Argument2);
+
+ /* Create the dos device link */
+ swprintf(DosNameBuffer,
+ L"\\??\\Scsi%lu:",
+ SystemConfig->ScsiPortCount);
+ RtlInitUnicodeString(&DosDeviceName, DosNameBuffer);
+ IoCreateSymbolicLink(&DosDeviceName, &DeviceName);
+
+ /* Increase the port count */
+ SystemConfig->ScsiPortCount++;
+ FirstConfigCall = FALSE;
+
+ /* Increase adapter number and bus number respectively */
+ ConfigInfo.AdapterNumber++;
+
+ if (!Again)
+ ConfigInfo.BusNumber++;
DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber, MaxBus);
- if (BusNumber >= MaxBus)
- {
- DPRINT("Scanned all buses!\n");
- Status = STATUS_SUCCESS;
- goto ByeBye;
- }
- if (Again == FALSE)
- {
- BusNumber++;
- SlotNumber.u.AsULONG = 0;
- }
+ DeviceFound = TRUE;
}
-ByeBye:
- /* Clean up the mess */
- if (PortDeviceObject != NULL)
+ /* Clean up the mess */
+ SpiCleanupAfterInit(DeviceExtension);
+
+ /* Close registry keys */
+ if (ConfigInfo.ServiceKey != NULL)
+ ZwClose(ConfigInfo.ServiceKey);
+
+ if (ConfigInfo.DeviceKey != NULL)
+ ZwClose(ConfigInfo.DeviceKey);
+
+ if (ConfigInfo.BusKey != NULL)
+ ZwClose(ConfigInfo.BusKey);
+
+ if (ConfigInfo.AccessRanges != NULL)
+ ExFreePool(ConfigInfo.AccessRanges);
+
+ if (ConfigInfo.Parameter != NULL)
+ ExFreePool(ConfigInfo.Parameter);
+
+ DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
+ Status, DeviceFound);
+
+ return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
+}
+
+static VOID
+SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+ PSCSI_LUN_INFO LunInfo;
+ PVOID Ptr;
+ ULONG Bus, Lun;
+
+ /* Check if we have something to clean up */
+ if (DeviceExtension == NULL)
+ return;
+
+ /* Stop the timer and disconnect the interrupt */
+ if (DeviceExtension->Interrupt)
{
- DPRINT("Delete device: %p\n", PortDeviceObject);
+ IoStopTimer(DeviceExtension->DeviceObject);
+ IoDisconnectInterrupt(DeviceExtension->Interrupt);
+ }
- DeviceExtension = PortDeviceObject->DeviceExtension;
+ /* Delete ConfigInfo */
+ if (DeviceExtension->BusesConfig)
+ {
+ for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
+ {
+ if (!DeviceExtension->BusesConfig->BusScanInfo[Bus])
+ continue;
- if (DeviceExtension->PortCapabilities != NULL)
- {
- IoDisconnectInterrupt (DeviceExtension->Interrupt);
- ExFreePool (DeviceExtension->PortCapabilities);
- }
+ LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
- if (DeviceExtension->PortConfig != NULL)
- {
- ExFreePool (DeviceExtension->PortConfig);
- }
+ while (LunInfo)
+ {
+ /* Free current, but save pointer to the next one */
+ Ptr = LunInfo->Next;
+ ExFreePool(LunInfo);
+ LunInfo = Ptr;
+ }
- IoDeleteDevice (PortDeviceObject);
+ ExFreePool(DeviceExtension->BusesConfig->BusScanInfo[Bus]);
+ }
+
+ ExFreePool(DeviceExtension->BusesConfig);
}
- DPRINT("ScsiPortInitialize() done!\n");
+ /* Free PortConfig */
+ if (DeviceExtension->PortConfig)
+ ExFreePool(DeviceExtension->PortConfig);
- return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
-}
+ /* Free LUNs*/
+ for(Lun = 0; Lun < LUS_NUMBER; Lun++)
+ {
+ while (DeviceExtension->LunExtensionList[Lun])
+ {
+ Ptr = DeviceExtension->LunExtensionList[Lun];
+ DeviceExtension->LunExtensionList[Lun] = DeviceExtension->LunExtensionList[Lun]->Next;
+
+ ExFreePool(Ptr);
+ }
+ }
+
+ /* Free common buffer (if it exists) */
+ if (DeviceExtension->SrbExtensionBuffer != NULL &&
+ DeviceExtension->CommonBufferLength != 0)
+ {
+ if (!DeviceExtension->AdapterObject)
+ {
+ ExFreePool(DeviceExtension->SrbExtensionBuffer);
+ }
+ else
+ {
+ HalFreeCommonBuffer(DeviceExtension->AdapterObject,
+ DeviceExtension->CommonBufferLength,
+ DeviceExtension->PhysicalAddress,
+ DeviceExtension->SrbExtensionBuffer,
+ FALSE);
+ }
+ }
+
+ /* Free SRB info */
+ if (DeviceExtension->SrbInfo != NULL)
+ ExFreePool(DeviceExtension->SrbInfo);
+
+ /* Unmap mapped addresses */
+ while (DeviceExtension->MappedAddressList != NULL)
+ {
+ MmUnmapIoSpace(DeviceExtension->MappedAddressList->MappedAddress,
+ DeviceExtension->MappedAddressList->NumberOfBytes);
+
+ Ptr = DeviceExtension->MappedAddressList;
+ DeviceExtension->MappedAddressList = DeviceExtension->MappedAddressList->NextMappedAddress;
+
+ ExFreePool(Ptr);
+ }
+ /* Finally delete the device object */
+ DPRINT("Deleting device %p\n", DeviceExtension->DeviceObject);
+ IoDeleteDevice(DeviceExtension->DeviceObject);
+}
/*
* @unimplemented
*/
-VOID STDCALL
+VOID NTAPI
ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb,
- IN ULONG LogicalAddress,
+ IN PVOID LogicalAddress,
IN ULONG Length)
{
DPRINT1("ScsiPortIoMapTransfer()\n");
UNIMPLEMENTED;
}
-
/*
* @unimplemented
*/
-VOID STDCALL
+VOID NTAPI
ScsiPortLogError(IN PVOID HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
IN UCHAR PathId,
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT1("ScsiPortLogError() called\n");
- DPRINT1("Srb %x, PathId %d, TargetId %d, Lun %d, ErrorCode %x, UniqueId %x\n",
- Srb, PathId, TargetId, Lun, ErrorCode, UniqueId);
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
SCSI_PORT_DEVICE_EXTENSION,
DPRINT("ScsiPortLogError() done\n");
}
-
/*
* @implemented
*/
-VOID STDCALL
+VOID NTAPI
ScsiPortMoveMemory(OUT PVOID Destination,
IN PVOID Source,
IN ULONG Length)
IN PVOID HwDeviceExtension,
...)
{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- va_list ap;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ va_list ap;
- DPRINT("ScsiPortNotification() called\n");
+ DPRINT("ScsiPortNotification() called\n");
- DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
- SCSI_PORT_DEVICE_EXTENSION,
- MiniPortDeviceExtension);
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
- DPRINT("DeviceExtension %p\n", DeviceExtension);
+ DPRINT("DeviceExtension %p\n", DeviceExtension);
- va_start(ap, HwDeviceExtension);
+ va_start(ap, HwDeviceExtension);
- switch (NotificationType)
+ switch (NotificationType)
{
- case RequestComplete:
- {
- PSCSI_REQUEST_BLOCK Srb;
+ case RequestComplete:
+ {
+ PSCSI_REQUEST_BLOCK Srb;
+ PSCSI_REQUEST_BLOCK_INFO SrbData;
- Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
+ Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
- DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
- DeviceExtension->Flags |= IRP_FLAG_COMPLETE;
- Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
- }
- break;
+ DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
- case NextRequest:
- DPRINT("Notify: NextRequest\n");
- DeviceExtension->Flags |= IRP_FLAG_NEXT;
- break;
+ /* Make sure Srb is allright */
+ ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING);
+ ASSERT(Srb->Function != SRB_FUNCTION_EXECUTE_SCSI || Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD);
- case NextLuRequest:
- {
- UCHAR PathId;
- UCHAR TargetId;
- UCHAR Lun;
- PSCSI_PORT_LUN_EXTENSION LunExtension;
-
- PathId = (UCHAR) va_arg (ap, int);
- TargetId = (UCHAR) va_arg (ap, int);
- Lun = (UCHAR) va_arg (ap, int);
-
- DPRINT ("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
- PathId, TargetId, Lun);
-
- LunExtension = SpiGetLunExtension(DeviceExtension,
- PathId,
- TargetId,
- Lun);
- if (LunExtension)
- {
- DeviceExtension->Flags |= IRP_FLAG_NEXT_LU;
- LunExtension->Flags |= IRP_FLAG_NEXT_LU;
- }
- }
- break;
+ if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
+ {
+ /* It's been already completed */
+ va_end(ap);
+ return;
+ }
+
+ /* It's not active anymore */
+ Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
+
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
+ {
+ /* TODO: Treat it specially */
+ ASSERT(FALSE);
+ }
+ else
+ {
+ /* Get the SRB data */
+ SrbData = SpiGetSrbData(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ Srb->QueueTag);
+
+ /* Make sure there are no CompletedRequests and there is a Srb */
+ ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL);
+
+ /* If it's a read/write request, make sure it has data inside it */
+ if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) &&
+ ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE)))
+ {
+ ASSERT(Srb->DataTransferLength);
+ }
+
+ SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests;
+ DeviceExtension->InterruptData.CompletedRequests = SrbData;
+ }
+ }
+ break;
+
+ case NextRequest:
+ DPRINT("Notify: NextRequest\n");
+ DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
+ break;
+
+ case NextLuRequest:
+ {
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+
+ PathId = (UCHAR) va_arg (ap, int);
+ TargetId = (UCHAR) va_arg (ap, int);
+ Lun = (UCHAR) va_arg (ap, int);
+
+ DPRINT("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
+ PathId, TargetId, Lun);
+
+ /* Mark it in the flags field */
+ DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
+
+ /* Get the LUN extension */
+ LunExtension = SpiGetLunExtension(DeviceExtension,
+ PathId,
+ TargetId,
+ Lun);
+
+ /* If returned LunExtension is NULL, break out */
+ if (!LunExtension) break;
+
+ /* This request should not be processed if */
+ if ((LunExtension->ReadyLun) ||
+ (LunExtension->SrbInfo.Srb))
+ {
+ /* Nothing to do here */
+ break;
+ }
+
+ /* Add this LUN to the list */
+ LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun;
+ DeviceExtension->InterruptData.ReadyLun = LunExtension;
+ }
+ break;
case ResetDetected:
- DPRINT1("Notify: ResetDetected\n");
- /* FIXME: ??? */
- break;
+ DPRINT("Notify: ResetDetected\n");
+ /* Add RESET flags */
+ DeviceExtension->InterruptData.Flags |=
+ SCSI_PORT_RESET | SCSI_PORT_RESET_REPORTED;
+ break;
default:
DPRINT1 ("Unsupported notification %lu\n", NotificationType);
break;
}
- if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
- {
- IoRequestDpc(DeviceExtension->DeviceObject,
- NULL,
- DeviceExtension);
- }
- else
- {
- SpiProcessRequests(DeviceExtension, NULL);
- }
-
- va_end(ap);
-}
+ va_end(ap);
-/*
- * @implemented
- */
-ULONG STDCALL
-ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
- IN ULONG BusDataType,
- IN ULONG SystemIoBusNumber,
- IN ULONG SlotNumber,
- IN PVOID Buffer,
- IN ULONG Offset,
- IN ULONG Length)
-{
- DPRINT("ScsiPortSetBusDataByOffset()\n");
- return(HalSetBusDataByOffset(BusDataType,
- SystemIoBusNumber,
- SlotNumber,
- Buffer,
- Offset,
- Length));
+ /* Request a DPC after we're done with the interrupt */
+ DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED;
}
-
/*
* @implemented
*/
-BOOLEAN STDCALL
+BOOLEAN NTAPI
ScsiPortValidateRange(IN PVOID HwDeviceExtension,
IN INTERFACE_TYPE BusType,
IN ULONG SystemIoBusNumber,
/* INTERNAL FUNCTIONS ********************************************************/
-
-static BOOLEAN
-SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
- IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
- IN ULONG BusNumber,
- IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
+static VOID
+SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
+ IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
+ IN PPORT_CONFIGURATION_INFORMATION PortConfig)
{
- PCI_COMMON_CONFIG PciConfig;
- PCI_SLOT_NUMBER SlotNumber;
- ULONG DataSize;
- ULONG DeviceNumber;
- ULONG FunctionNumber;
- CHAR VendorIdString[8];
- CHAR DeviceIdString[8];
- ULONG i;
- ULONG RangeLength;
-
- DPRINT ("SpiGetPciConfiguration() called\n");
+ PACCESS_RANGE AccessRange;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
+ ULONG RangeNumber;
+ ULONG Index;
- if (NextSlotNumber->u.bits.FunctionNumber >= PCI_MAX_FUNCTION)
- {
- NextSlotNumber->u.bits.FunctionNumber = 0;
- NextSlotNumber->u.bits.DeviceNumber++;
- }
+ RangeNumber = 0;
- if (NextSlotNumber->u.bits.DeviceNumber >= PCI_MAX_DEVICES)
+ /* Loop through all entries */
+ for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
{
- NextSlotNumber->u.bits.DeviceNumber = 0;
- return FALSE;
- }
+ PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
- for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
- {
- SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+ switch (PartialData->Type)
+ {
+ case CmResourceTypePort:
+ /* Copy access ranges */
+ if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
+ {
+ AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
- for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
- {
- SlotNumber.u.bits.FunctionNumber = FunctionNumber;
-
- DataSize = HalGetBusData (PCIConfiguration,
- BusNumber,
- SlotNumber.u.AsULONG,
- &PciConfig,
- PCI_COMMON_HDR_LENGTH);
- if (DataSize != PCI_COMMON_HDR_LENGTH)
- {
- if (FunctionNumber == 0)
- {
- break;
- }
- else
- {
- continue;
- }
- }
+ AccessRange->RangeStart = PartialData->u.Port.Start;
+ AccessRange->RangeLength = PartialData->u.Port.Length;
- sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
- sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
+ AccessRange->RangeInMemory = FALSE;
+ RangeNumber++;
+ }
+ break;
- if (!_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) &&
- !_strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
- {
- DPRINT ("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
- PciConfig.VendorID,
- PciConfig.DeviceID,
- BusNumber,
- SlotNumber.u.bits.DeviceNumber,
- SlotNumber.u.bits.FunctionNumber);
-
- PortConfig->BusInterruptLevel =
- PortConfig->BusInterruptVector = PciConfig.u.type0.InterruptLine;
- PortConfig->SlotNumber = SlotNumber.u.AsULONG;
-
- /* Initialize access ranges */
- if (PortConfig->NumberOfAccessRanges > 0)
- {
- if (PortConfig->NumberOfAccessRanges > PCI_TYPE0_ADDRESSES)
- PortConfig->NumberOfAccessRanges = PCI_TYPE0_ADDRESSES;
+ case CmResourceTypeMemory:
+ /* Copy access ranges */
+ if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
+ {
+ AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
- for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
- {
- (*PortConfig->AccessRanges)[i].RangeStart.QuadPart =
- PciConfig.u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_ADDRESS_MASK;
- if ((*PortConfig->AccessRanges)[i].RangeStart.QuadPart != 0)
- {
- RangeLength = (ULONG)-1;
- HalSetBusDataByOffset (PCIConfiguration,
- BusNumber,
- SlotNumber.u.AsULONG,
- (PVOID)&RangeLength,
- 0x10 + (i * sizeof(ULONG)),
- sizeof(ULONG));
-
- HalGetBusDataByOffset (PCIConfiguration,
- BusNumber,
- SlotNumber.u.AsULONG,
- (PVOID)&RangeLength,
- 0x10 + (i * sizeof(ULONG)),
- sizeof(ULONG));
-
- HalSetBusDataByOffset (PCIConfiguration,
- BusNumber,
- SlotNumber.u.AsULONG,
- (PVOID)&PciConfig.u.type0.BaseAddresses[i],
- 0x10 + (i * sizeof(ULONG)),
- sizeof(ULONG));
- if (RangeLength != 0)
- {
- (*PortConfig->AccessRanges)[i].RangeLength =
- -(RangeLength & PCI_ADDRESS_IO_ADDRESS_MASK);
- (*PortConfig->AccessRanges)[i].RangeInMemory =
- !(PciConfig.u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_SPACE);
-
- DPRINT("RangeStart 0x%lX RangeLength 0x%lX RangeInMemory %s\n",
- PciConfig.u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_ADDRESS_MASK,
- -(RangeLength & PCI_ADDRESS_IO_ADDRESS_MASK),
- (PciConfig.u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_SPACE)?"FALSE":"TRUE");
- }
- }
- }
- }
+ AccessRange->RangeStart = PartialData->u.Memory.Start;
+ AccessRange->RangeLength = PartialData->u.Memory.Length;
- NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
- NextSlotNumber->u.bits.FunctionNumber = FunctionNumber;
+ AccessRange->RangeInMemory = TRUE;
+ RangeNumber++;
+ }
+ break;
- PortConfig->SlotNumber = NextSlotNumber->u.AsULONG;
+ case CmResourceTypeInterrupt:
+ /* Copy interrupt data */
+ PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
+ PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
- NextSlotNumber->u.bits.FunctionNumber += 1;
+ /* Set interrupt mode accordingly to the resource */
+ if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
+ {
+ PortConfig->InterruptMode = Latched;
+ }
+ else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
+ {
+ PortConfig->InterruptMode = LevelSensitive;
+ }
+ break;
- return TRUE;
- }
+ case CmResourceTypeDma:
+ PortConfig->DmaChannel = PartialData->u.Dma.Channel;
+ PortConfig->DmaPort = PartialData->u.Dma.Port;
+ break;
+ }
+ }
+}
+static PCM_RESOURCE_LIST
+SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ PPORT_CONFIGURATION_INFORMATION PortConfig)
+{
+ PCONFIGURATION_INFORMATION ConfigInfo;
+ PCM_RESOURCE_LIST ResourceList;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
+ PACCESS_RANGE AccessRange;
+ BOOLEAN Dma;
+ ULONG ListLength = 0, i, FullSize;
+ ULONG Interrupt;
+
+ /* Get current Atdisk usage from the system */
+ ConfigInfo = IoGetConfigurationInformation();
+
+ if (PortConfig->AtdiskPrimaryClaimed)
+ ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
+
+ if (PortConfig->AtdiskSecondaryClaimed)
+ ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
+
+ /* Do we use DMA? */
+ if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE ||
+ PortConfig->DmaPort != SP_UNINITIALIZED_VALUE)
+ {
+ Dma = TRUE;
+ ListLength++;
+ }
+ else
+ {
+ Dma = FALSE;
+ }
- if (FunctionNumber == 0 && !(PciConfig.HeaderType & PCI_MULTIFUNCTION))
- {
- break;
- }
- }
- NextSlotNumber->u.bits.FunctionNumber = 0;
+ /* How many interrupts to we have? */
+ if (DeviceExtension->HwInterrupt == NULL ||
+ (PortConfig->BusInterruptLevel == 0 &&
+ PortConfig->BusInterruptVector == 0))
+ {
+ Interrupt = 0;
+ }
+ else
+ {
+ Interrupt = 1;
+ ListLength++;
}
- DPRINT ("No device found\n");
+ if (DeviceExtension->HwInterrupt != NULL &&
+ (PortConfig->BusInterruptLevel2 != 0 ||
+ PortConfig->BusInterruptVector2 != 0))
+ {
+ Interrupt++;
+ ListLength++;
+ }
- return FALSE;
-}
+ /* How many access ranges do we use? */
+ AccessRange = &((*(PortConfig->AccessRanges))[0]);
+ for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
+ {
+ if (AccessRange->RangeLength != 0)
+ ListLength++;
+ AccessRange++;
+ }
+ /* Allocate the resource list, since we know its size now */
+ FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) *
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
-/**********************************************************************
- * NAME INTERNAL
- * ScsiPortCreateClose
- *
- * DESCRIPTION
- * Answer requests for Create/Close calls: a null operation.
- *
- * RUN LEVEL
- * PASSIVE_LEVEL
- *
- * ARGUMENTS
- * DeviceObject
- * Pointer to a device object.
- *
- * Irp
- * Pointer to an IRP.
- *
- * RETURN VALUE
- * Status.
- */
+ ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT);
-static NTSTATUS STDCALL
-ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- DPRINT("ScsiPortCreateClose()\n");
+ if (!ResourceList)
+ return NULL;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = FILE_OPENED;
+ /* Zero it */
+ RtlZeroMemory(ResourceList, FullSize);
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ /* Initialize it */
+ ResourceList->Count = 1;
+ ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType;
+ ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber;
+ ResourceList->List[0].PartialResourceList.Count = ListLength;
+ ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
- return(STATUS_SUCCESS);
-}
+ /* Copy access ranges array over */
+ for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
+ {
+ AccessRange = &((*(PortConfig->AccessRanges))[i]);
+ /* If the range is empty - skip it */
+ if (AccessRange->RangeLength == 0)
+ continue;
-/**********************************************************************
- * NAME INTERNAL
- * ScsiPortDispatchScsi
- *
- * DESCRIPTION
- * Answer requests for SCSI calls
- *
- * RUN LEVEL
- * PASSIVE_LEVEL
- *
- * ARGUMENTS
- * Standard dispatch arguments
- *
- * RETURNS
- * NTSTATUS
- */
+ if (AccessRange->RangeInMemory)
+ {
+ ResourceDescriptor->Type = CmResourceTypeMemory;
+ ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
+ }
+ else
+ {
+ ResourceDescriptor->Type = CmResourceTypePort;
+ ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
+ }
-static NTSTATUS STDCALL
-ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- PSCSI_PORT_LUN_EXTENSION LunExtension;
- PIO_STACK_LOCATION Stack;
- PSCSI_REQUEST_BLOCK Srb;
- NTSTATUS Status = STATUS_SUCCESS;
- ULONG DataSize = 0;
+ ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
- DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
- DeviceObject, Irp);
+ ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart;
+ ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength;
- DeviceExtension = DeviceObject->DeviceExtension;
- Stack = IoGetCurrentIrpStackLocation(Irp);
+ ResourceDescriptor++;
+ }
- Srb = Stack->Parameters.Scsi.Srb;
- if (Srb == NULL)
+ /* If we use interrupt(s), copy them */
+ if (Interrupt)
{
- Status = STATUS_UNSUCCESSFUL;
-
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = 0;
-
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ ResourceDescriptor->Type = CmResourceTypeInterrupt;
- return(Status);
+ if (PortConfig->AdapterInterfaceType == MicroChannel ||
+ PortConfig->InterruptMode == LevelSensitive)
+ {
+ ResourceDescriptor->ShareDisposition = CmResourceShareShared;
+ ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+ }
+ else
+ {
+ ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+ ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+ }
+
+ ResourceDescriptor->u.Interrupt.Level = PortConfig->BusInterruptLevel;
+ ResourceDescriptor->u.Interrupt.Vector = PortConfig->BusInterruptVector;
+ ResourceDescriptor->u.Interrupt.Affinity = 0;
+
+ ResourceDescriptor++;
+ Interrupt--;
+ }
+
+ /* Copy 2nd interrupt
+ FIXME: Stupid code duplication, remove */
+ if (Interrupt)
+ {
+ ResourceDescriptor->Type = CmResourceTypeInterrupt;
+
+ if (PortConfig->AdapterInterfaceType == MicroChannel ||
+ PortConfig->InterruptMode == LevelSensitive)
+ {
+ ResourceDescriptor->ShareDisposition = CmResourceShareShared;
+ ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+ }
+ else
+ {
+ ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+ ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+ }
+
+ ResourceDescriptor->u.Interrupt.Level = PortConfig->BusInterruptLevel;
+ ResourceDescriptor->u.Interrupt.Vector = PortConfig->BusInterruptVector;
+ ResourceDescriptor->u.Interrupt.Affinity = 0;
+
+ ResourceDescriptor++;
+ }
+
+ /* Copy DMA data */
+ if (Dma)
+ {
+ ResourceDescriptor->Type = CmResourceTypeDma;
+ ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+ ResourceDescriptor->u.Dma.Channel = PortConfig->DmaChannel;
+ ResourceDescriptor->u.Dma.Port = PortConfig->DmaPort;
+ ResourceDescriptor->Flags = 0;
+
+ if (PortConfig->DmaChannel == SP_UNINITIALIZED_VALUE)
+ ResourceDescriptor->u.Dma.Channel = 0;
+
+ if (PortConfig->DmaPort == SP_UNINITIALIZED_VALUE)
+ ResourceDescriptor->u.Dma.Port = 0;
+ }
+
+ return ResourceList;
+}
+
+
+static BOOLEAN
+SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
+ IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
+ IN PUNICODE_STRING RegistryPath,
+ IN ULONG BusNumber,
+ IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
+{
+ PCI_COMMON_CONFIG PciConfig;
+ PCI_SLOT_NUMBER SlotNumber;
+ ULONG DataSize;
+ ULONG DeviceNumber;
+ ULONG FunctionNumber;
+ CHAR VendorIdString[8];
+ CHAR DeviceIdString[8];
+ UNICODE_STRING UnicodeStr;
+ PCM_RESOURCE_LIST ResourceList;
+ NTSTATUS Status;
+
+ DPRINT ("SpiGetPciConfiguration() called\n");
+
+ RtlZeroMemory(&ResourceList, sizeof(PCM_RESOURCE_LIST));
+ SlotNumber.u.AsULONG = 0;
+
+ /* Loop through all devices */
+ for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
+ {
+ SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+
+ /* Loop through all functions */
+ for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
+ {
+ SlotNumber.u.bits.FunctionNumber = FunctionNumber;
+
+ /* Get PCI config bytes */
+ DataSize = HalGetBusData(PCIConfiguration,
+ BusNumber,
+ SlotNumber.u.AsULONG,
+ &PciConfig,
+ sizeof(ULONG));
+
+ /* If result of HalGetBusData is 0, then the bus is wrong */
+ if (DataSize == 0)
+ return FALSE;
+
+ /* If result is PCI_INVALID_VENDORID, then this device has no more
+ "Functions" */
+ if (PciConfig.VendorID == PCI_INVALID_VENDORID)
+ break;
+
+ sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
+ sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
+
+ if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
+ _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
+ {
+ /* It is not our device */
+ continue;
+ }
+
+ DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
+ PciConfig.VendorID,
+ PciConfig.DeviceID,
+ BusNumber,
+ SlotNumber.u.bits.DeviceNumber,
+ SlotNumber.u.bits.FunctionNumber);
+
+
+ RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter");
+ Status = HalAssignSlotResources(RegistryPath,
+ &UnicodeStr,
+ DriverObject,
+ DeviceObject,
+ PCIBus,
+ BusNumber,
+ SlotNumber.u.AsULONG,
+ &ResourceList);
+
+ if (!NT_SUCCESS(Status))
+ break;
+
+ /* Create configuration information */
+ SpiResourceToConfig(HwInitializationData,
+ ResourceList->List,
+ PortConfig);
+
+ /* Free the resource list */
+ ExFreePool(ResourceList);
+
+ /* Set dev & fn numbers */
+ NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
+ NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
+
+ /* Save the slot number */
+ PortConfig->SlotNumber = SlotNumber.u.AsULONG;
+
+ return TRUE;
+ }
+ NextSlotNumber->u.bits.FunctionNumber = 0;
+ }
+
+ NextSlotNumber->u.bits.DeviceNumber = 0;
+ DPRINT ("No device found\n");
+
+ return FALSE;
+}
+
+
+
+/**********************************************************************
+ * NAME INTERNAL
+ * ScsiPortCreateClose
+ *
+ * DESCRIPTION
+ * Answer requests for Create/Close calls: a null operation.
+ *
+ * RUN LEVEL
+ * PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ * DeviceObject
+ * Pointer to a device object.
+ *
+ * Irp
+ * Pointer to an IRP.
+ *
+ * RETURN VALUE
+ * Status.
+ */
+
+static NTSTATUS NTAPI
+ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ DPRINT("ScsiPortCreateClose()\n");
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ PIRP Irp)
+{
+ PSCSI_LUN_INFO LunInfo;
+ PIO_STACK_LOCATION IrpStack;
+ PDEVICE_OBJECT DeviceObject;
+ PSCSI_REQUEST_BLOCK Srb;
+ KIRQL Irql;
+
+ /* Get pointer to the SRB */
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+ Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
+
+ /* Check if PathId matches number of buses */
+ if (DeviceExtension->BusesConfig == NULL ||
+ DeviceExtension->BusesConfig->NumberOfBuses <= Srb->PathId)
+ {
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ /* Get pointer to LunInfo */
+ LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Srb->PathId]->LunInfo;
+
+ /* Find matching LunInfo */
+ while (LunInfo)
+ {
+ if (LunInfo->PathId == Srb->PathId &&
+ LunInfo->TargetId == Srb->TargetId &&
+ LunInfo->Lun == Srb->Lun)
+ {
+ break;
+ }
+
+ LunInfo = LunInfo->Next;
+ }
+
+ /* If we couldn't find it - exit */
+ if (LunInfo == NULL)
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+
+
+ /* Get spinlock */
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
+
+ /* Release, if asked */
+ if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE)
+ {
+ LunInfo->DeviceClaimed = FALSE;
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ return STATUS_SUCCESS;
+ }
+
+ /* Attach, if not already claimed */
+ if (LunInfo->DeviceClaimed)
+ {
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+ Srb->SrbStatus = SRB_STATUS_BUSY;
+
+ return STATUS_DEVICE_BUSY;
+ }
+
+ /* Save the device object */
+ DeviceObject = LunInfo->DeviceObject;
+
+ if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE)
+ LunInfo->DeviceClaimed = TRUE;
+
+ if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE)
+ LunInfo->DeviceObject = Srb->DataBuffer;
+
+ Srb->DataBuffer = DeviceObject;
+
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ return STATUS_SUCCESS;
+}
+
+
+/**********************************************************************
+ * NAME INTERNAL
+ * ScsiPortDispatchScsi
+ *
+ * DESCRIPTION
+ * Answer requests for SCSI calls
+ *
+ * RUN LEVEL
+ * PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ * Standard dispatch arguments
+ *
+ * RETURNS
+ * NTSTATUS
+ */
+
+static NTSTATUS NTAPI
+ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ PIO_STACK_LOCATION Stack;
+ PSCSI_REQUEST_BLOCK Srb;
+ KIRQL Irql;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PIRP NextIrp, IrpList;
+ PKDEVICE_QUEUE_ENTRY Entry;
+
+ DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
+ DeviceObject, Irp);
+
+ DeviceExtension = DeviceObject->DeviceExtension;
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+
+ Srb = Stack->Parameters.Scsi.Srb;
+ if (Srb == NULL)
+ {
+ DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
+ Status = STATUS_UNSUCCESSFUL;
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return(Status);
+ }
+
+ DPRINT("Srb: %p\n", Srb);
+ DPRINT("Srb->Function: %lu\n", Srb->Function);
+ DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
+
+ LunExtension = SpiGetLunExtension(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+ if (LunExtension == NULL)
+ {
+ DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
+ Status = STATUS_NO_SUCH_DEVICE;
+
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return(Status);
+ }
+
+ switch (Srb->Function)
+ {
+ case SRB_FUNCTION_SHUTDOWN:
+ case SRB_FUNCTION_FLUSH:
+ DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
+ if (DeviceExtension->CachesData == FALSE)
+ {
+ /* All success here */
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+ }
+ /* Fall through to a usual execute operation */
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+ case SRB_FUNCTION_IO_CONTROL:
+ /* Mark IRP as pending in all cases */
+ IoMarkIrpPending(Irp);
+
+ if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
+ {
+ /* Start IO directly */
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+ }
+ else
+ {
+ KIRQL oldIrql;
+
+ /* We need to be at DISPATCH_LEVEL */
+ KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
+
+ /* Insert IRP into the queue */
+ if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
+ &Irp->Tail.Overlay.DeviceQueueEntry,
+ Srb->QueueSortKey))
+ {
+ /* It means the queue is empty, and we just start this request */
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+ }
+
+ /* Back to the old IRQL */
+ KeLowerIrql (oldIrql);
+ }
+ return STATUS_PENDING;
+
+ case SRB_FUNCTION_CLAIM_DEVICE:
+ case SRB_FUNCTION_ATTACH_DEVICE:
+ DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
+
+ /* Reference device object and keep the device object */
+ Status = SpiHandleAttachRelease(DeviceExtension, Irp);
+ break;
+
+ case SRB_FUNCTION_RELEASE_DEVICE:
+ DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
+
+ /* Dereference device object and clear the device object */
+ Status = SpiHandleAttachRelease(DeviceExtension, Irp);
+ break;
+
+ case SRB_FUNCTION_RELEASE_QUEUE:
+ DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
+
+ /* Guard with the spinlock */
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
+
+ if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
+ {
+ DPRINT("Queue is not frozen really\n");
+
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ Status = STATUS_SUCCESS;
+ break;
+
+ }
+
+ /* Unfreeze the queue */
+ LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
+
+ if (LunExtension->SrbInfo.Srb == NULL)
+ {
+ /* Get next logical unit request */
+ SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
+
+ /* SpiGetNextRequestFromLun() releases the spinlock */
+ KeLowerIrql(Irql);
+ }
+ else
+ {
+ DPRINT("The queue has active request\n");
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+ }
+
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ Status = STATUS_SUCCESS;
+ break;
+
+ case SRB_FUNCTION_FLUSH_QUEUE:
+ DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
+
+ /* Guard with the spinlock */
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
+
+ if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
+ {
+ DPRINT("Queue is not frozen really\n");
+
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ /* Make sure there is no active request */
+ ASSERT(LunExtension->SrbInfo.Srb == NULL);
+
+ /* Compile a list from the device queue */
+ IrpList = NULL;
+ while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) != NULL)
+ {
+ NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
+
+ /* Get the Srb */
+ Stack = IoGetCurrentIrpStackLocation(NextIrp);
+ Srb = Stack->Parameters.Scsi.Srb;
+
+ /* Set statuse */
+ Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
+ NextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+ /* Add then to the list */
+ NextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)IrpList;
+ IrpList = NextIrp;
+ }
+
+ /* Unfreeze the queue */
+ LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
+
+ /* Release the spinlock */
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+
+ /* Complete those requests */
+ while (IrpList)
+ {
+ NextIrp = IrpList;
+ IrpList = (PIRP)NextIrp->Tail.Overlay.ListEntry.Flink;
+
+ IoCompleteRequest(NextIrp, 0);
+ }
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ Irp->IoStatus.Status = Status;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return(Status);
+}
+
+
+/**********************************************************************
+ * NAME INTERNAL
+ * ScsiPortDeviceControl
+ *
+ * DESCRIPTION
+ * Answer requests for device control calls
+ *
+ * RUN LEVEL
+ * PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ * Standard dispatch arguments
+ *
+ * RETURNS
+ * NTSTATUS
+ */
+
+static NTSTATUS NTAPI
+ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION Stack;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ NTSTATUS Status = STATUS_SUCCESS;;
+
+ DPRINT("ScsiPortDeviceControl()\n");
+
+ Irp->IoStatus.Information = 0;
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ DeviceExtension = DeviceObject->DeviceExtension;
+
+ switch (Stack->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_SCSI_GET_DUMP_POINTERS:
+ {
+ PDUMP_POINTERS DumpPointers;
+ DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
+ DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
+ DumpPointers->DeviceObject = DeviceObject;
+
+ Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
+ }
+ break;
+
+ case IOCTL_SCSI_GET_CAPABILITIES:
+ DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
+ if (Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
+ {
+ *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = &DeviceExtension->PortCapabilities;
+
+ Irp->IoStatus.Information = sizeof(PVOID);
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IO_SCSI_CAPABILITIES))
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
+ &DeviceExtension->PortCapabilities,
+ sizeof(IO_SCSI_CAPABILITIES));
+
+ Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
+ Status = STATUS_SUCCESS;
+ break;
+
+ case IOCTL_SCSI_GET_INQUIRY_DATA:
+ DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
+
+ /* Copy inquiry data to the port device extension */
+ Status = SpiGetInquiryData(DeviceExtension, Irp);
+ break;
+
+ default:
+ DPRINT1(" unknown ioctl code: 0x%lX\n",
+ Stack->Parameters.DeviceIoControl.IoControlCode);
+ break;
+ }
+
+ /* Complete the request with the given status */
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+
+static VOID NTAPI
+ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ PIO_STACK_LOCATION IrpStack;
+ PSCSI_REQUEST_BLOCK Srb;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+ LONG CounterResult;
+ NTSTATUS Status;
+
+ DPRINT("ScsiPortStartIo() called!\n");
+
+ DeviceExtension = DeviceObject->DeviceExtension;
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ DPRINT("DeviceExtension %p\n", DeviceExtension);
+
+ Srb = IrpStack->Parameters.Scsi.Srb;
+
+ /* Apply "default" flags */
+ Srb->SrbFlags |= DeviceExtension->SrbFlags;
+
+ /* Get LUN extension */
+ LunExtension = SpiGetLunExtension(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ if (DeviceExtension->NeedSrbDataAlloc ||
+ DeviceExtension->NeedSrbExtensionAlloc)
+ {
+ /* Allocate them */
+ SrbInfo = SpiAllocateSrbStructures(DeviceExtension,
+ LunExtension,
+ Srb);
+
+ /* Couldn't alloc one or both data structures, return */
+ if (SrbInfo == NULL)
+ {
+ /* We have to call IoStartNextPacket, because this request
+ was not started */
+ if (LunExtension->Flags & LUNEX_REQUEST_PENDING)
+ IoStartNextPacket(DeviceObject, FALSE);
+
+ return;
+ }
+ }
+ else
+ {
+ /* No allocations are needed */
+ SrbInfo = &LunExtension->SrbInfo;
+ Srb->SrbExtension = NULL;
+ Srb->QueueTag = SP_UNTAGGED;
+ }
+
+ /* Increase sequence number of SRB */
+ if (!SrbInfo->SequenceNumber)
+ {
+ /* Increase global sequence number */
+ DeviceExtension->SequenceNumber++;
+
+ /* Assign it */
+ SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber;
+ }
+
+ /* Check some special SRBs */
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
+ {
+ /* Some special handling */
+ DPRINT1("Abort command! Unimplemented now\n");
+ }
+ else
+ {
+ SrbInfo->Srb = Srb;
+ }
+
+ if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
+ {
+ // Store the MDL virtual address in SrbInfo structure
+ SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
+
+ if (DeviceExtension->MapBuffers)
+ {
+ /* Calculate offset within DataBuffer */
+ SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress);
+ Srb->DataBuffer = SrbInfo->DataOffset +
+ (ULONG)((PUCHAR)Srb->DataBuffer -
+ (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
+ }
+
+ if (DeviceExtension->AdapterObject)
+ {
+ /* Flush buffers */
+ KeFlushIoBuffers(Irp->MdlAddress,
+ Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
+ TRUE);
+ }
+
+ if (DeviceExtension->MapRegisters)
+ {
+ /* Calculate number of needed map registers */
+ SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
+ Srb->DataBuffer,
+ Srb->DataTransferLength);
+
+ /* Allocate adapter channel */
+ Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject,
+ DeviceExtension->DeviceObject,
+ SrbInfo->NumberOfMapRegisters,
+ SpiAdapterControl,
+ SrbInfo);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("IoAllocateAdapterChannel() failed!\n");
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(RequestComplete,
+ DeviceExtension + 1,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ DeviceExtension + 1);
+
+ /* Request DPC for that work */
+ IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
+ }
+
+ /* Control goes to SpiAdapterControl */
+ return;
+ }
+ }
+
+ /* Increase active request counter */
+ CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter);
+
+ if (CounterResult == 0 &&
+ DeviceExtension->AdapterObject != NULL &&
+ !DeviceExtension->MapRegisters)
+ {
+ IoAllocateAdapterChannel(
+ DeviceExtension->AdapterObject,
+ DeviceObject,
+ DeviceExtension->PortCapabilities.MaximumPhysicalPages,
+ ScsiPortAllocateAdapterChannel,
+ LunExtension
+ );
+
+ return;
+ }
+
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+ if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
+ ScsiPortStartPacket,
+ DeviceObject))
+ {
+ DPRINT("Synchronization failed!\n");
+
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ Irp->IoStatus.Information = 0;
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+ else
+ {
+ /* Release the spinlock only */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+
+
+ DPRINT("ScsiPortStartIo() done\n");
+}
+
+
+static BOOLEAN NTAPI
+ScsiPortStartPacket(IN OUT PVOID Context)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PIO_STACK_LOCATION IrpStack;
+ PSCSI_REQUEST_BLOCK Srb;
+ PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+ BOOLEAN Result;
+ BOOLEAN StartTimer;
+
+ DPRINT("ScsiPortStartPacket() called\n");
+
+ DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
+ Srb = IrpStack->Parameters.Scsi.Srb;
+
+ /* Get LUN extension */
+ LunExtension = SpiGetLunExtension(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ /* Check if we are in a reset state */
+ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
+ {
+ /* Mark the we've got requests while being in the reset state */
+ DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST;
+ return TRUE;
+ }
+
+ /* Set the time out value */
+ DeviceExtension->TimerCount = Srb->TimeOutValue;
+
+ /* We are busy */
+ DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY;
+
+ if (LunExtension->RequestTimeout != -1)
+ {
+ /* Timer already active */
+ StartTimer = FALSE;
+ }
+ else
+ {
+ /* It hasn't been initialized yet */
+ LunExtension->RequestTimeout = Srb->TimeOutValue;
+ StartTimer = TRUE;
+ }
+
+ if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
+ {
+ /* Handle bypass-requests */
+
+ /* Is this an abort request? */
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
+ {
+ /* Get pointer to SRB info structure */
+ SrbInfo = SpiGetSrbData(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ Srb->QueueTag);
+
+ /* Check if the request is still "active" */
+ if (SrbInfo == NULL ||
+ SrbInfo->Srb == NULL ||
+ !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
+ {
+ /* It's not, mark it as active then */
+ Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
+
+ if (StartTimer)
+ LunExtension->RequestTimeout = -1;
+
+ DPRINT("Request has been already completed, but abort request came\n");
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ /* Notify about request complete */
+ ScsiPortNotification(RequestComplete,
+ DeviceExtension->MiniPortDeviceExtension,
+ Srb);
+
+ /* and about readiness for the next request */
+ ScsiPortNotification(NextRequest,
+ DeviceExtension->MiniPortDeviceExtension);
+
+ /* They might ask for some work, so queue the DPC for them */
+ IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
+
+ /* We're done in this branch */
+ return TRUE;
+ }
+ }
+ else
+ {
+ /* Add number of queued requests */
+ LunExtension->QueueCount++;
+ }
+
+ /* Bypass requests don't need request sense */
+ LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE;
+
+ /* Is disconnect disabled for this request? */
+ if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+ {
+ /* Set the corresponding flag */
+ DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
+ }
+
+ /* Transfer timeout value from Srb to Lun */
+ LunExtension->RequestTimeout = Srb->TimeOutValue;
+ }
+ else
+ {
+ if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+ {
+ /* It's a disconnect, so no more requests can go */
+ DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
+ }
+
+ LunExtension->Flags |= SCSI_PORT_LU_ACTIVE;
+
+ /* Increment queue count */
+ LunExtension->QueueCount++;
+
+ /* If it's tagged - special thing */
+ if (Srb->QueueTag != SP_UNTAGGED)
+ {
+ SrbInfo = &DeviceExtension->SrbInfo[Srb->QueueTag - 1];
+
+ /* Chek for consistency */
+ ASSERT(SrbInfo->Requests.Blink == NULL);
+
+ /* Insert it into the list of requests */
+ InsertTailList(&LunExtension->SrbInfo.Requests, &SrbInfo->Requests);
+ }
+ }
+
+ /* Mark this Srb active */
+ Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
+
+ /* Call HwStartIo routine */
+ Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
+ Srb);
+
+ /* If notification is needed, then request a DPC */
+ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
+ IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
+
+ return Result;
+}
+
+IO_ALLOCATION_ACTION
+NTAPI
+SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID MapRegisterBase,
+ PVOID Context)
+{
+ PSCSI_REQUEST_BLOCK Srb;
+ PSCSI_SG_ADDRESS ScatterGatherList;
+ KIRQL CurrentIrql;
+ PIO_STACK_LOCATION IrpStack;
+ ULONG TotalLength = 0;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PUCHAR DataVA;
+ BOOLEAN WriteToDevice;
+
+ /* Get pointers to SrbInfo and DeviceExtension */
+ SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
+ DeviceExtension = DeviceObject->DeviceExtension;
+
+ /* Get pointer to SRB */
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+ Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
+
+ /* Depending on the map registers number, we allocate
+ either from NonPagedPool, or from our static list */
+ if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
+ {
+ SrbInfo->ScatterGather = ExAllocatePoolWithTag(
+ NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT);
+
+ if (SrbInfo->ScatterGather == NULL)
+ ASSERT(FALSE);
+
+ Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
+ }
+ else
+ {
+ SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
+ }
+
+ /* Use chosen SG list source */
+ ScatterGatherList = SrbInfo->ScatterGather;
+
+ /* Save map registers base */
+ SrbInfo->BaseOfMapRegister = MapRegisterBase;
+
+ /* Determine WriteToDevice flag */
+ WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
+
+ /* Get virtual address of the data buffer */
+ DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
+ ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
+
+ /* Build the actual SG list */
+ while (TotalLength < Srb->DataTransferLength)
+ {
+ if (!ScatterGatherList)
+ break;
+
+ ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
+ ScatterGatherList->PhysicalAddress = IoMapTransfer(NULL,
+ Irp->MdlAddress,
+ MapRegisterBase,
+ DataVA + TotalLength,
+ &ScatterGatherList->Length,
+ WriteToDevice);
+
+ TotalLength += ScatterGatherList->Length;
+ ScatterGatherList++;
+ }
+
+ /* Schedule an active request */
+ InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
+ KeSynchronizeExecution(DeviceExtension->Interrupt,
+ ScsiPortStartPacket,
+ DeviceObject);
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
+
+ return DeallocateObjectKeepRegisters;
+}
+
+static PSCSI_PORT_LUN_EXTENSION
+SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ ULONG LunExtensionSize;
+
+ DPRINT("SpiAllocateLunExtension (%p)\n",
+ DeviceExtension);
+
+ /* Round LunExtensionSize first to the sizeof LONGLONG */
+ LunExtensionSize = (DeviceExtension->LunExtensionSize +
+ sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
+
+ LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
+ DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
+
+ LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT);
+ if (LunExtension == NULL)
+ {
+ DPRINT1("Out of resources!\n");
+ return NULL;
+ }
+
+ /* Zero everything */
+ RtlZeroMemory(LunExtension, LunExtensionSize);
+
+ /* Initialize a list of requests */
+ InitializeListHead(&LunExtension->SrbInfo.Requests);
+
+ /* Initialize timeout counter */
+ LunExtension->RequestTimeout = -1;
+
+ /* Set maximum queue size */
+ LunExtension->MaxQueueCount = 256;
+
+ /* Initialize request queue */
+ KeInitializeDeviceQueue (&LunExtension->DeviceQueue);
+
+ return LunExtension;
+}
+
+static PSCSI_PORT_LUN_EXTENSION
+SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun)
+{
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+
+ DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
+ DeviceExtension, PathId, TargetId, Lun);
+
+ /* Get appropriate list */
+ LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER];
+
+ /* Iterate it until we find what we need */
+ while (LunExtension)
+ {
+ if (LunExtension->TargetId == TargetId &&
+ LunExtension->Lun == Lun &&
+ LunExtension->PathId == PathId)
+ {
+ /* All matches, return */
+ return LunExtension;
+ }
+
+ /* Advance to the next item */
+ LunExtension = LunExtension->Next;
+ }
+
+ /* We did not find anything */
+ DPRINT("Nothing found\n");
+ return NULL;
+}
+
+static PSCSI_REQUEST_BLOCK_INFO
+SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ PSCSI_PORT_LUN_EXTENSION LunExtension,
+ PSCSI_REQUEST_BLOCK Srb)
+{
+ PCHAR SrbExtension;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+
+ /* Spinlock must be held while this function executes */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+ /* Allocate SRB data structure */
+ if (DeviceExtension->NeedSrbDataAlloc)
+ {
+ /* Treat the abort request in a special way */
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
+ {
+ SrbInfo = SpiGetSrbData(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ Srb->QueueTag);
+ }
+ else if (Srb->SrbFlags &
+ (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) &&
+ !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+ )
+ {
+ /* Do not process tagged commands if need request sense is set */
+ if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
+ {
+ ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
+
+ LunExtension->PendingRequest = Srb->OriginalRequest;
+ LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
+
+ /* Relese the spinlock and return */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ return NULL;
+ }
+
+ ASSERT(LunExtension->SrbInfo.Srb == NULL);
+ SrbInfo = DeviceExtension->FreeSrbInfo;
+
+ if (SrbInfo == NULL)
+ {
+ /* No SRB structures left in the list. We have to leave
+ and wait while we are called again */
+
+ DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ return NULL;
+ }
+
+ DeviceExtension->FreeSrbInfo = (PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink;
+
+ /* QueueTag must never be 0, so +1 to it */
+ Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1;
+ }
+ else
+ {
+ /* Usual untagged command */
+ if (
+ (!IsListEmpty(&LunExtension->SrbInfo.Requests) ||
+ LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) &&
+ !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
+ )
+ {
+ /* Mark it as pending and leave */
+ ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
+ LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
+ LunExtension->PendingRequest = Srb->OriginalRequest;
+
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ return(NULL);
+ }
+
+ Srb->QueueTag = SP_UNTAGGED;
+ SrbInfo = &LunExtension->SrbInfo;
+ }
+ }
+ else
+ {
+ Srb->QueueTag = SP_UNTAGGED;
+ SrbInfo = &LunExtension->SrbInfo;
}
- DPRINT("Srb: %p\n", Srb);
- DPRINT("Srb->Function: %lu\n", Srb->Function);
- DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
+ /* Allocate SRB extension structure */
+ if (DeviceExtension->NeedSrbExtensionAlloc)
+ {
+ /* Check the list of free extensions */
+ SrbExtension = DeviceExtension->FreeSrbExtensions;
+
+ /* If no free extensions... */
+ if (SrbExtension == NULL)
+ {
+ /* Free SRB data */
+ if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND &&
+ Srb->QueueTag != SP_UNTAGGED)
+ {
+ SrbInfo->Requests.Blink = NULL;
+ SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
+ DeviceExtension->FreeSrbInfo = SrbInfo;
+ }
+
+ /* Return, in order to be called again later */
+ DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ return NULL;
+ }
+
+ /* Remove that free SRB extension from the list (since
+ we're going to use it) */
+ DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension);
+
+ /* Spinlock can be released now */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ Srb->SrbExtension = SrbExtension;
+
+ if (Srb->SenseInfoBuffer != NULL &&
+ DeviceExtension->SupportsAutoSense)
+ {
+ /* Store pointer to the SenseInfo buffer */
+ SrbInfo->SaveSenseRequest = Srb->SenseInfoBuffer;
- LunExtension = SpiGetLunExtension(DeviceExtension,
- Srb->PathId,
- Srb->TargetId,
- Srb->Lun);
- if (LunExtension == NULL)
+ /* Does data fit the buffer? */
+ if (Srb->SenseInfoBufferLength > sizeof(SENSE_DATA))
+ {
+ /* No, disabling autosense at all */
+ Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
+ }
+ else
+ {
+ /* Yes, update the buffer pointer */
+ Srb->SenseInfoBuffer = SrbExtension + DeviceExtension->SrbExtensionSize;
+ }
+ }
+ }
+ else
{
- Status = STATUS_NO_SUCH_DEVICE;
+ /* Cleanup... */
+ Srb->SrbExtension = NULL;
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
- Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = 0;
+ return SrbInfo;
+}
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return(Status);
+static NTSTATUS
+SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
+ IN PSCSI_LUN_INFO LunInfo)
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ PIO_STACK_LOCATION IrpStack;
+ KEVENT Event;
+ KIRQL Irql;
+ PIRP Irp;
+ NTSTATUS Status;
+ PINQUIRYDATA InquiryBuffer;
+ PSENSE_DATA SenseBuffer;
+ BOOLEAN KeepTrying = TRUE;
+ ULONG RetryCount = 0;
+ SCSI_REQUEST_BLOCK Srb;
+ PCDB Cdb;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+
+ DPRINT ("SpiSendInquiry() called\n");
+
+ DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ InquiryBuffer = ExAllocatePoolWithTag (NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_SCSIPORT);
+ if (InquiryBuffer == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ SenseBuffer = ExAllocatePoolWithTag (NonPagedPool, SENSE_BUFFER_SIZE, TAG_SCSIPORT);
+ if (SenseBuffer == NULL)
+ {
+ ExFreePool(InquiryBuffer);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ while (KeepTrying)
+ {
+ /* Initialize event for waiting */
+ KeInitializeEvent(&Event,
+ NotificationEvent,
+ FALSE);
+
+ /* Create an IRP */
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
+ DeviceObject,
+ NULL,
+ 0,
+ InquiryBuffer,
+ INQUIRYDATABUFFERSIZE,
+ TRUE,
+ &Event,
+ &IoStatusBlock);
+ if (Irp == NULL)
+ {
+ DPRINT("IoBuildDeviceIoControlRequest() failed\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Prepare SRB */
+ RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
+ Srb.OriginalRequest = Irp;
+ Srb.PathId = LunInfo->PathId;
+ Srb.TargetId = LunInfo->TargetId;
+ Srb.Lun = LunInfo->Lun;
+ Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
+ Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+ Srb.TimeOutValue = 4;
+ Srb.CdbLength = 6;
+
+ Srb.SenseInfoBuffer = SenseBuffer;
+ Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
+
+ Srb.DataBuffer = InquiryBuffer;
+ Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
+
+ /* Attach Srb to the Irp */
+ IrpStack = IoGetNextIrpStackLocation (Irp);
+ IrpStack->Parameters.Scsi.Srb = &Srb;
+
+ /* Fill in CDB */
+ Cdb = (PCDB)Srb.Cdb;
+ Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
+ Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
+ Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
+
+ /* Call the driver */
+ Status = IoCallDriver(DeviceObject, Irp);
+
+ /* Wait for it to complete */
+ if (Status == STATUS_PENDING)
+ {
+ DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
+ KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = IoStatusBlock.Status;
+ }
+
+ DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
+
+ if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS)
+ {
+ /* All fine, copy data over */
+ RtlCopyMemory(LunInfo->InquiryData,
+ InquiryBuffer,
+ INQUIRYDATABUFFERSIZE);
+
+ Status = STATUS_SUCCESS;
+ KeepTrying = FALSE;
+ }
+ else
+ {
+ DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus);
+ /* Check if the queue is frozen */
+ if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
+ {
+ /* Something weird happened, deal with it (unfreeze the queue) */
+ KeepTrying = FALSE;
+
+ DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId);
+
+ LunExtension = SpiGetLunExtension(DeviceExtension,
+ LunInfo->PathId,
+ LunInfo->TargetId,
+ LunInfo->Lun);
+
+ /* Clear frozen flag */
+ LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
+
+ /* Acquire the spinlock */
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
+
+ /* Process the request */
+ SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
+
+ /* SpiGetNextRequestFromLun() releases the spinlock,
+ so we just lower irql back to what it was before */
+ KeLowerIrql(Irql);
+ }
+
+ /* Check if data overrun happened */
+ if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
+ {
+ DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId);
+ /* Nothing dramatic, just copy data, but limiting the size */
+ RtlCopyMemory(LunInfo->InquiryData,
+ InquiryBuffer,
+ (Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ?
+ INQUIRYDATABUFFERSIZE : Srb.DataTransferLength);
+
+ Status = STATUS_SUCCESS;
+ KeepTrying = FALSE;
+ }
+ else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
+ SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
+ {
+ /* LUN is not valid, but some device responds there.
+ Mark it as invalid anyway */
+
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ KeepTrying = FALSE;
+ }
+ else
+ {
+ /* Retry a couple of times if no timeout happened */
+ if ((RetryCount < 2) &&
+ (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
+ (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT))
+ {
+ RetryCount++;
+ KeepTrying = TRUE;
+ }
+ else
+ {
+ /* That's all, go to exit */
+ KeepTrying = FALSE;
+
+ /* Set status according to SRB status */
+ if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
+ SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
+ {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ else
+ {
+ Status = STATUS_IO_DEVICE_ERROR;
+ }
+ }
+ }
+ }
+ }
+
+ /* Free buffers */
+ ExFreePool(InquiryBuffer);
+ ExFreePool(SenseBuffer);
+
+ DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status);
+
+ return Status;
+}
+
+
+/* Scans all SCSI buses */
+static VOID
+SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ ULONG Bus;
+ ULONG Target;
+ ULONG Lun;
+ PSCSI_BUS_SCAN_INFO BusScanInfo;
+ PSCSI_LUN_INFO LastLunInfo, LunInfo, LunInfoExists;
+ BOOLEAN DeviceExists;
+ ULONG Hint;
+ NTSTATUS Status;
+ ULONG DevicesFound;
+
+ DPRINT("SpiScanAdapter() called\n");
+
+ /* Scan all buses */
+ for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
+ {
+ DPRINT(" Scanning bus %d\n", Bus);
+ DevicesFound = 0;
+
+ /* Get pointer to the scan information */
+ BusScanInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus];
+
+ if (BusScanInfo)
+ {
+ /* Find the last LUN info in the list */
+ LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
+ LastLunInfo = LunInfo;
+
+ while (LunInfo != NULL)
+ {
+ LastLunInfo = LunInfo;
+ LunInfo = LunInfo->Next;
+ }
+ }
+ else
+ {
+ /* We need to allocate this buffer */
+ BusScanInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_BUS_SCAN_INFO), TAG_SCSIPORT);
+
+ if (!BusScanInfo)
+ {
+ DPRINT1("Out of resources!\n");
+ return;
+ }
+
+ /* Store the pointer in the BusScanInfo array */
+ DeviceExtension->BusesConfig->BusScanInfo[Bus] = BusScanInfo;
+
+ /* Fill this struct (length and bus ids for now) */
+ BusScanInfo->Length = sizeof(SCSI_BUS_SCAN_INFO);
+ BusScanInfo->LogicalUnitsCount = 0;
+ BusScanInfo->BusIdentifier = DeviceExtension->PortConfig->InitiatorBusId[Bus];
+ BusScanInfo->LunInfo = NULL;
+
+ /* Set pointer to the last LUN info to NULL */
+ LastLunInfo = NULL;
+ }
+
+ /* Create LUN information structure */
+ LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
+
+ if (LunInfo == NULL)
+ {
+ DPRINT1("Out of resources!\n");
+ return;
+ }
+
+ RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
+
+ /* Create LunExtension */
+ LunExtension = SpiAllocateLunExtension (DeviceExtension);
+
+ /* And send INQUIRY to every target */
+ for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
+ {
+ /* TODO: Support scan bottom-up */
+
+ /* Skip if it's the same address */
+ if (Target == BusScanInfo->BusIdentifier)
+ continue;
+
+ /* Try to find an existing device here */
+ DeviceExists = FALSE;
+ LunInfoExists = BusScanInfo->LunInfo;
+
+ /* Find matching address on this bus */
+ while (LunInfoExists)
+ {
+ if (LunInfoExists->TargetId == Target)
+ {
+ DeviceExists = TRUE;
+ break;
+ }
+
+ /* Advance to the next one */
+ LunInfoExists = LunInfoExists->Next;
+ }
+
+ /* No need to bother rescanning, since we already did that before */
+ if (DeviceExists)
+ continue;
+
+ /* Scan all logical units */
+ for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
+ {
+ if ((!LunExtension) || (!LunInfo))
+ break;
+
+ /* Add extension to the list */
+ Hint = (Target + Lun) % LUS_NUMBER;
+ LunExtension->Next = DeviceExtension->LunExtensionList[Hint];
+ DeviceExtension->LunExtensionList[Hint] = LunExtension;
+
+ /* Fill Path, Target, Lun fields */
+ LunExtension->PathId = LunInfo->PathId = (UCHAR)Bus;
+ LunExtension->TargetId = LunInfo->TargetId = (UCHAR) Target;
+ LunExtension->Lun = LunInfo->Lun = (UCHAR)Lun;
+
+ /* Set flag to prevent race conditions */
+ LunExtension->Flags |= SCSI_PORT_SCAN_IN_PROGRESS;
+
+ /* Zero LU extension contents */
+ if (DeviceExtension->LunExtensionSize)
+ {
+ RtlZeroMemory(LunExtension + 1,
+ DeviceExtension->LunExtensionSize);
+ }
+
+ /* Finally send the inquiry command */
+ Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* Let's see if we really found a device */
+ PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
+
+ /* Check if this device is unsupported */
+ if (InquiryData->DeviceTypeQualifier == DEVICE_QUALIFIER_NOT_SUPPORTED)
+ {
+ DeviceExtension->LunExtensionList[Hint] =
+ DeviceExtension->LunExtensionList[Hint]->Next;
+
+ continue;
+ }
+
+ /* Clear the "in scan" flag */
+ LunExtension->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS;
+
+ DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
+ InquiryData->DeviceType, Bus, Target, Lun);
+
+ /* Add this info to the linked list */
+ LunInfo->Next = NULL;
+ if (LastLunInfo)
+ LastLunInfo->Next = LunInfo;
+ else
+ BusScanInfo->LunInfo = LunInfo;
+
+ /* Store the last LUN info */
+ LastLunInfo = LunInfo;
+
+ /* Store DeviceObject */
+ LunInfo->DeviceObject = DeviceExtension->DeviceObject;
+
+ /* Allocate another buffer */
+ LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
+
+ if (!LunInfo)
+ {
+ DPRINT1("Out of resources!\n");
+ break;
+ }
+
+ RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
+
+ /* Create a new LU extension */
+ LunExtension = SpiAllocateLunExtension(DeviceExtension);
+
+ DevicesFound++;
+ }
+ else
+ {
+ /* Remove this LUN from the list */
+ DeviceExtension->LunExtensionList[Hint] =
+ DeviceExtension->LunExtensionList[Hint]->Next;
+
+ /* Decide whether we are continuing or not */
+ if (Status == STATUS_INVALID_DEVICE_REQUEST)
+ continue;
+ else
+ break;
+ }
+ }
+ }
+
+ /* Free allocated buffers */
+ if (LunExtension)
+ ExFreePool(LunExtension);
+
+ if (LunInfo)
+ ExFreePool(LunInfo);
+
+ /* Sum what we found */
+ BusScanInfo->LogicalUnitsCount += (UCHAR) DevicesFound;
+ DPRINT(" Found %d devices on bus %d\n", DevicesFound, Bus);
+ }
+
+ DPRINT ("SpiScanAdapter() done\n");
+}
+
+
+static NTSTATUS
+SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ PIRP Irp)
+{
+ ULONG InquiryDataSize;
+ PSCSI_LUN_INFO LunInfo;
+ ULONG BusCount, LunCount, Length;
+ PIO_STACK_LOCATION IrpStack;
+ PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
+ PSCSI_INQUIRY_DATA InquiryData;
+ PSCSI_BUS_DATA BusData;
+ ULONG Bus;
+ PUCHAR Buffer;
+
+ DPRINT("SpiGetInquiryData() called\n");
+
+ /* Get pointer to the buffer */
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+ Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+ /* Initialize bus and LUN counters */
+ BusCount = DeviceExtension->BusesConfig->NumberOfBuses;
+ LunCount = 0;
+
+ /* Calculate total number of LUNs */
+ for (Bus = 0; Bus < BusCount; Bus++)
+ LunCount += DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
+
+ /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
+ InquiryDataSize =
+ ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
+ sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
+
+ /* Calculate data size */
+ Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) *
+ sizeof(SCSI_BUS_DATA);
+
+ Length += InquiryDataSize * LunCount;
+
+ /* Check, if all data is going to fit into provided buffer */
+ if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length)
+ {
+ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* Store data size in the IRP */
+ Irp->IoStatus.Information = Length;
+
+ DPRINT("Data size: %lu\n", Length);
+
+ AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
+
+ AdapterBusInfo->NumberOfBuses = (UCHAR)BusCount;
+
+ /* Point InquiryData to the corresponding place inside Buffer */
+ InquiryData = (PSCSI_INQUIRY_DATA)(Buffer + sizeof(SCSI_ADAPTER_BUS_INFO) +
+ (BusCount - 1) * sizeof(SCSI_BUS_DATA));
+
+ /* Loop each bus */
+ for (Bus = 0; Bus < BusCount; Bus++)
+ {
+ BusData = &AdapterBusInfo->BusData[Bus];
+
+ /* Calculate and save an offset of the inquiry data */
+ BusData->InquiryDataOffset = (PUCHAR)InquiryData - Buffer;
+
+ /* Get a pointer to the LUN information structure */
+ LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
+
+ /* Store Initiator Bus Id */
+ BusData->InitiatorBusId =
+ DeviceExtension->BusesConfig->BusScanInfo[Bus]->BusIdentifier;
+
+ /* Store LUN count */
+ BusData->NumberOfLogicalUnits =
+ DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
+
+ /* Loop all LUNs */
+ while (LunInfo != NULL)
+ {
+ DPRINT("(Bus %lu Target %lu Lun %lu)\n",
+ Bus, LunInfo->TargetId, LunInfo->Lun);
+
+ /* Fill InquiryData with values */
+ InquiryData->PathId = LunInfo->PathId;
+ InquiryData->TargetId = LunInfo->TargetId;
+ InquiryData->Lun = LunInfo->Lun;
+ InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
+ InquiryData->DeviceClaimed = LunInfo->DeviceClaimed;
+ InquiryData->NextInquiryDataOffset =
+ (PUCHAR)InquiryData + InquiryDataSize - Buffer;
+
+ /* Copy data in it */
+ RtlCopyMemory(InquiryData->InquiryData,
+ LunInfo->InquiryData,
+ INQUIRYDATABUFFERSIZE);
+
+ /* Move to the next LUN */
+ LunInfo = LunInfo->Next;
+ InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize);
+ }
+
+ /* Either mark the end, or set offset to 0 */
+ if (BusData->NumberOfLogicalUnits != 0)
+ ((PSCSI_INQUIRY_DATA) ((PCHAR) InquiryData - InquiryDataSize))->NextInquiryDataOffset = 0;
+ else
+ BusData->InquiryDataOffset = 0;
+ }
+
+ /* Finish with success */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ return STATUS_SUCCESS;
+}
+
+static PSCSI_REQUEST_BLOCK_INFO
+SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN UCHAR QueueTag)
+{
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+
+ if (QueueTag == SP_UNTAGGED)
+ {
+ /* Untagged request, get LU and return pointer to SrbInfo */
+ LunExtension = SpiGetLunExtension(DeviceExtension,
+ PathId,
+ TargetId,
+ Lun);
+
+ /* Return NULL in case of error */
+ if (!LunExtension)
+ return(NULL);
+
+ /* Return the pointer to SrbInfo */
+ return &LunExtension->SrbInfo;
+ }
+ else
+ {
+ /* Make sure the tag is valid, if it is - return the data */
+ if (QueueTag > DeviceExtension->SrbDataCount || QueueTag < 1)
+ return NULL;
+ else
+ return &DeviceExtension->SrbInfo[QueueTag -1];
+ }
+}
+
+static VOID
+SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK InitialSrb)
+{
+ PSCSI_REQUEST_BLOCK Srb;
+ PCDB Cdb;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpStack;
+ LARGE_INTEGER LargeInt;
+ PVOID *Ptr;
+
+ DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb);
+
+ /* Allocate Srb */
+ Srb = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(PVOID), TAG_SCSIPORT);
+ RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ /* Allocate IRP */
+ LargeInt.QuadPart = (LONGLONG) 1;
+ Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
+ DeviceExtension->DeviceObject,
+ InitialSrb->SenseInfoBuffer,
+ InitialSrb->SenseInfoBufferLength,
+ &LargeInt,
+ NULL);
+
+ IoSetCompletionRoutine(Irp,
+ (PIO_COMPLETION_ROUTINE)SpiCompletionRoutine,
+ Srb,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ if (!Srb)
+ {
+ DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb);
+ return;
+ }
+
+ IrpStack = IoGetNextIrpStackLocation(Irp);
+ IrpStack->MajorFunction = IRP_MJ_SCSI;
+
+ /* Put Srb address into Irp... */
+ IrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
+
+ /* ...and vice versa */
+ Srb->OriginalRequest = Irp;
+
+ /* Save Srb */
+ Ptr = (PVOID *)(Srb+1);
+ *Ptr = InitialSrb;
+
+ /* Build CDB for REQUEST SENSE */
+ Srb->CdbLength = 6;
+ Cdb = (PCDB)Srb->Cdb;
+
+ Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
+ Cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
+ Cdb->CDB6INQUIRY.Reserved1 = 0;
+ Cdb->CDB6INQUIRY.PageCode = 0;
+ Cdb->CDB6INQUIRY.IReserved = 0;
+ Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)InitialSrb->SenseInfoBufferLength;
+ Cdb->CDB6INQUIRY.Control = 0;
+
+ /* Set address */
+ Srb->TargetId = InitialSrb->TargetId;
+ Srb->Lun = InitialSrb->Lun;
+ Srb->PathId = InitialSrb->PathId;
+
+ Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+ Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+
+ /* Timeout will be 2 seconds */
+ Srb->TimeOutValue = 2;
+
+ /* No auto request sense */
+ Srb->SenseInfoBufferLength = 0;
+ Srb->SenseInfoBuffer = NULL;
+
+ /* Set necessary flags */
+ Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE |
+ SRB_FLAGS_DISABLE_DISCONNECT;
+
+ /* Transfer disable synch transfer flag */
+ if (InitialSrb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER)
+ Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+
+ Srb->DataBuffer = InitialSrb->SenseInfoBuffer;
+
+ /* Fill the transfer length */
+ Srb->DataTransferLength = InitialSrb->SenseInfoBufferLength;
+
+ /* Clear statuses */
+ Srb->ScsiStatus = Srb->SrbStatus = 0;
+ Srb->NextSrb = 0;
+
+ /* Call the driver */
+ (VOID)IoCallDriver(DeviceExtension->DeviceObject, Irp);
+
+ DPRINT("SpiSendRequestSense() done\n");
+}
+
+
+static
+VOID
+NTAPI
+SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
+ OUT PBOOLEAN NeedToCallStartIo)
+{
+ PSCSI_REQUEST_BLOCK Srb;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ LONG Result;
+ PIRP Irp;
+ ULONG SequenceNumber;
+
+ Srb = SrbInfo->Srb;
+ Irp = Srb->OriginalRequest;
+
+ /* Get Lun extension */
+ LunExtension = SpiGetLunExtension(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION &&
+ DeviceExtension->MapBuffers &&
+ Irp->MdlAddress)
+ {
+ /* MDL is shared if transfer is broken into smaller parts */
+ Srb->DataBuffer = (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
+ ((PCCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
+
+ /* In case of data going in, flush the buffers */
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
+ {
+ KeFlushIoBuffers(Irp->MdlAddress,
+ TRUE,
+ FALSE);
+ }
+ }
+
+ /* Flush adapter if needed */
+ if (SrbInfo->BaseOfMapRegister)
+ {
+ /* TODO: Implement */
+ ASSERT(FALSE);
+ }
+
+ /* Clear the request */
+ SrbInfo->Srb = NULL;
+
+ /* If disconnect is disabled... */
+ if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+ {
+ /* Acquire the spinlock since we mess with flags */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+ /* Set corresponding flag */
+ DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
+
+ /* Clear the timer if needed */
+ if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET))
+ DeviceExtension->TimerCount = -1;
+
+ /* Spinlock is not needed anymore */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ if (!(DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) &&
+ !(DeviceExtension->Flags & SCSI_PORT_DEVICE_BUSY) &&
+ !(*NeedToCallStartIo))
+ {
+ /* We're not busy, but we have a request pending */
+ IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
+ }
+ }
+
+ /* Scatter/gather */
+ if (Srb->SrbFlags & SRB_FLAGS_SGLIST_FROM_POOL)
+ {
+ /* TODO: Implement */
+ ASSERT(FALSE);
+ }
+
+ /* Acquire spinlock (we're freeing SrbExtension) */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+ /* Free it (if needed) */
+ if (Srb->SrbExtension)
+ {
+ if (Srb->SenseInfoBuffer != NULL && DeviceExtension->SupportsAutoSense)
+ {
+ ASSERT(Srb->SenseInfoBuffer == NULL || SrbInfo->SaveSenseRequest != NULL);
+
+ if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)
+ {
+ /* Copy sense data to the buffer */
+ RtlCopyMemory(SrbInfo->SaveSenseRequest,
+ Srb->SenseInfoBuffer,
+ Srb->SenseInfoBufferLength);
+ }
+
+ /* And restore the pointer */
+ Srb->SenseInfoBuffer = SrbInfo->SaveSenseRequest;
+ }
+
+ /* Put it into the free srb extensions list */
+ *((PVOID *)Srb->SrbExtension) = DeviceExtension->FreeSrbExtensions;
+ DeviceExtension->FreeSrbExtensions = Srb->SrbExtension;
+ }
+
+ /* Save transfer length in the IRP */
+ Irp->IoStatus.Information = Srb->DataTransferLength;
+
+ SequenceNumber = SrbInfo->SequenceNumber;
+ SrbInfo->SequenceNumber = 0;
+
+ /* Decrement the queue count */
+ LunExtension->QueueCount--;
+
+ /* Free Srb, if needed*/
+ if (Srb->QueueTag != SP_UNTAGGED)
+ {
+ /* Put it into the free list */
+ SrbInfo->Requests.Blink = NULL;
+ SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
+ DeviceExtension->FreeSrbInfo = SrbInfo;
+ }
+
+ /* SrbInfo is not used anymore */
+ SrbInfo = NULL;
+
+ if (DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING)
+ {
+ /* Clear the flag */
+ DeviceExtension->Flags &= ~SCSI_PORT_REQUEST_PENDING;
+
+ /* Note the caller about StartIo */
+ *NeedToCallStartIo = TRUE;
+ }
+
+ if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
+ {
+ /* Start the packet */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ if (!(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) &&
+ LunExtension->RequestTimeout == -1)
+ {
+ /* Start the next packet */
+ SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
+ }
+ else
+ {
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+
+ DPRINT("IoCompleting request IRP 0x%p\n", Irp);
+
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ /* Decrement number of active requests, and analyze the result */
+ Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
+
+ if (Result < 0 &&
+ !DeviceExtension->MapRegisters &&
+ DeviceExtension->AdapterObject != NULL)
+ {
+ /* Nullify map registers */
+ DeviceExtension->MapRegisterBase = NULL;
+ IoFreeAdapterChannel(DeviceExtension->AdapterObject);
+ }
+
+ /* Exit, we're done */
+ return;
}
- switch (Srb->Function)
+ /* Decrement number of active requests, and analyze the result */
+ Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
+
+ if (Result < 0 &&
+ !DeviceExtension->MapRegisters &&
+ DeviceExtension->AdapterObject != NULL)
{
- case SRB_FUNCTION_EXECUTE_SCSI:
- case SRB_FUNCTION_IO_CONTROL:
- IoMarkIrpPending(Irp);
- Srb->OriginalRequest = LunExtension;
- Irp->Tail.Overlay.DriverContext[3] = Srb;
- SpiProcessRequests(DeviceExtension, Irp);
- return(STATUS_PENDING);
-
- case SRB_FUNCTION_SHUTDOWN:
- case SRB_FUNCTION_FLUSH:
- if (DeviceExtension->PortConfig->CachesData == TRUE)
- {
- IoMarkIrpPending(Irp);
- Srb->OriginalRequest = LunExtension;
- Irp->Tail.Overlay.DriverContext[3] = Srb;
- SpiProcessRequests(DeviceExtension, Irp);
- return(STATUS_PENDING);
- }
- break;
+ /* Result is negative, so this is a slave, free map registers */
+ DeviceExtension->MapRegisterBase = NULL;
+ IoFreeAdapterChannel(DeviceExtension->AdapterObject);
+ }
- case SRB_FUNCTION_CLAIM_DEVICE:
- DPRINT (" SRB_FUNCTION_CLAIM_DEVICE\n");
+ /* Convert status */
+ Irp->IoStatus.Status = SpiStatusSrbToNt(Srb->SrbStatus);
- /* Reference device object and keep the device object */
- ObReferenceObject(DeviceObject);
- LunExtension->DeviceObject = DeviceObject;
- LunExtension->DeviceClaimed = TRUE;
- Srb->DataBuffer = DeviceObject;
- break;
+ /* It's not a bypass, it's busy or the queue is full? */
+ if ((Srb->ScsiStatus == SCSISTAT_BUSY ||
+ Srb->SrbStatus == SRB_STATUS_BUSY ||
+ Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) &&
+ !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE))
+ {
- case SRB_FUNCTION_RELEASE_DEVICE:
- DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
- DPRINT ("PathId: %lu TargetId: %lu Lun: %lu\n",
- Srb->PathId, Srb->TargetId, Srb->Lun);
+ DPRINT("Busy SRB status %x\n", Srb->SrbStatus);
- /* Dereference device object and clear the device object */
- ObDereferenceObject(LunExtension->DeviceObject);
- LunExtension->DeviceObject = NULL;
- LunExtension->DeviceClaimed = FALSE;
- break;
+ /* Requeu, if needed */
+ if (LunExtension->Flags & (LUNEX_FROZEN_QUEUE | LUNEX_BUSY))
+ {
+ DPRINT("it's being requeued\n");
- default:
- DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
- Status = STATUS_NOT_IMPLEMENTED;
- break;
- }
+ Srb->SrbStatus = SRB_STATUS_PENDING;
+ Srb->ScsiStatus = 0;
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = DataSize;
+ if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
+ &Irp->Tail.Overlay.DeviceQueueEntry,
+ Srb->QueueSortKey))
+ {
+ /* It's a big f.ck up if we got here */
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_BUSY;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ ASSERT(FALSE);
+ goto Error;
+ }
- return(Status);
-}
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+ else if (LunExtension->AttemptCount++ < 20)
+ {
+ /* LUN is still busy */
+ Srb->ScsiStatus = 0;
+ Srb->SrbStatus = SRB_STATUS_PENDING;
-/**********************************************************************
- * NAME INTERNAL
- * ScsiPortDeviceControl
- *
- * DESCRIPTION
- * Answer requests for device control calls
- *
- * RUN LEVEL
- * PASSIVE_LEVEL
- *
- * ARGUMENTS
- * Standard dispatch arguments
- *
- * RETURNS
- * NTSTATUS
- */
+ LunExtension->BusyRequest = Irp;
+ LunExtension->Flags |= LUNEX_BUSY;
-static NTSTATUS STDCALL
-ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- PIO_STACK_LOCATION Stack;
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- NTSTATUS Status = STATUS_SUCCESS;
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+ else
+ {
+Error:
+ /* Freeze the queue*/
+ Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
+ LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
- DPRINT("ScsiPortDeviceControl()\n");
+ /* "Unfull" the queue */
+ LunExtension->Flags &= ~LUNEX_FULL_QUEUE;
- Irp->IoStatus.Information = 0;
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ /* Return status that the device is not ready */
+ Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ }
- Stack = IoGetCurrentIrpStackLocation(Irp);
- DeviceExtension = DeviceObject->DeviceExtension;
+ return;
+ }
- switch (Stack->Parameters.DeviceIoControl.IoControlCode)
+ /* Start the next request, if LUN is idle, and this is sense request */
+ if (((Srb->ScsiStatus != SCSISTAT_CHECK_CONDITION) ||
+ (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) ||
+ !Srb->SenseInfoBuffer || !Srb->SenseInfoBufferLength)
+ && (Srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE))
{
- case IOCTL_SCSI_GET_DUMP_POINTERS:
- {
- PDUMP_POINTERS DumpPointers;
- DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
- DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
- DumpPointers->DeviceObject = DeviceObject;
-
- Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
- }
- break;
+ if (LunExtension->RequestTimeout == -1)
+ SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
+ else
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+ else
+ {
+ /* Freeze the queue */
+ Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
+ LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
+
+ /* Do we need a request sense? */
+ if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
+ !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
+ Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength)
+ {
+ /* If LUN is busy, we have to requeue it in order to allow request sense */
+ if (LunExtension->Flags & LUNEX_BUSY)
+ {
+ DPRINT("Requeueing busy request to allow request sense\n");
- case IOCTL_SCSI_GET_CAPABILITIES:
- {
- DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
+ if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
+ &LunExtension->BusyRequest->Tail.Overlay.DeviceQueueEntry,
+ Srb->QueueSortKey))
+ {
+ /* We should never get here */
+ ASSERT(FALSE);
- *((PIO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer) =
- DeviceExtension->PortCapabilities;
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ return;
- Irp->IoStatus.Information = sizeof(PIO_SCSI_CAPABILITIES);
- }
- break;
+ }
- case IOCTL_SCSI_GET_INQUIRY_DATA:
- {
- DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
+ /* Clear busy flags */
+ LunExtension->Flags &= ~(LUNEX_FULL_QUEUE | LUNEX_BUSY);
+ }
- /* Copy inquiry data to the port device extension */
- Irp->IoStatus.Information =
- SpiGetInquiryData(DeviceExtension,
- Irp->AssociatedIrp.SystemBuffer);
- DPRINT("Inquiry data size: %lu\n", Irp->IoStatus.Information);
- }
- break;
-
- case IOCTL_SCSI_PASS_THROUGH:
- DPRINT(" IOCTL_SCSI_PASS_THROUGH\n");
- Status = STATUS_NOT_IMPLEMENTED;
- break;
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
- case IOCTL_SCSI_PASS_THROUGH_DIRECT:
- DPRINT(" IOCTL_SCSI_PASS_THROUGH_DIRECT\n");
- Status = STATUS_NOT_IMPLEMENTED;
- break;
+ /* Send RequestSense */
+ SpiSendRequestSense(DeviceExtension, Srb);
- case IOCTL_SCSI_MINIPORT:
- DPRINT(" IOCTL_SCSI_MINIPORT\n");
- DPRINT(" Signature: %.8s\n", ((PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer)->Signature);
- DPRINT(" ControlCode: 0x%lX\n", ((PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer)->ControlCode);
- return SpiScsiMiniport(DeviceObject, Irp);
+ /* Exit */
+ return;
+ }
- default:
- DPRINT1(" unknown ioctl code: 0x%lX\n",
- Stack->Parameters.DeviceIoControl.IoControlCode);
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
}
- Irp->IoStatus.Status = Status;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- return Status;
+ /* Complete the request */
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
}
-static NTSTATUS STDCALL
-SpiCompletion(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context)
+NTSTATUS
+NTAPI
+SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context)
{
- PSCSI_REQUEST_BLOCK Srb;
-
- DPRINT("SpiCompletion(DeviceObject %x, Irp %x, Context %x)\n",
- DeviceObject, Irp, Context);
+ PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)Context;
+ PSCSI_REQUEST_BLOCK InitialSrb;
+ PIRP InitialIrp;
- Srb = (PSCSI_REQUEST_BLOCK)Context;
- Irp->IoStatus.Information = 0;
+ DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp);
- switch (SRB_STATUS(Srb->SrbStatus))
+ if ((Srb->Function == SRB_FUNCTION_RESET_BUS) ||
+ (Srb->Function == SRB_FUNCTION_ABORT_COMMAND))
{
- case SRB_STATUS_SUCCESS:
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = Srb->DataTransferLength;
- break;
+ /* Deallocate SRB and IRP and exit */
+ ExFreePool(Srb);
+ IoFreeIrp(Irp);
- case SRB_STATUS_INVALID_PATH_ID:
- case SRB_STATUS_INVALID_TARGET_ID:
- case SRB_STATUS_INVALID_LUN:
- case SRB_STATUS_NO_HBA:
- Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
- break;
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
- case SRB_STATUS_NO_DEVICE:
- Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
- break;
+ /* Get a pointer to the SRB and IRP which were initially sent */
+ InitialSrb = *((PVOID *)(Srb+1));
+ InitialIrp = InitialSrb->OriginalRequest;
- case SRB_STATUS_BUSY:
- Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
- break;
+ if ((SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
+ (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN))
+ {
+ /* Sense data is OK */
+ InitialSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
- case SRB_STATUS_DATA_OVERRUN:
- Irp->IoStatus.Status = STATUS_DATA_OVERRUN;
- Irp->IoStatus.Information = Srb->DataTransferLength;
- break;
+ /* Set length to be the same */
+ InitialSrb->SenseInfoBufferLength = (UCHAR)Srb->DataTransferLength;
+ }
- case SRB_STATUS_INVALID_REQUEST:
- Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ /* Make sure initial SRB's queue is frozen */
+ ASSERT(InitialSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN);
- default:
- Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
- break;
- }
+ /* Complete this request */
+ IoCompleteRequest(InitialIrp, IO_DISK_INCREMENT);
- ExFreePool(Srb);
+ /* Deallocate everything (internal) */
+ ExFreePool(Srb);
- if (Irp->PendingReturned)
+ if (Irp->MdlAddress != NULL)
{
- IoMarkIrpPending (Irp);
+ MmUnlockPages(Irp->MdlAddress);
+ IoFreeMdl(Irp->MdlAddress);
+ Irp->MdlAddress = NULL;
}
- return Irp->IoStatus.Status;
+
+ IoFreeIrp(Irp);
+ return STATUS_MORE_PROCESSING_REQUIRED;
}
-static NTSTATUS
-SpiScsiMiniport(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
+static BOOLEAN NTAPI
+ScsiPortIsr(IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext)
{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- PSRB_IO_CONTROL SrbIoControl;
- PIO_STACK_LOCATION IrpStack;
- PSCSI_REQUEST_BLOCK Srb;
- PSCSI_PORT_LUN_EXTENSION LunExtension;
-
- DPRINT("SpiScsiMiniport(DeviceObject %x, Irp %x)\n",
- DeviceObject, Irp);
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ BOOLEAN Result;
- DeviceExtension = DeviceObject->DeviceExtension;
- SrbIoControl = (PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer;
+ DPRINT("ScsiPortIsr() called!\n");
- IrpStack = IoGetCurrentIrpStackLocation(Irp);
- if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SRB_IO_CONTROL))
- {
- Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return STATUS_INVALID_PARAMETER;
- }
- if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SRB_IO_CONTROL) + SrbIoControl->Length)
+ DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
+
+ /* If interrupts are disabled - we don't expect any */
+ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS)
+ return FALSE;
+
+ /* Call miniport's HwInterrupt routine */
+ Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
+
+ /* If flag of notification is set - queue a DPC */
+ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
{
- Irp->IoStatus.Information = sizeof(SRB_IO_CONTROL) + SrbIoControl->Length;
- Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return STATUS_BUFFER_TOO_SMALL;
+ IoRequestDpc(DeviceExtension->DeviceObject,
+ DeviceExtension->CurrentIrp,
+ DeviceExtension);
}
- if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
- {
- Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return STATUS_NO_SUCH_DEVICE;
- }
-
- Srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
- if (Srb == NULL)
- {
- Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
- Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
- Srb->OriginalRequest = Irp;
- Srb->Function = SRB_FUNCTION_IO_CONTROL;
- Srb->DataBuffer = (PVOID)SrbIoControl;
- Srb->DataTransferLength = sizeof(SRB_IO_CONTROL) + SrbIoControl->Length;
-
- /* We using the first extension from the list. The miniport driver is responsible to find the correct device. */
- LunExtension = CONTAINING_RECORD(DeviceExtension->LunExtensionListHead.Flink,
- SCSI_PORT_LUN_EXTENSION,
- List);
- Srb->PathId = LunExtension->PathId;
- Srb->TargetId = LunExtension->TargetId;
- Srb->Lun = LunExtension->Lun;
-
- IrpStack = IoGetNextIrpStackLocation(Irp);
-
- IrpStack->MajorFunction = IRP_MJ_SCSI;
- IrpStack->Parameters.Scsi.Srb = Srb;
-
- IoSetCompletionRoutine(Irp,
- SpiCompletion,
- Srb,
- TRUE,
- TRUE,
- TRUE);
-
- return IoCallDriver(DeviceObject, Irp);
+
+ return TRUE;
}
-static VOID
-SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- PSCSI_REQUEST_BLOCK Srb)
+BOOLEAN
+NTAPI
+SpiSaveInterruptData(IN PVOID Context)
{
- ULONG index;
+ PSCSI_PORT_SAVE_INTERRUPT InterruptContext = Context;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ PSCSI_REQUEST_BLOCK Srb;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo, NextSrbInfo;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ BOOLEAN IsTimed;
+
+ /* Get pointer to the device extension */
+ DeviceExtension = InterruptContext->DeviceExtension;
+
+ /* If we don't have anything pending - return */
+ if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED))
+ return FALSE;
+
+ /* Actually save the interrupt data */
+ *InterruptContext->InterruptData = DeviceExtension->InterruptData;
+
+ /* Clear the data stored in the device extension */
+ DeviceExtension->InterruptData.Flags &=
+ (SCSI_PORT_RESET | SCSI_PORT_RESET_REQUEST | SCSI_PORT_DISABLE_INTERRUPTS);
+ DeviceExtension->InterruptData.CompletedAbort = NULL;
+ DeviceExtension->InterruptData.ReadyLun = NULL;
+ DeviceExtension->InterruptData.CompletedRequests = NULL;
+
+ /* Loop through the list of completed requests */
+ SrbInfo = InterruptContext->InterruptData->CompletedRequests;
+
+ while (SrbInfo)
+ {
+ /* Make sure we have SRV */
+ ASSERT(SrbInfo->Srb);
- DPRINT("SpiAllocateSrbExtension\n");
+ /* Get SRB and LunExtension */
+ Srb = SrbInfo->Srb;
- DPRINT("DeviceExtension->VirtualAddress %x, DeviceExtension->SrbExtensionSize %x\n",
- DeviceExtension->VirtualAddress, DeviceExtension->SrbExtensionSize);
+ LunExtension = SpiGetLunExtension(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
- Srb->SrbExtension = NULL;
- if (DeviceExtension->VirtualAddress != NULL &&
- DeviceExtension->SrbExtensionSize > 0)
- {
- index = RtlFindClearBitsAndSet(&DeviceExtension->SrbExtensionAllocMap, 1, 0);
- if (index != 0xffffffff)
+ /* We have to check special cases if request is unsuccessfull*/
+ if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
{
- DeviceExtension->CurrentSrbExtensions++;
- Srb->SrbExtension = (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + index * DeviceExtension->SrbExtensionSize);
- }
- }
- DPRINT("%x\n", Srb->SrbExtension);
-}
+ /* Check if we need request sense by a few conditions */
+ if (Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength &&
+ Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
+ !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
+ {
+ if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
+ {
+ /* It means: we tried to send REQUEST SENSE, but failed */
-static VOID
-SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- PSCSI_REQUEST_BLOCK Srb)
-{
- ULONG index;
+ Srb->ScsiStatus = 0;
+ Srb->SrbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
+ }
+ else
+ {
+ /* Set the corresponding flag, so that REQUEST SENSE
+ will be sent */
+ LunExtension->Flags |= LUNEX_NEED_REQUEST_SENSE;
+ }
- if (DeviceExtension->VirtualAddress != NULL &&
- DeviceExtension->SrbExtensionSize > 0 &&
- Srb->SrbExtension != NULL)
- {
- index = ((ULONG_PTR)Srb->SrbExtension - (ULONG_PTR)DeviceExtension->VirtualAddress) / DeviceExtension->SrbExtensionSize;
- RtlClearBits(&DeviceExtension->SrbExtensionAllocMap, index, 1);
- DeviceExtension->CurrentSrbExtensions--;
- }
- Srb->SrbExtension = NULL;
-}
+ }
+ /* Check for a full queue */
+ if (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL)
+ {
+ /* TODO: Implement when it's encountered */
+ ASSERT(FALSE);
+ }
+ }
-static BOOLEAN STDCALL
-ScsiPortStartPacket(IN OUT PVOID Context)
-{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- PSCSI_REQUEST_BLOCK Srb;
- PIRP Irp;
- PIO_STACK_LOCATION IrpStack;
+ /* Let's decide if we need to watch timeout or not */
+ if (Srb->QueueTag == SP_UNTAGGED)
+ {
+ IsTimed = TRUE;
+ }
+ else
+ {
+ if (LunExtension->SrbInfo.Requests.Flink == &SrbInfo->Requests)
+ IsTimed = TRUE;
+ else
+ IsTimed = FALSE;
+
+ /* Remove it from the queue */
+ RemoveEntryList(&SrbInfo->Requests);
+ }
+
+ if (IsTimed)
+ {
+ /* We have to maintain timeout counter */
+ if (IsListEmpty(&LunExtension->SrbInfo.Requests))
+ {
+ LunExtension->RequestTimeout = -1;
+ }
+ else
+ {
+ NextSrbInfo = CONTAINING_RECORD(LunExtension->SrbInfo.Requests.Flink,
+ SCSI_REQUEST_BLOCK_INFO,
+ Requests);
- DPRINT("ScsiPortStartPacket(Context %x) called\n", Context);
+ Srb = NextSrbInfo->Srb;
- Srb = (PSCSI_REQUEST_BLOCK)Context;
- Irp = (PIRP)Srb->OriginalRequest;
- IrpStack = IoGetCurrentIrpStackLocation(Irp);
- DeviceExtension = IrpStack->DeviceObject->DeviceExtension;
+ /* Update timeout counter */
+ LunExtension->RequestTimeout = Srb->TimeOutValue;
+ }
+ }
- return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
- Srb));
-}
+ SrbInfo = SrbInfo->CompletedRequests;
+ }
+ return TRUE;
+}
-static PSCSI_PORT_LUN_EXTENSION
-SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- IN UCHAR PathId,
- IN UCHAR TargetId,
- IN UCHAR Lun)
+VOID
+NTAPI
+SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_PORT_LUN_EXTENSION LunExtension)
{
- PSCSI_PORT_LUN_EXTENSION LunExtension;
- ULONG LunExtensionSize;
+ PIO_STACK_LOCATION IrpStack;
+ PIRP NextIrp;
+ PKDEVICE_QUEUE_ENTRY Entry;
+ PSCSI_REQUEST_BLOCK Srb;
- DPRINT("SpiAllocateLunExtension (%p %u %u %u)\n",
- DeviceExtension, PathId, TargetId, Lun);
- LunExtensionSize =
- sizeof(SCSI_PORT_LUN_EXTENSION) + DeviceExtension->LunExtensionSize;
- DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
-
- LunExtension = ExAllocatePool(NonPagedPool,
- LunExtensionSize);
- if (LunExtension == NULL)
+ /* If LUN is not active or queue is more than maximum allowed */
+ if (LunExtension->QueueCount >= LunExtension->MaxQueueCount ||
+ !(LunExtension->Flags & SCSI_PORT_LU_ACTIVE))
{
- return NULL;
+ /* Release the spinlock and exit */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ return;
}
- RtlZeroMemory(LunExtension,
- LunExtensionSize);
+ /* Check if we can get a next request */
+ if (LunExtension->Flags &
+ (LUNEX_NEED_REQUEST_SENSE | LUNEX_BUSY |
+ LUNEX_FULL_QUEUE | LUNEX_FROZEN_QUEUE | LUNEX_REQUEST_PENDING))
+ {
+ /* Pending requests can only be started if the queue is empty */
+ if (IsListEmpty(&LunExtension->SrbInfo.Requests) &&
+ !(LunExtension->Flags &
+ (LUNEX_BUSY | LUNEX_FROZEN_QUEUE | LUNEX_FULL_QUEUE | LUNEX_NEED_REQUEST_SENSE)))
+ {
+ /* Make sure we have SRB */
+ ASSERT(LunExtension->SrbInfo.Srb == NULL);
- InsertTailList(&DeviceExtension->LunExtensionListHead,
- &LunExtension->List);
+ /* Clear active and pending flags */
+ LunExtension->Flags &= ~(LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE);
- LunExtension->PathId = PathId;
- LunExtension->TargetId = TargetId;
- LunExtension->Lun = Lun;
+ /* Get next Irp, and clear pending requests list */
+ NextIrp = LunExtension->PendingRequest;
+ LunExtension->PendingRequest = NULL;
- LunExtension->PendingIrpCount = 0;
- LunExtension->ActiveIrpCount = 0;
+ /* Set attempt counter to zero */
+ LunExtension->AttemptCount = 0;
- LunExtension->NextIrp = NULL;
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
- return LunExtension;
-}
+ /* Start the next pending request */
+ IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
+ return;
+ }
+ else
+ {
+ /* Release the spinlock, without clearing any flags and exit */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
-static VOID
-SpiRemoveLunExtension (IN PSCSI_PORT_LUN_EXTENSION LunExtension)
-{
- DPRINT("SpiRemoveLunExtension(%p) called\n",
- LunExtension);
+ return;
+ }
+ }
- if (LunExtension == NULL)
- return;
+ /* Reset active flag */
+ LunExtension->Flags &= ~SCSI_PORT_LU_ACTIVE;
- RemoveEntryList (&LunExtension->List);
+ /* Set attempt counter to zero */
+ LunExtension->AttemptCount = 0;
+ /* Remove packet from the device queue */
+ Entry = KeRemoveByKeyDeviceQueue(&LunExtension->DeviceQueue, LunExtension->SortKey);
+
+ if (Entry != NULL)
+ {
+ /* Get pointer to the next irp */
+ NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
- /* Release LUN extersion data */
+ /* Get point to the SRB */
+ IrpStack = IoGetCurrentIrpStackLocation(NextIrp);
+ Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
+ /* Set new key*/
+ LunExtension->SortKey = Srb->QueueSortKey;
+ LunExtension->SortKey++;
- ExFreePool (LunExtension);
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
- return;
+ /* Start the next pending request */
+ IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
+ }
+ else
+ {
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
}
-static PSCSI_PORT_LUN_EXTENSION
-SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- IN UCHAR PathId,
- IN UCHAR TargetId,
- IN UCHAR Lun)
+
+// ScsiPortDpcForIsr
+// DESCRIPTION:
+//
+// RUN LEVEL:
+//
+// ARGUMENTS:
+// IN PKDPC Dpc
+// IN PDEVICE_OBJECT DpcDeviceObject
+// IN PIRP DpcIrp
+// IN PVOID DpcContext
+//
+static VOID NTAPI
+ScsiPortDpcForIsr(IN PKDPC Dpc,
+ IN PDEVICE_OBJECT DpcDeviceObject,
+ IN PIRP DpcIrp,
+ IN PVOID DpcContext)
{
- PSCSI_PORT_LUN_EXTENSION LunExtension;
- PLIST_ENTRY Entry;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DpcDeviceObject->DeviceExtension;
+ SCSI_PORT_INTERRUPT_DATA InterruptData;
+ SCSI_PORT_SAVE_INTERRUPT Context;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ BOOLEAN NeedToStartIo;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo;
- DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
- DeviceExtension, PathId, TargetId, Lun);
+ DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
+ Dpc, DpcDeviceObject, DpcIrp, DpcContext);
- if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
- return NULL;
+ /* We need to acquire spinlock */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
- Entry = DeviceExtension->LunExtensionListHead.Flink;
- while (Entry != &DeviceExtension->LunExtensionListHead)
+ RtlZeroMemory(&InterruptData, sizeof(SCSI_PORT_INTERRUPT_DATA));
+
+TryAgain:
+
+ /* Interrupt structure must be snapshotted, and only then analyzed */
+ Context.InterruptData = &InterruptData;
+ Context.DeviceExtension = DeviceExtension;
+
+ if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
+ SpiSaveInterruptData,
+ &Context))
{
- LunExtension = CONTAINING_RECORD(Entry,
- SCSI_PORT_LUN_EXTENSION,
- List);
- if (LunExtension->PathId == PathId &&
- LunExtension->TargetId == TargetId &&
- LunExtension->Lun == Lun)
- {
- return LunExtension;
- }
+ /* Nothing - just return (don't forget to release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ DPRINT("ScsiPortDpcForIsr() done\n");
+ return;
+ }
- Entry = Entry->Flink;
+ /* If flush of adapters is needed - do it */
+ if (InterruptData.Flags & SCSI_PORT_FLUSH_ADAPTERS)
+ {
+ /* TODO: Implement */
+ ASSERT(FALSE);
}
- return NULL;
-}
+ /* Check for IoMapTransfer */
+ if (InterruptData.Flags & SCSI_PORT_MAP_TRANSFER)
+ {
+ /* TODO: Implement */
+ ASSERT(FALSE);
+ }
+ /* Check if timer is needed */
+ if (InterruptData.Flags & SCIS_PORT_TIMER_NEEDED)
+ {
+ /* TODO: Implement */
+ ASSERT(FALSE);
+ }
-static NTSTATUS
-SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
- IN OUT PSCSI_REQUEST_BLOCK Srb,
- IN OUT PIO_STATUS_BLOCK IoStatusBlock,
- IN OUT PKEVENT Event)
-{
- PIO_STACK_LOCATION IrpStack;
- PIRP Irp;
- NTSTATUS Status;
+ /* If it's ready for the next request */
+ if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
+ {
+ /* Check for a duplicate request (NextRequest+NextLuRequest) */
+ if ((DeviceExtension->Flags &
+ (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED)) ==
+ (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED))
+ {
+ /* Clear busy flag set by ScsiPortStartPacket() */
+ DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
- DPRINT ("SpiSendInquiry() called\n");
+ if (!(InterruptData.Flags & SCSI_PORT_RESET))
+ {
+ /* Ready for next, and no reset is happening */
+ DeviceExtension->TimerCount = -1;
+ }
+ }
+ else
+ {
+ /* Not busy, but not ready for the next request */
+ DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
+ InterruptData.Flags &= ~SCSI_PORT_NEXT_REQUEST_READY;
+ }
+ }
+ /* Any resets? */
+ if (InterruptData.Flags & SCSI_PORT_RESET_REPORTED)
+ {
+ /* Hold for a bit */
+ DeviceExtension->TimerCount = 4;
+ }
- KeInitializeEvent (Event,
- NotificationEvent,
- FALSE);
+ /* Any ready LUN? */
+ if (InterruptData.ReadyLun != NULL)
+ {
- Irp = IoBuildDeviceIoControlRequest (IOCTL_SCSI_EXECUTE_OUT,
- DeviceObject,
- NULL,
- 0,
- Srb->DataBuffer,
- Srb->DataTransferLength,
- TRUE,
- Event,
- IoStatusBlock);
- if (Irp == NULL)
+ /* Process all LUNs from the list*/
+ while (TRUE)
+ {
+ /* Remove it from the list first (as processed) */
+ LunExtension = InterruptData.ReadyLun;
+ InterruptData.ReadyLun = LunExtension->ReadyLun;
+ LunExtension->ReadyLun = NULL;
+
+ /* Get next request for this LUN */
+ SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
+
+ /* Still ready requests exist?
+ If yes - get spinlock, if no - stop here */
+ if (InterruptData.ReadyLun != NULL)
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+ else
+ break;
+ }
+ }
+ else
{
- DPRINT("IoBuildDeviceIoControlRequest() failed\n");
- return STATUS_INSUFFICIENT_RESOURCES;
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
}
- /* Attach Srb to the Irp */
- IrpStack = IoGetNextIrpStackLocation (Irp);
- IrpStack->Parameters.Scsi.Srb = Srb;
- Srb->OriginalRequest = Irp;
+ /* If we ready for next packet, start it */
+ if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
+ IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
- /* Call the driver */
- Status = IoCallDriver (DeviceObject,
- Irp);
+ NeedToStartIo = FALSE;
- return Status;
-}
+ /* Loop the completed request list */
+ while (InterruptData.CompletedRequests)
+ {
+ /* Remove the request */
+ SrbInfo = InterruptData.CompletedRequests;
+ InterruptData.CompletedRequests = SrbInfo->CompletedRequests;
+ SrbInfo->CompletedRequests = NULL;
+
+ /* Process it */
+ SpiProcessCompletedRequest(DeviceExtension,
+ SrbInfo,
+ &NeedToStartIo);
+ }
-static VOID
-SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
-{
- PSCSI_REQUEST_BLOCK Srb;
- PCDB Cdb;
- ULONG Bus;
- ULONG Target;
- PSCSI_PORT_SCAN_ADAPTER ScanDataArray;
- PSCSI_PORT_SCAN_ADAPTER ScanData;
- ULONG i;
- ULONG MaxCount;
- ULONG WaitCount;
- ULONG ActiveCount;
- PVOID* EventArray;
- PKWAIT_BLOCK WaitBlockArray;
+ /* Loop abort request list */
+ while (InterruptData.CompletedAbort)
+ {
+ LunExtension = InterruptData.CompletedAbort;
- DPRINT ("SpiScanAdapter() called\n");
+ /* Remove the request */
+ InterruptData.CompletedAbort = LunExtension->CompletedAbortRequests;
- MaxCount = DeviceExtension->PortConfig->NumberOfBuses *
- DeviceExtension->PortConfig->MaximumNumberOfTargets;
+ /* Get spinlock since we're going to change flags */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
- ScanDataArray = ExAllocatePool(NonPagedPool, MaxCount * (sizeof(SCSI_PORT_SCAN_ADAPTER) + sizeof(PVOID) + sizeof(KWAIT_BLOCK)));
- if (ScanDataArray == NULL)
- {
- return;
+ /* TODO: Put SrbExtension to the list of free extensions */
+ ASSERT(FALSE);
}
- EventArray = (PVOID*)((PUCHAR)ScanDataArray + MaxCount * sizeof(SCSI_PORT_SCAN_ADAPTER));
- WaitBlockArray = (PKWAIT_BLOCK)((PUCHAR)EventArray + MaxCount * sizeof(PVOID));
- for (Bus = 0; Bus < DeviceExtension->PortConfig->NumberOfBuses; Bus++)
+ /* If we need - call StartIo routine */
+ if (NeedToStartIo)
{
- for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
- {
- ScanData = &ScanDataArray[Bus * DeviceExtension->PortConfig->MaximumNumberOfTargets + Target];
- ScanData->Bus = Bus;
- ScanData->Target = Target;
- ScanData->Lun = 0;
- ScanData->Active = FALSE;
- }
+ /* Make sure CurrentIrp is not null! */
+ ASSERT(DpcDeviceObject->CurrentIrp != NULL);
+ ScsiPortStartIo(DpcDeviceObject, DpcDeviceObject->CurrentIrp);
}
- do
+
+ /* Everything has been done, check */
+ if (InterruptData.Flags & SCSI_PORT_ENABLE_INT_REQUEST)
{
- ActiveCount = 0;
- WaitCount = 0;
- for (i = 0; i < MaxCount; i++)
- {
- ScanData = &ScanDataArray[i];
- Srb = &ScanData->Srb;
- if (ScanData->Active)
- {
- if (ScanData->Status == STATUS_PENDING &&
- 0 == KeReadStateEvent(&ScanData->Event))
- {
- ActiveCount++;
- continue;
- }
- else
- {
- ScanData->Status = ScanData->IoStatusBlock.Status;
- }
- ScanData->Active = FALSE;
- DPRINT ("Target %lu Lun %lu\n", ScanData->Target, ScanData->Lun);
- DPRINT ("Status %lx Srb.SrbStatus %x\n", ScanData->Status, Srb->SrbStatus);
- DPRINT ("DeviceTypeQualifier %x\n", ((PINQUIRYDATA)Srb->DataBuffer)->DeviceTypeQualifier);
-
- if (NT_SUCCESS(ScanData->Status) &&
- (Srb->SrbStatus == SRB_STATUS_SUCCESS ||
- (Srb->SrbStatus == SRB_STATUS_DATA_OVERRUN &&
- /*
- * FIXME:
- * The NT 4.0 driver from an inic950 based scsi controller
- * returns only 4 byte of inquiry data, but the device name
- * is visible on NT 4.0. We must implement an other way
- * to get the complete inquiry data.
- */
- Srb->DataTransferLength >= /*INQUIRYDATABUFFERSIZE*/4)) &&
- ((PINQUIRYDATA)Srb->DataBuffer)->DeviceTypeQualifier == 0)
- {
- /* Copy inquiry data */
- RtlCopyMemory (&ScanData->LunExtension->InquiryData,
- Srb->DataBuffer,
- min(sizeof(INQUIRYDATA), Srb->DataTransferLength));
- ScanData->Lun++;
- }
- else
- {
- SpiRemoveLunExtension (ScanData->LunExtension);
- ScanData->Lun = SCSI_MAXIMUM_LOGICAL_UNITS;
- }
- }
- if (ScanData->Lun >= SCSI_MAXIMUM_LOGICAL_UNITS)
- {
- continue;
- }
- RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
- Srb->SrbFlags = SRB_FLAGS_DATA_IN;
- Srb->DataBuffer = ScanData->DataBuffer;
- Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
- Srb->DataTransferLength = 255; //256;
- Srb->CdbLength = 6;
- Srb->Lun = ScanData->Lun;
- Srb->PathId = ScanData->Bus;
- Srb->TargetId = ScanData->Target;
- Srb->SrbStatus = SRB_STATUS_SUCCESS;
- Srb->TimeOutValue = 2;
- Cdb = (PCDB) &Srb->Cdb;
-
- Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
- Cdb->CDB6INQUIRY.AllocationLength = 255;
- Cdb->CDB6INQUIRY.LogicalUnitNumber = ScanData->Lun;
-
- RtlZeroMemory(Srb->DataBuffer, 256);
-
- ScanData->LunExtension = SpiAllocateLunExtension (DeviceExtension,
- ScanData->Bus,
- ScanData->Target,
- ScanData->Lun);
- if (ScanData->LunExtension == NULL)
- {
- DPRINT1("Failed to allocate the LUN extension!\n");
- ScanData->Lun = SCSI_MAXIMUM_LOGICAL_UNITS;
- continue;
- }
- ScanData->Status = SpiSendInquiry (DeviceExtension->DeviceObject,
- Srb,
- &ScanData->IoStatusBlock,
- &ScanData->Event);
- ScanData->Active = TRUE;
- ActiveCount++;
- if (ScanData->Status == STATUS_PENDING)
- {
- EventArray[WaitCount] = &ScanData->Event;
- WaitCount++;
- }
- }
- if (WaitCount > 0 && WaitCount == ActiveCount)
- {
- KeWaitForMultipleObjects(WaitCount,
- EventArray,
- WaitAny,
- Executive,
- KernelMode,
- FALSE,
- NULL,
- WaitBlockArray);
- }
- }
- while (ActiveCount > 0);
+ /* Synchronize using spinlock */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
- ExFreePool(ScanDataArray);
+ /* Request an interrupt */
+ DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension);
- DPRINT ("SpiScanAdapter() done\n");
-}
+ ASSERT(DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET);
+ /* Should interrupts be enabled again? */
+ if (DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET)
+ {
+ /* Clear this flag */
+ DeviceExtension->Flags &= ~SCSI_PORT_DISABLE_INT_REQUESET;
-static ULONG
-SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo)
-{
- PSCSI_PORT_LUN_EXTENSION LunExtension;
- PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
- ULONG Bus;
- ULONG Target;
- ULONG Lun;
- ULONG UnitCount;
+ /* Call a special routine to do this */
+ ASSERT(FALSE);
+#if 0
+ KeSynchronizeExecution(DeviceExtension->Interrupt,
+ SpiEnableInterrupts,
+ DeviceExtension);
+#endif
+ }
- DPRINT("SpiGetInquiryData() called\n");
+ /* If we need a notification again - loop */
+ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
+ goto TryAgain;
- /* Copy inquiry data to the port device extension */
- AdapterBusInfo->NumberOfBuses = DeviceExtension->PortConfig->NumberOfBuses;
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
- UnitInfo = (PSCSI_INQUIRY_DATA)
- ((PUCHAR)AdapterBusInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
- (sizeof(SCSI_BUS_DATA) * (AdapterBusInfo->NumberOfBuses - 1)));
+ DPRINT("ScsiPortDpcForIsr() done\n");
+}
- for (Bus = 0; Bus < AdapterBusInfo->NumberOfBuses; Bus++)
- {
- AdapterBusInfo->BusData[Bus].InitiatorBusId =
- DeviceExtension->PortConfig->InitiatorBusId[Bus];
- AdapterBusInfo->BusData[Bus].InquiryDataOffset =
- (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterBusInfo);
+BOOLEAN
+NTAPI
+SpiProcessTimeout(PVOID ServiceContext)
+{
+ PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+ ULONG Bus;
- PrevUnit = NULL;
- UnitCount = 0;
+ DPRINT("SpiProcessTimeout() entered\n");
- for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
- {
- for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
- {
- LunExtension = SpiGetLunExtension(DeviceExtension,
- Bus,
- Target,
- Lun);
- if (LunExtension != NULL)
- {
- DPRINT("(Bus %lu Target %lu Lun %lu)\n",
- Bus, Target, Lun);
- RtlZeroMemory(UnitInfo, sizeof(*UnitInfo));
- UnitInfo->PathId = Bus;
- UnitInfo->TargetId = Target;
- UnitInfo->Lun = Lun;
- UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
- RtlCopyMemory (&UnitInfo->InquiryData,
- &LunExtension->InquiryData,
- INQUIRYDATABUFFERSIZE);
- if (PrevUnit != NULL)
- {
- PrevUnit->NextInquiryDataOffset =
- (ULONG)((ULONG_PTR)UnitInfo-(ULONG_PTR)AdapterBusInfo);
- }
- PrevUnit = UnitInfo;
- UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
- UnitCount++;
- }
- }
- }
- DPRINT("UnitCount: %lu\n", UnitCount);
- AdapterBusInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
- if (UnitCount == 0)
- {
- AdapterBusInfo->BusData[Bus].InquiryDataOffset = 0;
- }
- }
+ DeviceExtension->TimerCount = -1;
- DPRINT("Data size: %lu\n", (ULONG)UnitInfo - (ULONG)AdapterBusInfo);
+ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
+ {
+ DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET;
- return (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterBusInfo);
-}
+ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST)
+ {
+ DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET_REQUEST;
+ ScsiPortStartPacket(ServiceContext);
+ }
+ return FALSE;
+ }
+ else
+ {
+ DPRINT("Resetting the bus\n");
-static BOOLEAN STDCALL
-ScsiPortIsr(IN PKINTERRUPT Interrupt,
- IN PVOID ServiceContext)
-{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
+ {
+ DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus);
- DPRINT("ScsiPortIsr() called!\n");
+ /* Reset flags and set reset timeout to 4 seconds */
+ DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
+ DeviceExtension->TimerCount = 4;
+ }
- DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
+ /* If miniport requested - request a dpc for it */
+ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
+ IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
+ }
- return DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
+ return TRUE;
}
-// ScsiPortDpc
-// DESCRIPTION:
-//
-// RUN LEVEL:
-//
-// ARGUMENTS:
-// IN PKDPC Dpc
-// IN PDEVICE_OBJECT DpcDeviceObject
-// IN PIRP DpcIrp
-// IN PVOID DpcContext
-//
-static VOID STDCALL
-ScsiPortDpc(IN PKDPC Dpc,
- IN PDEVICE_OBJECT DpcDeviceObject,
- IN PIRP DpcIrp,
- IN PVOID DpcContext)
+BOOLEAN
+NTAPI
+SpiResetBus(PVOID ServiceContext)
{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- DPRINT("ScsiPortDpc(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
- Dpc, DpcDeviceObject, DpcIrp, DpcContext);
+ /* Perform the bus reset */
+ DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension;
+ DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension,
+ ResetParams->PathId);
- DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
+ /* Set flags and start the timer */
+ DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
+ DeviceExtension->TimerCount = 4;
- SpiProcessRequests(DeviceExtension, NULL);
+ /* If miniport requested - give him a DPC */
+ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
+ IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
- DPRINT("ScsiPortDpc() done\n");
+ return TRUE;
}
-
// ScsiPortIoTimer
// DESCRIPTION:
// This function handles timeouts and other time delayed processing
// IN PVOID Context the Controller extension for the
// controller the device is on
//
-static VOID STDCALL
+static VOID NTAPI
ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
- PVOID Context)
+ PVOID Context)
{
- DPRINT1("ScsiPortIoTimer()\n");
-}
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ ULONG Lun;
+ PIRP Irp;
+ DPRINT("ScsiPortIoTimer()\n");
-static PSCSI_REQUEST_BLOCK
-ScsiPortInitSenseRequestSrb(PSCSI_REQUEST_BLOCK OriginalSrb)
-{
- PSCSI_REQUEST_BLOCK Srb;
- ULONG Length;
- PCDB Cdb;
+ DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
- Length = sizeof(SCSI_REQUEST_BLOCK) + sizeof(SENSE_DATA) + 32;
- Srb = ExAllocatePoolWithTag(NonPagedPool,
- Length,
- TAG('S', 'S', 'r', 'b'));
- if (Srb == NULL)
+ /* Protect with the spinlock */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+ /* Check timeouts */
+ if (DeviceExtension->TimerCount > 0)
{
- return NULL;
+ /* Decrease the timeout counter */
+ DeviceExtension->TimerCount--;
+
+ if (DeviceExtension->TimerCount == 0)
+ {
+ /* Timeout, process it */
+ if (KeSynchronizeExecution(DeviceExtension->Interrupt,
+ SpiProcessTimeout,
+ DeviceExtension->DeviceObject))
+ {
+ DPRINT("Error happened during processing timeout, but nothing critical\n");
+ }
+ }
+
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ /* We should exit now, since timeout is processed */
+ return;
}
- RtlZeroMemory(Srb, Length);
+ /* Per-Lun scanning of timeouts is needed... */
+ for (Lun = 0; Lun < LUS_NUMBER; Lun++)
+ {
+ LunExtension = DeviceExtension->LunExtensionList[Lun];
+
+ while (LunExtension)
+ {
+ if (LunExtension->Flags & LUNEX_BUSY)
+ {
+ if (!(LunExtension->Flags &
+ (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE)))
+ {
+ DPRINT("Retrying busy request\n");
- Srb->PathId = OriginalSrb->PathId;
- Srb->TargetId = OriginalSrb->TargetId;
- Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
- Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
- Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
- Srb->OriginalRequest = OriginalSrb->OriginalRequest;
+ /* Clear flags, and retry busy request */
+ LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE);
+ Irp = LunExtension->BusyRequest;
- Srb->TimeOutValue = 4;
+ /* Clearing busy request */
+ LunExtension->BusyRequest = NULL;
- Srb->CdbLength = 6;
- /* The DataBuffer must be located in contiguous physical memory if
- * the miniport driver uses dma for the sense info. The size of
- * the sense data is 18 byte. If the buffer starts at a 32 byte
- * boundary than is the buffer always in one memory page.
- */
- Srb->DataBuffer = (PVOID)ROUND_UP((ULONG_PTR)(Srb + 1), 32);
- Srb->DataTransferLength = sizeof(SENSE_DATA);
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
+
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+ }
+ }
+ else if (LunExtension->RequestTimeout == 0)
+ {
+ RESETBUS_PARAMS ResetParams;
- Cdb = (PCDB)Srb->Cdb;
- Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
- Cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
+ LunExtension->RequestTimeout = -1;
- return(Srb);
+ DPRINT("Request timed out, resetting bus\n");
+
+ /* Pass params to the bus reset routine */
+ ResetParams.PathId = LunExtension->PathId;
+ ResetParams.DeviceExtension = DeviceExtension;
+
+ if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
+ SpiResetBus,
+ &ResetParams))
+ {
+ DPRINT1("Reset failed\n");
+ }
+ }
+ else if (LunExtension->RequestTimeout > 0)
+ {
+ /* Decrement the timeout counter */
+ LunExtension->RequestTimeout--;
+ }
+
+ LunExtension = LunExtension->Next;
+ }
+ }
+
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
}
/**********************************************************************
{
PSCSI_PORT_LUN_EXTENSION LunExtension;
OBJECT_ATTRIBUTES ObjectAttributes;
- UNICODE_STRING KeyName =
- RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
+ UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
WCHAR NameBuffer[64];
ULONG Disposition;
}
/* Open or create the 'Scsi' subkey */
+ RtlInitUnicodeString(&KeyName,
+ L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
*/
/* Set 'DMA Enabled' (REG_DWORD) value */
- UlongData = (ULONG)!DeviceExtension->PortCapabilities->AdapterUsesPio;
+ UlongData = (ULONG)!DeviceExtension->PortCapabilities.AdapterUsesPio;
DPRINT(" DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE");
RtlInitUnicodeString(&ValueName,
L"DMA Enabled");
for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
{
LunExtension = SpiGetLunExtension(DeviceExtension,
- BusNumber,
- Target,
- Lun);
+ (UCHAR)BusNumber,
+ (UCHAR)Target,
+ (UCHAR)Lun);
if (LunExtension != NULL)
{
if (Target != CurrentTarget)
return Status;
}
-static VOID
-SpiRemoveActiveIrp(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- PIRP Irp,
- PIRP PrevIrp)
+VOID
+NTAPI
+SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
+ IN PVOID DeviceObject,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2)
{
- PSCSI_PORT_LUN_EXTENSION LunExtension;
- PIRP CurrentIrp;
- LunExtension = Irp->Tail.Overlay.DriverContext[2];
- InterlockedDecrement((PLONG)&LunExtension->ActiveIrpCount);
- InterlockedDecrement((PLONG)&DeviceExtension->ActiveIrpCount);
- if (PrevIrp)
+ DPRINT1("Miniport timer DPC\n");
+ ASSERT(FALSE);
+}
+
+static NTSTATUS
+SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ PHW_INITIALIZATION_DATA HwInitData,
+ PCONFIGURATION_INFO InternalConfigInfo,
+ PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ BOOLEAN ZeroStruct)
+{
+ UNICODE_STRING UnicodeString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PCONFIGURATION_INFORMATION DdkConfigInformation;
+ HANDLE RootKey, Key;
+ BOOLEAN Found;
+ WCHAR DeviceBuffer[16];
+ WCHAR StrBuffer[512];
+ ULONG Bus;
+ NTSTATUS Status;
+
+ /* Zero out the struct if told so */
+ if (ZeroStruct)
+ {
+ /* First zero the portconfig */
+ RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
+
+ /* Then access ranges */
+ RtlZeroMemory(InternalConfigInfo->AccessRanges,
+ HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
+
+ /* Initialize the struct */
+ ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
+ ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
+ ConfigInfo->InterruptMode = Latched;
+ ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
+ ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
+ ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
+ ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
+ ConfigInfo->MaximumNumberOfTargets = 8;
+
+ /* Store parameters */
+ ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
+ ConfigInfo->MapBuffers = HwInitData->MapBuffers;
+ ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense;
+ ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent;
+ ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing;
+ ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
+
+ /* Get the disk usage */
+ DdkConfigInformation = IoGetConfigurationInformation();
+ ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed;
+ ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed;
+
+ /* Initiator bus id is not set */
+ for (Bus = 0; Bus < 8; Bus++)
+ ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE;
+ }
+
+ ConfigInfo->NumberOfPhysicalBreaks = 17;
+
+ /* Clear this information */
+ InternalConfigInfo->DisableTaggedQueueing = FALSE;
+ InternalConfigInfo->DisableMultipleLun = FALSE;
+
+ /* Store Bus Number */
+ ConfigInfo->SystemIoBusNumber = InternalConfigInfo->BusNumber;
+
+TryNextAd:
+
+ if (ConfigInfo->AdapterInterfaceType == Internal)
+ {
+ /* Open registry key for HW database */
+ InitializeObjectAttributes(&ObjectAttributes,
+ DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = ZwOpenKey(&RootKey,
+ KEY_READ,
+ &ObjectAttributes);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* Create name for it */
+ swprintf(StrBuffer, L"ScsiAdapter\\%lu",
+ InternalConfigInfo->AdapterNumber);
+
+ RtlInitUnicodeString(&UnicodeString, StrBuffer);
+
+ /* Open device key */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &UnicodeString,
+ OBJ_CASE_INSENSITIVE,
+ RootKey,
+ NULL);
+
+ Status = ZwOpenKey(&Key,
+ KEY_READ,
+ &ObjectAttributes);
+
+ ZwClose(RootKey);
+
+ if (NT_SUCCESS(Status))
+ {
+ if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
+ {
+ DPRINT("Hardware info found at %S\n", StrBuffer);
+
+ /* Parse it */
+ SpiParseDeviceInfo(DeviceExtension,
+ Key,
+ ConfigInfo,
+ InternalConfigInfo,
+ (PUCHAR)StrBuffer);
+
+ InternalConfigInfo->BusNumber = 0;
+ }
+ else
+ {
+ /* Try the next adapter */
+ InternalConfigInfo->AdapterNumber++;
+ goto TryNextAd;
+ }
+ }
+ else
+ {
+ /* Info was not found, exit */
+ DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+ }
+ else
+ {
+ DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
+ }
+ }
+
+ /* Look at device params */
+ Key = NULL;
+ if (InternalConfigInfo->Parameter)
{
- InterlockedExchangePointer(&PrevIrp->Tail.Overlay.DriverContext[0],
- Irp->Tail.Overlay.DriverContext[0]);
+ ExFreePool(InternalConfigInfo->Parameter);
+ InternalConfigInfo->Parameter = NULL;
}
- else
+
+ if (InternalConfigInfo->ServiceKey != NULL)
{
- InterlockedExchangePointer(&DeviceExtension->NextIrp,
- Irp->Tail.Overlay.DriverContext[0]);
+ swprintf(DeviceBuffer, L"Device%lu", InternalConfigInfo->AdapterNumber);
+ RtlInitUnicodeString(&UnicodeString, DeviceBuffer);
+
+ /* Open the service key */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &UnicodeString,
+ OBJ_CASE_INSENSITIVE,
+ InternalConfigInfo->ServiceKey,
+ NULL);
+
+ Status = ZwOpenKey(&Key,
+ KEY_READ,
+ &ObjectAttributes);
}
- if (LunExtension->NextIrp == Irp)
+
+ /* Parse device key */
+ if (InternalConfigInfo->DeviceKey != NULL)
{
- InterlockedExchangePointer(&LunExtension->NextIrp,
- Irp->Tail.Overlay.DriverContext[1]);
- return;
+ SpiParseDeviceInfo(DeviceExtension,
+ InternalConfigInfo->DeviceKey,
+ ConfigInfo,
+ InternalConfigInfo,
+ (PUCHAR)StrBuffer);
}
- else
+
+ /* Then parse hw info */
+ if (Key != NULL)
{
- CurrentIrp = LunExtension->NextIrp;
- while (CurrentIrp)
+ if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
{
- if (CurrentIrp->Tail.Overlay.DriverContext[1] == Irp)
- {
- InterlockedExchangePointer(&CurrentIrp->Tail.Overlay.DriverContext[1],
- Irp->Tail.Overlay.DriverContext[1]);
- return;
- }
- CurrentIrp = CurrentIrp->Tail.Overlay.DriverContext[1];
- }
- KEBUGCHECK(0);
+ SpiParseDeviceInfo(DeviceExtension,
+ Key,
+ ConfigInfo,
+ InternalConfigInfo,
+ (PUCHAR)StrBuffer);
+
+ /* Close the key */
+ ZwClose(Key);
+ }
+ else
+ {
+ /* Adapter not found, go try the next one */
+ InternalConfigInfo->AdapterNumber++;
+
+ /* Close the key */
+ ZwClose(Key);
+
+ goto TryNextAd;
+ }
}
-}
-static VOID
-SpiAddActiveIrp(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- PIRP Irp)
-{
- PSCSI_PORT_LUN_EXTENSION LunExtension;
- PSCSI_REQUEST_BLOCK Srb;
- LunExtension = Irp->Tail.Overlay.DriverContext[2];
- Srb = Irp->Tail.Overlay.DriverContext[3];
- Irp->Tail.Overlay.DriverContext[0] = (PVOID)DeviceExtension->NextIrp;
- InterlockedExchangePointer(&DeviceExtension->NextIrp, Irp);
- Irp->Tail.Overlay.DriverContext[1] = (PVOID)LunExtension->NextIrp;
- InterlockedExchangePointer(&LunExtension->NextIrp, Irp);
+ /* Update the last adapter number */
+ InternalConfigInfo->LastAdapterNumber = InternalConfigInfo->AdapterNumber;
+
+ /* Do we have this kind of bus at all? */
+ Found = FALSE;
+ Status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType,
+ &InternalConfigInfo->BusNumber,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ SpQueryDeviceCallout,
+ &Found);
+
+ /* This bus was not found */
+ if (!Found)
+ {
+ INTERFACE_TYPE InterfaceType = Eisa;
+
+ /* Check for EISA */
+ if (HwInitData->AdapterInterfaceType == Isa)
+ {
+ Status = IoQueryDeviceDescription(&InterfaceType,
+ &InternalConfigInfo->BusNumber,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ SpQueryDeviceCallout,
+ &Found);
+
+ /* Return respectively */
+ if (Found)
+ return STATUS_SUCCESS;
+ else
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+ else
+ {
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+ }
+ else
+ {
+ return STATUS_SUCCESS;
+ }
}
static VOID
-SpiProcessRequests(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- IN PIRP NextIrp)
+SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN HANDLE Key,
+ IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN PCONFIGURATION_INFO InternalConfigInfo,
+ IN PUCHAR Buffer)
{
- /*
- * Using of some fields from Srb and Irp while processing requests:
- *
- * NextIrp on entry:
- * Srb->OriginalRequest -> LunExtension
- * Irp->Tail.Overlay.DriverContext[3] -> original Srb
- * IoStack->Parameters.Scsi.Srb -> original Srb
- *
- * Irp is within the pending irp list:
- * Srb->OriginalRequest -> LunExtension
- * Irp->Tail.Overlay.DriverContext[0] and DriverContext[1] -> ListEntry for queue
- * Irp->Tail.Overlay.DriverContext[2] -> sort key (from Srb->QueueSortKey)
- * Irp->Tail.Overlay.DriverContext[3] -> current Srb (original or sense request)
- * IoStack->Parameters.Scsi.Srb -> original Srb
- *
- * Irp is within the active irp list or while other processing:
- * Srb->OriginalRequest -> Irp
- * Irp->Tail.Overlay.DriverContext[0] -> next irp, DeviceExtension->NextIrp is head.
- * Irp->Tail.Overlay.DriverContext[1] -> next irp, LunExtension->NextIrp is head.
- * Irp->Tail.Overlay.DriverContext[2] -> LunExtension
- * Irp->Tail.Overlay.DriverContext[3] -> current Srb (original or sense request)
- * IoStack->Parameters.Scsi.Srb -> original Srb
- */
- PIO_STACK_LOCATION IrpStack;
- PSCSI_PORT_LUN_EXTENSION LunExtension;
- PLIST_ENTRY ListEntry;
- KIRQL oldIrql;
- PIRP Irp;
- LIST_ENTRY NextIrpListHead;
- LIST_ENTRY CompleteIrpListHead;
- PSCSI_REQUEST_BLOCK Srb;
- PSCSI_REQUEST_BLOCK OriginalSrb;
- PIRP PrevIrp;
-
- DPRINT("SpiProcessRequests() called\n");
+ PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
+ PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
+ PCM_SCSI_DEVICE_DATA ScsiDeviceData;
+ ULONG Length, Count;
+ ULONG Index = 0, RangeCount = 0;
+ UNICODE_STRING UnicodeString;
+ ANSI_STRING AnsiString;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer;
+
+ /* Loop through all values in the device node */
+ while(TRUE)
+ {
+ Status = ZwEnumerateValueKey(Key,
+ Index,
+ KeyValueFullInformation,
+ Buffer,
+ 512,
+ &Length);
- InitializeListHead(&NextIrpListHead);
- InitializeListHead(&CompleteIrpListHead);
+ if (!NT_SUCCESS(Status))
+ return;
- KeAcquireSpinLock(&DeviceExtension->Lock, &oldIrql);
+ Index++;
- if (NextIrp)
- {
- Srb = NextIrp->Tail.Overlay.DriverContext[3];
- /*
- * FIXME:
- * Is this the right place to set this flag ?
- */
- NextIrp->Tail.Overlay.DriverContext[2] = (PVOID)Srb->QueueSortKey;
- LunExtension = Srb->OriginalRequest;
+ /* Length for DWORD is ok? */
+ if (KeyValueInformation->Type == REG_DWORD &&
+ KeyValueInformation->DataLength != sizeof(ULONG))
+ {
+ continue;
+ }
- ListEntry = DeviceExtension->PendingIrpListHead.Flink;
- while (ListEntry != &DeviceExtension->PendingIrpListHead)
+ /* Get MaximumLogicalUnit */
+ if (_wcsnicmp(KeyValueInformation->Name, L"MaximumLogicalUnit",
+ KeyValueInformation->NameLength/2) == 0)
{
- Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
- if ((ULONG)Irp->Tail.Overlay.DriverContext[2] > Srb->QueueSortKey)
+
+ if (KeyValueInformation->Type != REG_DWORD)
{
- break;
- }
- ListEntry = ListEntry->Flink;
- }
- InsertTailList(ListEntry, (PLIST_ENTRY)&NextIrp->Tail.Overlay.DriverContext[0]);
- DeviceExtension->PendingIrpCount++;
- LunExtension->PendingIrpCount++;
- }
+ DPRINT("Bad data type for MaximumLogicalUnit\n");
+ continue;
+ }
- while (DeviceExtension->Flags & IRP_FLAG_COMPLETE ||
- (((DeviceExtension->SrbExtensionSize == 0 || DeviceExtension->CurrentSrbExtensions < DeviceExtension->MaxSrbExtensions) &&
- DeviceExtension->PendingIrpCount > 0 &&
- (DeviceExtension->Flags & (IRP_FLAG_NEXT|IRP_FLAG_NEXT_LU) || DeviceExtension->NextIrp == NULL))))
- {
- DPRINT ("RequestComplete %d, NextRequest %d, NextLuRequest %d, PendingIrpCount %d, ActiveIrpCount %d\n",
- DeviceExtension->Flags & IRP_FLAG_COMPLETE ? 1 : 0,
- DeviceExtension->Flags & IRP_FLAG_NEXT ? 1 : 0,
- DeviceExtension->Flags & IRP_FLAG_NEXT_LU ? 1 : 0,
- DeviceExtension->PendingIrpCount,
- DeviceExtension->ActiveIrpCount);
+ DeviceExtension->MaxLunCount = *((PUCHAR)
+ (Buffer + KeyValueInformation->DataOffset));
+ /* Check / reset if needed */
+ if (DeviceExtension->MaxLunCount > SCSI_MAXIMUM_LOGICAL_UNITS)
+ DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
+
+ DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension->MaxLunCount);
+ }
- if (DeviceExtension->Flags & IRP_FLAG_COMPLETE)
+ /* Get InitiatorTargetId */
+ if (_wcsnicmp(KeyValueInformation->Name, L"InitiatorTargetId",
+ KeyValueInformation->NameLength / 2) == 0)
{
- DeviceExtension->Flags &= ~IRP_FLAG_COMPLETE;
- PrevIrp = NULL;
- Irp = DeviceExtension->NextIrp;
- while (Irp)
- {
- NextIrp = (PIRP)Irp->Tail.Overlay.DriverContext[0];
- Srb = Irp->Tail.Overlay.DriverContext[3];
- if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
- {
- BOOLEAN CompleteThisRequest;
- LunExtension = Irp->Tail.Overlay.DriverContext[2];
- IrpStack = IoGetCurrentIrpStackLocation(Irp);
- OriginalSrb = IrpStack->Parameters.Scsi.Srb;
-
- if (Srb->SrbStatus == SRB_STATUS_BUSY)
- {
- CompleteThisRequest = FALSE;
- Irp->Tail.Overlay.DriverContext[3] = Srb;
- SpiRemoveActiveIrp(DeviceExtension, Irp, PrevIrp);
- SpiFreeSrbExtension(DeviceExtension, OriginalSrb);
+ if (KeyValueInformation->Type != REG_DWORD)
+ {
+ DPRINT("Bad data type for InitiatorTargetId\n");
+ continue;
+ }
+
+ ConfigInfo->InitiatorBusId[0] = *((PUCHAR)
+ (Buffer + KeyValueInformation->DataOffset));
- Srb->OriginalRequest = LunExtension;
- Irp->Tail.Overlay.DriverContext[2] = 0;
+ /* Check / reset if needed */
+ if (ConfigInfo->InitiatorBusId[0] > ConfigInfo->MaximumNumberOfTargets - 1)
+ ConfigInfo->InitiatorBusId[0] = (CCHAR)-1;
- InsertHeadList(&DeviceExtension->PendingIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
- DeviceExtension->PendingIrpCount++;
- LunExtension->PendingIrpCount++;
- Irp = NextIrp;
- continue;
- }
+ DPRINT("InitiatorTargetId = %d\n", ConfigInfo->InitiatorBusId[0]);
+ }
+
+ /* Get ScsiDebug */
+ if (_wcsnicmp(KeyValueInformation->Name, L"ScsiDebug",
+ KeyValueInformation->NameLength/2) == 0)
+ {
+ DPRINT("ScsiDebug key not supported\n");
+ }
- if (OriginalSrb != Srb)
- {
- SENSE_DATA* SenseInfoBuffer;
+ /* Check for a breakpoint */
+ if (_wcsnicmp(KeyValueInformation->Name, L"BreakPointOnEntry",
+ KeyValueInformation->NameLength/2) == 0)
+ {
+ DPRINT1("Breakpoint on entry requested!\n");
+ DbgBreakPoint();
+ }
- SenseInfoBuffer = Srb->DataBuffer;
+ /* Get DisableSynchronousTransfers */
+ if (_wcsnicmp(KeyValueInformation->Name, L"DisableSynchronousTransfers",
+ KeyValueInformation->NameLength/2) == 0)
+ {
+ DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+ DPRINT("Synch transfers disabled\n");
+ }
- DPRINT("Got sense data!\n");
+ /* Get DisableDisconnects */
+ if (_wcsnicmp(KeyValueInformation->Name, L"DisableDisconnects",
+ KeyValueInformation->NameLength/2) == 0)
+ {
+ DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
+ DPRINT("Disconnects disabled\n");
+ }
- DPRINT("Valid: %x\n", SenseInfoBuffer->Valid);
- DPRINT("ErrorCode: %x\n", SenseInfoBuffer->ErrorCode);
- DPRINT("SenseKey: %x\n", SenseInfoBuffer->SenseKey);
- DPRINT("SenseCode: %x\n", SenseInfoBuffer->AdditionalSenseCode);
+ /* Get DisableTaggedQueuing */
+ if (_wcsnicmp(KeyValueInformation->Name, L"DisableTaggedQueuing",
+ KeyValueInformation->NameLength/2) == 0)
+ {
+ InternalConfigInfo->DisableTaggedQueueing = TRUE;
+ DPRINT("Tagged queueing disabled\n");
+ }
- /* Copy sense data */
- RtlCopyMemory(OriginalSrb->SenseInfoBuffer,
- SenseInfoBuffer,
- sizeof(SENSE_DATA));
- OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
- OriginalSrb->SrbExtension = Srb->SrbExtension;
- ExFreePool(Srb);
- CompleteThisRequest = TRUE;
- }
- else if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS &&
- Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
- Srb->SenseInfoBuffer != NULL &&
- Srb->SenseInfoBufferLength >= sizeof(SENSE_DATA) &&
- !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
- {
- DPRINT("SCSIOP_REQUEST_SENSE required!\n");
-
- Srb = ScsiPortInitSenseRequestSrb(OriginalSrb);
-
- if (Srb)
- {
- CompleteThisRequest = FALSE;
- Irp->Tail.Overlay.DriverContext[3] = Srb;
- SpiRemoveActiveIrp(DeviceExtension, Irp, PrevIrp);
- SpiFreeSrbExtension(DeviceExtension, OriginalSrb);
-
- Srb->OriginalRequest = LunExtension;
- Irp->Tail.Overlay.DriverContext[2] = 0;
-
- InsertHeadList(&DeviceExtension->PendingIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
- DeviceExtension->PendingIrpCount++;
- LunExtension->PendingIrpCount++;
- Irp = NextIrp;
- continue;
- }
- else
- {
- CompleteThisRequest = TRUE;
- }
- }
- else
- {
- DPRINT("Complete Request\n");
- CompleteThisRequest = TRUE;
- }
- if (CompleteThisRequest)
- {
- SpiRemoveActiveIrp(DeviceExtension, Irp, PrevIrp);
- InsertHeadList(&CompleteIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
- SpiFreeSrbExtension(DeviceExtension, OriginalSrb);
- }
- else
- {
- PrevIrp = Irp;
- }
- Irp = NextIrp;
- continue;
- }
- PrevIrp = Irp;
- Irp = NextIrp;
- }
- }
- if (!IsListEmpty(&CompleteIrpListHead))
+ /* Get DisableMultipleRequests */
+ if (_wcsnicmp(KeyValueInformation->Name, L"DisableMultipleRequests",
+ KeyValueInformation->NameLength/2) == 0)
{
- KeReleaseSpinLockFromDpcLevel(&DeviceExtension->Lock);
- while (!IsListEmpty(&CompleteIrpListHead))
- {
- ListEntry = RemoveTailList(&CompleteIrpListHead);
- Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- }
- KeAcquireSpinLockAtDpcLevel(&DeviceExtension->Lock);
+ InternalConfigInfo->DisableMultipleLun = TRUE;
+ DPRINT("Multiple requests disabled\n");
}
- if (DeviceExtension->Flags & (IRP_FLAG_NEXT|IRP_FLAG_NEXT_LU) &&
- (DeviceExtension->SrbExtensionSize == 0 || DeviceExtension->CurrentSrbExtensions < DeviceExtension->MaxSrbExtensions))
+
+ /* Get DriverParameters */
+ if (_wcsnicmp(KeyValueInformation->Name, L"DriverParameters",
+ KeyValueInformation->NameLength/2) == 0)
{
- BOOLEAN StartThisRequest;
- ListEntry = DeviceExtension->PendingIrpListHead.Flink;
- while (ListEntry != &DeviceExtension->PendingIrpListHead)
- {
- Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
- ListEntry = ListEntry->Flink;
- Srb = Irp->Tail.Overlay.DriverContext[3];
- LunExtension = Srb->OriginalRequest;
- if (DeviceExtension->SrbExtensionSize > 0 &&
- DeviceExtension->CurrentSrbExtensions >= DeviceExtension->MaxSrbExtensions)
- {
- break;
- }
- if (LunExtension->Flags & IRP_FLAG_NEXT_LU)
+ /* Skip if nothing */
+ if (KeyValueInformation->DataLength == 0)
+ continue;
+
+ /* If there was something previously allocated - free it */
+ if (InternalConfigInfo->Parameter != NULL)
+ ExFreePool(InternalConfigInfo->Parameter);
+
+ /* Allocate it */
+ InternalConfigInfo->Parameter = ExAllocatePoolWithTag(NonPagedPool,
+ KeyValueInformation->DataLength, TAG_SCSIPORT);
+
+ if (InternalConfigInfo->Parameter != NULL)
+ {
+ if (KeyValueInformation->Type != REG_SZ)
{
- StartThisRequest = TRUE;
- LunExtension->Flags &= ~IRP_FLAG_NEXT_LU;
- DeviceExtension->Flags &= ~IRP_FLAG_NEXT_LU;
- }
- else if (DeviceExtension->Flags & IRP_FLAG_NEXT &&
- LunExtension->ActiveIrpCount == 0)
- {
- StartThisRequest = TRUE;
- DeviceExtension->Flags &= ~IRP_FLAG_NEXT;
- }
- else
- {
- StartThisRequest = FALSE;
- }
- if (StartThisRequest)
- {
- LunExtension->PendingIrpCount--;
- DeviceExtension->PendingIrpCount--;
- Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
- LunExtension->ActiveIrpCount++;
- DeviceExtension->ActiveIrpCount++;
-
- RemoveEntryList((PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
- Irp->Tail.Overlay.DriverContext[2] = LunExtension;
- Srb->OriginalRequest = Irp;
- SpiAllocateSrbExtension(DeviceExtension, Srb);
-
- InsertHeadList(&NextIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
- }
- }
- }
+ /* Just copy */
+ RtlCopyMemory(
+ InternalConfigInfo->Parameter,
+ (PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
+ KeyValueInformation->DataLength);
+ }
+ else
+ {
+ /* If it's a unicode string, convert it to ansi */
+ UnicodeString.Length = (USHORT)KeyValueInformation->DataLength;
+ UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
+ UnicodeString.Buffer =
+ (PWSTR)((PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
+
+ AnsiString.Length = 0;
+ AnsiString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
+ AnsiString.Buffer = (PCHAR)InternalConfigInfo->Parameter;
+
+ Status = RtlUnicodeStringToAnsiString(&AnsiString,
+ &UnicodeString,
+ FALSE);
+
+ /* In case of error, free the allocated space */
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePool(InternalConfigInfo->Parameter);
+ InternalConfigInfo->Parameter = NULL;
+ }
+
+ }
+ }
- if (!IsListEmpty(&NextIrpListHead))
+ DPRINT("Found driver parameter\n");
+ }
+
+ /* Get MaximumSGList */
+ if (_wcsnicmp(KeyValueInformation->Name, L"MaximumSGList",
+ KeyValueInformation->NameLength/2) == 0)
{
- while (!IsListEmpty(&NextIrpListHead))
- {
- ListEntry = RemoveTailList(&NextIrpListHead);
- Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
- KeReleaseSpinLockFromDpcLevel(&DeviceExtension->Lock);
+ if (KeyValueInformation->Type != REG_DWORD)
+ {
+ DPRINT("Bad data type for MaximumSGList\n");
+ continue;
+ }
- // Start this Irp
- SpiStartIo(DeviceExtension, Irp);
- KeAcquireSpinLockAtDpcLevel(&DeviceExtension->Lock);
- }
- }
+ ConfigInfo->NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
+
+ /* Check / fix */
+ if (ConfigInfo->NumberOfPhysicalBreaks > SCSI_MAXIMUM_PHYSICAL_BREAKS)
+ {
+ ConfigInfo->NumberOfPhysicalBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS;
+ }
+ else if (ConfigInfo->NumberOfPhysicalBreaks < SCSI_MINIMUM_PHYSICAL_BREAKS)
+ {
+ ConfigInfo->NumberOfPhysicalBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS;
+ }
- if (!IsListEmpty(&DeviceExtension->PendingIrpListHead) &&
- DeviceExtension->NextIrp == NULL &&
- (DeviceExtension->SrbExtensionSize == 0 || DeviceExtension->CurrentSrbExtensions < DeviceExtension->MaxSrbExtensions))
+ DPRINT("MaximumSGList = %d\n", ConfigInfo->NumberOfPhysicalBreaks);
+ }
+
+ /* Get NumberOfRequests */
+ if (_wcsnicmp(KeyValueInformation->Name, L"NumberOfRequests",
+ KeyValueInformation->NameLength/2) == 0)
{
- ListEntry = RemoveHeadList(&DeviceExtension->PendingIrpListHead);
- Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
- Srb = Irp->Tail.Overlay.DriverContext[3];
- LunExtension = Srb->OriginalRequest;
- Irp->Tail.Overlay.DriverContext[2] = LunExtension;
- Srb->OriginalRequest = Irp;
+ if (KeyValueInformation->Type != REG_DWORD)
+ {
+ DPRINT("NumberOfRequests has wrong data type\n");
+ continue;
+ }
- LunExtension->PendingIrpCount--;
- DeviceExtension->PendingIrpCount--;
- Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
- LunExtension->ActiveIrpCount++;
- DeviceExtension->ActiveIrpCount++;
+ DeviceExtension->RequestsNumber = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
- SpiAllocateSrbExtension(DeviceExtension, Srb);
- KeReleaseSpinLockFromDpcLevel(&DeviceExtension->Lock);
+ /* Check / fix */
+ if (DeviceExtension->RequestsNumber < 16)
+ {
+ DeviceExtension->RequestsNumber = 16;
+ }
+ else if (DeviceExtension->RequestsNumber > 512)
+ {
+ DeviceExtension->RequestsNumber = 512;
+ }
- /* Start this irp */
- SpiStartIo(DeviceExtension, Irp);
- KeAcquireSpinLockAtDpcLevel(&DeviceExtension->Lock);
+ DPRINT("Number Of Requests = %d\n", DeviceExtension->RequestsNumber);
}
- }
- KeReleaseSpinLock(&DeviceExtension->Lock, oldIrql);
- DPRINT("SpiProcessRequests() done\n");
- }
+ /* Get resource list */
+ if (_wcsnicmp(KeyValueInformation->Name, L"ResourceList",
+ KeyValueInformation->NameLength/2) == 0 ||
+ _wcsnicmp(KeyValueInformation->Name, L"Configuration Data",
+ KeyValueInformation->NameLength/2) == 0 )
+ {
+ if (KeyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR ||
+ KeyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR))
+ {
+ DPRINT("Bad data type for ResourceList\n");
+ continue;
+ }
+ else
+ {
+ DPRINT("Found ResourceList\n");
+ }
-static VOID
-SpiStartIo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- IN PIRP Irp)
+ FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)(Buffer + KeyValueInformation->DataOffset);
+
+ /* Copy some info from it */
+ InternalConfigInfo->BusNumber = FullResource->BusNumber;
+ ConfigInfo->SystemIoBusNumber = FullResource->BusNumber;
+
+ /* Loop through it */
+ for (Count = 0; Count < FullResource->PartialResourceList.Count; Count++)
+ {
+ /* Get partial descriptor */
+ PartialDescriptor =
+ &FullResource->PartialResourceList.PartialDescriptors[Count];
+
+ /* Check datalength */
+ if ((ULONG)((PCHAR)(PartialDescriptor + 1) -
+ (PCHAR)FullResource) > KeyValueInformation->DataLength)
+ {
+ DPRINT("Resource data is of incorrect size\n");
+ break;
+ }
+
+ switch (PartialDescriptor->Type)
+ {
+ case CmResourceTypePort:
+ if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
+ {
+ DPRINT("Too many access ranges\n");
+ continue;
+ }
+
+ InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = FALSE;
+ InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Port.Start;
+ InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Port.Length;
+ RangeCount++;
+
+ break;
+
+ case CmResourceTypeMemory:
+ if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
+ {
+ DPRINT("Too many access ranges\n");
+ continue;
+ }
+
+ InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = TRUE;
+ InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Memory.Start;
+ InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Memory.Length;
+ RangeCount++;
+
+ break;
+
+ case CmResourceTypeInterrupt:
+ ConfigInfo->BusInterruptLevel =
+ PartialDescriptor->u.Interrupt.Level;
+
+ ConfigInfo->BusInterruptVector =
+ PartialDescriptor->u.Interrupt.Vector;
+ break;
+
+ case CmResourceTypeDma:
+ ConfigInfo->DmaChannel = PartialDescriptor->u.Dma.Channel;
+ ConfigInfo->DmaPort = PartialDescriptor->u.Dma.Port;
+ break;
+
+ case CmResourceTypeDeviceSpecific:
+ if (PartialDescriptor->u.DeviceSpecificData.DataSize <
+ sizeof(CM_SCSI_DEVICE_DATA) ||
+ (PCHAR) (PartialDescriptor + 1) - (PCHAR)FullResource +
+ PartialDescriptor->u.DeviceSpecificData.DataSize >
+ KeyValueInformation->DataLength)
+ {
+ DPRINT("Resource data length is incorrect");
+ break;
+ }
+
+ /* Set only one field from it */
+ ScsiDeviceData = (PCM_SCSI_DEVICE_DATA) (PartialDescriptor+1);
+ ConfigInfo->InitiatorBusId[0] = ScsiDeviceData->HostIdentifier;
+ break;
+ }
+ }
+ }
+ }
+}
+
+NTSTATUS
+NTAPI
+SpQueryDeviceCallout(IN PVOID Context,
+ IN PUNICODE_STRING PathName,
+ IN INTERFACE_TYPE BusType,
+ IN ULONG BusNumber,
+ IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
+ IN CONFIGURATION_TYPE ControllerType,
+ IN ULONG ControllerNumber,
+ IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
+ IN CONFIGURATION_TYPE PeripheralType,
+ IN ULONG PeripheralNumber,
+ IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation)
{
- PSCSI_PORT_LUN_EXTENSION LunExtension;
- PSCSI_REQUEST_BLOCK Srb;
+ PBOOLEAN Found = (PBOOLEAN)Context;
+ /* We just set our Found variable to TRUE */
+
+ *Found = TRUE;
+ return STATUS_SUCCESS;
+}
+
+IO_ALLOCATION_ACTION
+NTAPI
+ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context)
+{
+ KIRQL Irql;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
- DPRINT("SpiStartIo() called!\n");
+ /* Guard access with the spinlock */
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
- assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+ /* Save MapRegisterBase we've got here */
+ DeviceExtension->MapRegisterBase = MapRegisterBase;
- Srb = Irp->Tail.Overlay.DriverContext[3];
- LunExtension = Irp->Tail.Overlay.DriverContext[2];
+ /* Start pending request */
+ KeSynchronizeExecution(DeviceExtension->Interrupt,
+ ScsiPortStartPacket, DeviceObject);
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = Srb->DataTransferLength;
+ /* Release spinlock we took */
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
- SpiAddActiveIrp(DeviceExtension, Irp);
+ return KeepObject;
+}
- if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
- ScsiPortStartPacket,
- Srb))
+static
+NTSTATUS
+SpiStatusSrbToNt(UCHAR SrbStatus)
+{
+ switch (SRB_STATUS(SrbStatus))
{
- DPRINT1("Synchronization failed!\n");
- DPRINT1("Irp %x, Srb->Function %02x, Srb->Cdb[0] %02x, Srb->SrbStatus %02x\n", Irp, Srb->Function, Srb->Cdb[0], Srb->SrbStatus);
- ScsiPortNotification(RequestComplete,
- &DeviceExtension->MiniPortDeviceExtension,
- Srb);
+ case SRB_STATUS_TIMEOUT:
+ case SRB_STATUS_COMMAND_TIMEOUT:
+ return STATUS_IO_TIMEOUT;
+
+ case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
+ case SRB_STATUS_BAD_FUNCTION:
+ return STATUS_INVALID_DEVICE_REQUEST;
+
+ case SRB_STATUS_NO_DEVICE:
+ case SRB_STATUS_INVALID_LUN:
+ case SRB_STATUS_INVALID_TARGET_ID:
+ case SRB_STATUS_NO_HBA:
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+
+ case SRB_STATUS_DATA_OVERRUN:
+ return STATUS_BUFFER_OVERFLOW;
+
+ case SRB_STATUS_SELECTION_TIMEOUT:
+ return STATUS_DEVICE_NOT_CONNECTED;
+
+ default:
+ return STATUS_IO_DEVICE_ERROR;
}
- DPRINT("SpiStartIo() done\n");
+ return STATUS_IO_DEVICE_ERROR;
}
+#undef ScsiPortConvertPhysicalAddressToUlong
+/*
+ * @implemented
+ */
+ULONG NTAPI
+ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
+{
+ DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
+ return(Address.u.LowPart);
+}
+
/* EOF */