--- /dev/null
+/*
+ * ReactOS kernel
+ * Copyright (C) 2001, 2002 ReactOS Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* $Id: scsiport.c,v 1.52 2004/04/02 15:43:01 hbirr Exp $
+ *
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: services/storage/scsiport/scsiport.c
+ * PURPOSE: SCSI port driver
+ * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include <ddk/ntddk.h>
+#include <ddk/srb.h>
+#include <ddk/scsi.h>
+#include <ddk/ntddscsi.h>
+#include <rosrtl/string.h>
+
+#define NDEBUG
+#include <debug.h>
+
+
+#define VERSION "0.0.1"
+
+#include "scsiport_int.h"
+
+/* #define USE_DEVICE_QUEUES */
+
+/* TYPES *********************************************************************/
+
+#define IRP_FLAG_COMPLETE 0x00000001
+#define IRP_FLAG_NEXT 0x00000002
+#define IRP_FLAG_NEXT_LU 0x00000004
+
+
+/* GLOBALS *******************************************************************/
+
+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
+ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+static NTSTATUS STDCALL
+ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+static NTSTATUS STDCALL
+ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+static VOID STDCALL
+ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+static BOOLEAN STDCALL
+ScsiPortStartPacket(IN OUT 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);
+
+static PSCSI_PORT_LUN_EXTENSION
+SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun);
+
+static NTSTATUS
+SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
+ IN OUT PSCSI_REQUEST_BLOCK Srb);
+
+static VOID
+SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
+
+static ULONG
+SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo);
+
+static BOOLEAN STDCALL
+ScsiPortIsr(IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext);
+
+static VOID STDCALL
+ScsiPortDpcForIsr(IN PKDPC Dpc,
+ IN PDEVICE_OBJECT DpcDeviceObject,
+ IN PIRP DpcIrp,
+ IN PVOID DpcContext);
+
+static VOID STDCALL
+ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
+ PVOID Context);
+
+static PSCSI_REQUEST_BLOCK
+ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ PSCSI_REQUEST_BLOCK OriginalSrb);
+
+static VOID
+ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
+
+static NTSTATUS
+SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ PUNICODE_STRING RegistryPath);
+
+
+/* FUNCTIONS *****************************************************************/
+
+/**********************************************************************
+ * NAME EXPORTED
+ * DriverEntry
+ *
+ * DESCRIPTION
+ * This function initializes the driver.
+ *
+ * RUN LEVEL
+ * PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ * DriverObject
+ * System allocated Driver Object for this driver.
+ *
+ * RegistryPath
+ * Name of registry driver service key.
+ *
+ * RETURN VALUE
+ * Status.
+ */
+
+NTSTATUS STDCALL
+DriverEntry(IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath)
+{
+ DPRINT("ScsiPort Driver %s\n", VERSION);
+ return(STATUS_SUCCESS);
+}
+
+
+/**********************************************************************
+ * NAME EXPORTED
+ * ScsiDebugPrint
+ *
+ * DESCRIPTION
+ * Prints debugging messages.
+ *
+ * RUN LEVEL
+ * PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ * DebugPrintLevel
+ * Debug level of the given message.
+ *
+ * DebugMessage
+ * Pointer to printf()-compatible format string.
+ *
+ * ...
+ Additional output data (see printf()).
+ *
+ * RETURN VALUE
+ * None.
+ *
+ * @implemented
+ */
+
+VOID
+ScsiDebugPrint(IN ULONG DebugPrintLevel,
+ IN PCHAR DebugMessage,
+ ...)
+{
+ char Buffer[256];
+ va_list ap;
+
+#if 0
+ if (DebugPrintLevel > InternalDebugLevel)
+ return;
+#endif
+
+ va_start(ap, DebugMessage);
+ vsprintf(Buffer, DebugMessage, ap);
+ va_end(ap);
+
+ DbgPrint(Buffer);
+}
+
+
+/*
+ * @unimplemented
+ */
+VOID STDCALL
+ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN UCHAR SrbStatus)
+{
+ DPRINT("ScsiPortCompleteRequest()\n");
+ UNIMPLEMENTED;
+}
+
+
+/*
+ * @implemented
+ */
+ULONG STDCALL
+ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
+{
+ DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
+ return(Address.u.LowPart);
+}
+
+
+/*
+ * @unimplemented
+ */
+VOID STDCALL
+ScsiPortFlushDma(IN PVOID HwDeviceExtension)
+{
+ DPRINT("ScsiPortFlushDma()\n");
+ UNIMPLEMENTED;
+}
+
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
+ IN PVOID MappedAddress)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PSCSI_PORT_DEVICE_BASE DeviceBase;
+ PLIST_ENTRY Entry;
+
+ DPRINT("ScsiPortFreeDeviceBase() called\n");
+
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
+ if (IsListEmpty(&DeviceExtension->DeviceBaseListHead))
+ return;
+
+ Entry = DeviceExtension->DeviceBaseListHead.Flink;
+ while (Entry != &DeviceExtension->DeviceBaseListHead)
+ {
+ DeviceBase = CONTAINING_RECORD(Entry,
+ SCSI_PORT_DEVICE_BASE,
+ List);
+ if (DeviceBase->MappedAddress == MappedAddress)
+ {
+ MmUnmapIoSpace(DeviceBase->MappedAddress,
+ DeviceBase->NumberOfBytes);
+ RemoveEntryList(Entry);
+ ExFreePool(DeviceBase);
+
+ return;
+ }
+
+ Entry = Entry->Flink;
+ }
+}
+
+
+/*
+ * @implemented
+ */
+ULONG STDCALL
+ScsiPortGetBusData(IN PVOID DeviceExtension,
+ IN ULONG BusDataType,
+ IN ULONG SystemIoBusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Length)
+{
+ return(HalGetBusData(BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ Buffer,
+ Length));
+}
+
+
+/*
+ * @implemented
+ */
+PVOID STDCALL
+ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
+ IN INTERFACE_TYPE BusType,
+ IN ULONG SystemIoBusNumber,
+ IN SCSI_PHYSICAL_ADDRESS IoAddress,
+ 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;
+
+ /* i/o space */
+ if (AddressSpace != 0)
+ return((PVOID)TranslatedAddress.u.LowPart);
+
+ MappedAddress = MmMapIoSpace(TranslatedAddress,
+ NumberOfBytes,
+ FALSE);
+
+ DeviceBase = ExAllocatePool(NonPagedPool,
+ sizeof(SCSI_PORT_DEVICE_BASE));
+ if (DeviceBase == NULL)
+ return(MappedAddress);
+
+ DeviceBase->MappedAddress = MappedAddress;
+ DeviceBase->NumberOfBytes = NumberOfBytes;
+ DeviceBase->IoAddress = IoAddress;
+ DeviceBase->SystemIoBusNumber = SystemIoBusNumber;
+
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
+
+ InsertHeadList(&DeviceExtension->DeviceBaseListHead,
+ &DeviceBase->List);
+
+ return(MappedAddress);
+}
+
+
+/*
+ * @implemented
+ */
+PVOID STDCALL
+ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ PLIST_ENTRY Entry;
+
+ DPRINT("ScsiPortGetLogicalUnit() called\n");
+
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
+ if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
+ return NULL;
+
+ Entry = DeviceExtension->LunExtensionListHead.Flink;
+ while (Entry != &DeviceExtension->LunExtensionListHead)
+ {
+ LunExtension = CONTAINING_RECORD(Entry,
+ SCSI_PORT_LUN_EXTENSION,
+ List);
+ if (LunExtension->PathId == PathId &&
+ LunExtension->TargetId == TargetId &&
+ LunExtension->Lun == Lun)
+ {
+ return (PVOID)&LunExtension->MiniportLunExtension;
+ }
+
+ Entry = Entry->Flink;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * @unimplemented
+ */
+SCSI_PHYSICAL_ADDRESS STDCALL
+ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
+ 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;
+
+ DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
+ HwDeviceExtension, Srb, VirtualAddress, Length);
+
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
+
+ *Length = 0;
+
+ if (Srb == NULL)
+ {
+ if ((ULONG_PTR)DeviceExtension->VirtualAddress > (ULONG_PTR)VirtualAddress)
+ {
+ PhysicalAddress.QuadPart = 0ULL;
+ return PhysicalAddress;
+ }
+
+ Offset = (ULONG_PTR)VirtualAddress - (ULONG_PTR)DeviceExtension->VirtualAddress;
+ if (Offset >= DeviceExtension->CommonBufferLength)
+ {
+ PhysicalAddress.QuadPart = 0ULL;
+ return PhysicalAddress;
+ }
+
+ PhysicalAddress.QuadPart =
+ DeviceExtension->PhysicalAddress.QuadPart + (ULONGLONG)Offset;
+ BufferLength = DeviceExtension->CommonBufferLength - Offset;
+ }
+ else
+ {
+ EndAddress = Srb->DataBuffer + Srb->DataTransferLength;
+ if (VirtualAddress == NULL)
+ {
+ VirtualAddress = Srb->DataBuffer;
+ }
+ else if (VirtualAddress < Srb->DataBuffer || VirtualAddress >= EndAddress)
+ {
+ PhysicalAddress.QuadPart = 0LL;
+ return PhysicalAddress;
+ }
+
+ PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
+ if (PhysicalAddress.QuadPart == 0LL)
+ {
+ return PhysicalAddress;
+ }
+
+ Offset = (ULONG_PTR)VirtualAddress & (PAGE_SIZE - 1);
+#if 1
+ /*
+ * FIXME:
+ * MmGetPhysicalAddress doesn't return the offset within the page.
+ * We must set the correct offset.
+ */
+ PhysicalAddress.u.LowPart = (PhysicalAddress.u.LowPart & ~(PAGE_SIZE - 1)) + Offset;
+#endif
+ BufferLength += PAGE_SIZE - Offset;
+ while (VirtualAddress + BufferLength < EndAddress)
+ {
+ NextPhysicalAddress = MmGetPhysicalAddress(VirtualAddress + BufferLength);
+ if (PhysicalAddress.QuadPart + (ULONGLONG)BufferLength != NextPhysicalAddress.QuadPart)
+ {
+ break;
+ }
+ BufferLength += PAGE_SIZE;
+ }
+ if (VirtualAddress + BufferLength >= EndAddress)
+ {
+ BufferLength = EndAddress - VirtualAddress;
+ }
+ }
+
+ *Length = BufferLength;
+
+ return PhysicalAddress;
+}
+
+
+/*
+ * @unimplemented
+ */
+PSCSI_REQUEST_BLOCK STDCALL
+ScsiPortGetSrb(IN PVOID DeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN LONG QueueTag)
+{
+ DPRINT1("ScsiPortGetSrb() unimplemented\n");
+ UNIMPLEMENTED;
+ return NULL;
+}
+
+
+/*
+ * @implemented
+ */
+PVOID STDCALL
+ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
+ IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN ULONG NumberOfBytes)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ DEVICE_DESCRIPTION DeviceDescription;
+
+ DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
+ HwDeviceExtension, ConfigInfo, NumberOfBytes);
+
+ 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;
+ }
+ }
+
+ /* Allocate a common DMA buffer */
+ DeviceExtension->CommonBufferLength =
+ NumberOfBytes + DeviceExtension->SrbExtensionSize;
+ DeviceExtension->VirtualAddress =
+ HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
+ DeviceExtension->CommonBufferLength,
+ &DeviceExtension->PhysicalAddress,
+ FALSE);
+ if (DeviceExtension->VirtualAddress == NULL)
+ {
+ DPRINT1("HalAllocateCommonBuffer() failed!\n");
+ DeviceExtension->CommonBufferLength = 0;
+ return NULL;
+ }
+
+ return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress +
+ DeviceExtension->SrbExtensionSize);
+}
+
+
+/*
+ * @implemented
+ */
+PVOID STDCALL
+ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
+ IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ ULONG Offset;
+
+ DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
+ HwDeviceExtension, PhysicalAddress.QuadPart);
+
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
+
+ if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
+ return NULL;
+
+ Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
+ if (Offset >= DeviceExtension->CommonBufferLength)
+ return NULL;
+
+ return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + Offset);
+}
+
+
+/**********************************************************************
+ * NAME EXPORTED
+ * ScsiPortInitialize
+ *
+ * DESCRIPTION
+ * Initializes SCSI port driver specific data.
+ *
+ * RUN LEVEL
+ * PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ * Argument1
+ * Pointer to the miniport driver's driver object.
+ *
+ * Argument2
+ * Pointer to the miniport driver's registry path.
+ *
+ * HwInitializationData
+ * Pointer to port driver specific configuration data.
+ *
+ * HwContext
+ Miniport driver specific context.
+ *
+ * RETURN VALUE
+ * Status.
+ *
+ * @implemented
+ */
+
+ULONG STDCALL
+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;
+
+ 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;
+
+
+ DPRINT ("ScsiPortInitialize() called!\n");
+
+ if ((HwInitializationData->HwInitialize == NULL) ||
+ (HwInitializationData->HwStartIo == NULL) ||
+ (HwInitializationData->HwInterrupt == NULL) ||
+ (HwInitializationData->HwFindAdapter == NULL) ||
+ (HwInitializationData->HwResetBus == NULL))
+ return(STATUS_INVALID_PARAMETER);
+
+ 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_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;
+ }
+
+ DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
+
+ /* Set the buffering strategy here... */
+ PortDeviceObject->Flags |= DO_DIRECT_IO;
+ PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
+
+ DeviceExtension = PortDeviceObject->DeviceExtension;
+ 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;
+
+#if 0
+ DeviceExtension->AdapterObject = NULL;
+ DeviceExtension->MapRegisterCount = 0;
+ DeviceExtension->PhysicalAddress.QuadPart = 0ULL;
+ DeviceExtension->VirtualAddress = NULL;
+ DeviceExtension->CommonBufferLength = 0;
+#endif
+
+ /* Initialize the device base list */
+ InitializeListHead (&DeviceExtension->DeviceBaseListHead);
+
+ /* Initialize LUN-Extension list */
+ InitializeListHead (&DeviceExtension->LunExtensionListHead);
+
+ /* Initialize the spin lock in the controller extension */
+ KeInitializeSpinLock (&DeviceExtension->IrpLock);
+ KeInitializeSpinLock (&DeviceExtension->SpinLock);
+
+ /* Initialize the DPC object */
+ IoInitializeDpcRequest (PortDeviceObject,
+ ScsiPortDpcForIsr);
+
+ /* 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 =
+// PortConfig->DmaSpeed =
+// PortConfig->AlignmentMask =
+ PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
+// PortConfig->NumberOfBuses =
+
+ for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
+ PortConfig->InitiatorBusId[i] = 255;
+
+// PortConfig->ScatterGather =
+// PortConfig->Master =
+// PortConfig->CachesData =
+// PortConfig->AdapterScansDown =
+ PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
+ PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
+// PortConfig->Dma32BitAddresses =
+// PortConfig->DemandMode =
+ PortConfig->MapBuffers = HwInitializationData->MapBuffers;
+ PortConfig->NeedPhysicalAddresses = HwInitializationData->NeedPhysicalAddresses;
+ PortConfig->TaggedQueuing = HwInitializationData->TaggedQueueing;
+ PortConfig->AutoRequestSense = HwInitializationData->AutoRequestSense;
+ PortConfig->MultipleRequestPerLu = HwInitializationData->MultipleRequestPerLu;
+ PortConfig->ReceiveEvent = HwInitializationData->ReceiveEvent;
+// PortConfig->RealModeInitialized =
+// PortConfig->BufferAccessScsiPortControlled =
+ PortConfig->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS;
+// PortConfig->MaximumNumberOfLogicalUnits = SCSI_MAXIMUM_LOGICAL_UNITS;
+
+ PortConfig->SlotNumber = SlotNumber.u.AsULONG;
+
+ PortConfig->AccessRanges = (PACCESS_RANGE)(PortConfig + 1);
+
+ /* 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;
+ }
+ }
+
+ /* 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");
+
+ if (Result == SP_RETURN_FOUND)
+ {
+ DPRINT("ScsiPortInitialize(): Found HBA! (%x)\n", PortConfig->BusInterruptVector);
+
+ /* Register an interrupt handler for this device */
+ MappedIrq = HalGetInterruptVector(PortConfig->AdapterInterfaceType,
+ PortConfig->SystemIoBusNumber,
+ PortConfig->BusInterruptLevel,
+ PortConfig->BusInterruptVector,
+ &Dirql,
+ &Affinity);
+ Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
+ ScsiPortIsr,
+ DeviceExtension,
+ &DeviceExtension->SpinLock,
+ MappedIrq,
+ Dirql,
+ Dirql,
+ PortConfig->InterruptMode,
+ TRUE,
+ Affinity,
+ FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("Could not connect interrupt %d\n",
+ PortConfig->BusInterruptVector);
+ goto ByeBye;
+ }
+
+ if (!(HwInitializationData->HwInitialize)(&DeviceExtension->MiniPortDeviceExtension))
+ {
+ DbgPrint("HwInitialize() failed!");
+ Status = STATUS_UNSUCCESSFUL;
+ goto ByeBye;
+ }
+
+ /* 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;
+ }
+
+ PortCapabilities = DeviceExtension->PortCapabilities;
+ PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
+ PortCapabilities->MaximumTransferLength =
+ PortConfig->MaximumTransferLength;
+ 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;
+ }
+ else
+ {
+ DPRINT("HwFindAdapter() Result: %lu\n", Result);
+
+ ExFreePool (PortConfig);
+ IoDeleteDevice (PortDeviceObject);
+ PortDeviceObject = NULL;
+ }
+
+ 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;
+ }
+ }
+
+ByeBye:
+ /* Clean up the mess */
+ if (PortDeviceObject != NULL)
+ {
+ DPRINT("Delete device: %p\n", PortDeviceObject);
+
+ DeviceExtension = PortDeviceObject->DeviceExtension;
+
+ if (DeviceExtension->PortCapabilities != NULL)
+ {
+ IoDisconnectInterrupt (DeviceExtension->Interrupt);
+ ExFreePool (DeviceExtension->PortCapabilities);
+ }
+
+ if (DeviceExtension->PortConfig != NULL)
+ {
+ ExFreePool (DeviceExtension->PortConfig);
+ }
+
+ IoDeleteDevice (PortDeviceObject);
+ }
+
+ DPRINT("ScsiPortInitialize() done!\n");
+
+ return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
+}
+
+
+/*
+ * @unimplemented
+ */
+VOID STDCALL
+ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN ULONG LogicalAddress,
+ IN ULONG Length)
+{
+ DPRINT1("ScsiPortIoMapTransfer()\n");
+ UNIMPLEMENTED;
+}
+
+
+/*
+ * @unimplemented
+ */
+VOID STDCALL
+ScsiPortLogError(IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN ULONG ErrorCode,
+ IN ULONG UniqueId)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+
+ DPRINT1("ScsiPortLogError() called\n");
+
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
+
+
+ DPRINT("ScsiPortLogError() done\n");
+}
+
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+ScsiPortMoveMemory(OUT PVOID Destination,
+ IN PVOID Source,
+ IN ULONG Length)
+{
+ RtlMoveMemory(Destination,
+ Source,
+ Length);
+}
+
+
+/*
+ * @implemented
+ */
+VOID
+ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
+ IN PVOID HwDeviceExtension,
+ ...)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ va_list ap;
+
+ DPRINT("ScsiPortNotification() called\n");
+
+ DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+ SCSI_PORT_DEVICE_EXTENSION,
+ MiniPortDeviceExtension);
+
+ DPRINT("DeviceExtension %p\n", DeviceExtension);
+
+ va_start(ap, HwDeviceExtension);
+
+ switch (NotificationType)
+ {
+ case RequestComplete:
+ {
+ PSCSI_REQUEST_BLOCK Srb;
+
+ Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
+
+ DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
+ DeviceExtension->IrpFlags |= IRP_FLAG_COMPLETE;
+ }
+ break;
+
+ case NextRequest:
+ DPRINT("Notify: NextRequest\n");
+ DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
+ break;
+
+ case NextLuRequest:
+ {
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+
+ PathId = (UCHAR) va_arg (ap, int);
+ TargetId = (UCHAR) va_arg (ap, int);
+ Lun = (UCHAR) va_arg (ap, int);
+
+ DPRINT1 ("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
+ PathId, TargetId, Lun);
+ /* FIXME: Implement it! */
+
+ DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
+// DeviceExtension->IrpFlags |= IRP_FLAG_NEXT_LU;
+
+ /* Hack! */
+ DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
+ }
+ break;
+
+ case ResetDetected:
+ DPRINT1("Notify: ResetDetected\n");
+ /* FIXME: ??? */
+ break;
+
+ default:
+ DPRINT1 ("Unsupported notification %lu\n", NotificationType);
+ break;
+ }
+
+ 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));
+}
+
+
+/*
+ * @implemented
+ */
+BOOLEAN STDCALL
+ScsiPortValidateRange(IN PVOID HwDeviceExtension,
+ IN INTERFACE_TYPE BusType,
+ IN ULONG SystemIoBusNumber,
+ IN SCSI_PHYSICAL_ADDRESS IoAddress,
+ IN ULONG NumberOfBytes,
+ IN BOOLEAN InIoSpace)
+{
+ DPRINT("ScsiPortValidateRange()\n");
+ return(TRUE);
+}
+
+
+/* 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)
+{
+ 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");
+
+ if (NextSlotNumber->u.bits.FunctionNumber >= PCI_MAX_FUNCTION)
+ {
+ NextSlotNumber->u.bits.FunctionNumber = 0;
+ NextSlotNumber->u.bits.DeviceNumber++;
+ }
+
+ if (NextSlotNumber->u.bits.DeviceNumber >= PCI_MAX_DEVICES)
+ {
+ NextSlotNumber->u.bits.DeviceNumber = 0;
+ return FALSE;
+ }
+
+ for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
+ {
+ SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+
+ 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;
+ }
+ }
+
+ sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
+ sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
+
+ 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;
+
+ 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");
+ }
+ }
+ }
+ }
+
+ NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
+ NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
+
+ return TRUE;
+ }
+
+
+ if (FunctionNumber == 0 && !(PciConfig.HeaderType & PCI_MULTIFUNCTION))
+ {
+ break;
+ }
+ }
+ NextSlotNumber->u.bits.FunctionNumber = 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 STDCALL
+ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ DPRINT("ScsiPortCreateClose()\n");
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = FILE_OPENED;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return(STATUS_SUCCESS);
+}
+
+
+/**********************************************************************
+ * NAME INTERNAL
+ * ScsiPortDispatchScsi
+ *
+ * DESCRIPTION
+ * Answer requests for SCSI calls
+ *
+ * RUN LEVEL
+ * PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ * Standard dispatch arguments
+ *
+ * RETURNS
+ * NTSTATUS
+ */
+
+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;
+
+ DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
+ DeviceObject, Irp);
+
+ DeviceExtension = DeviceObject->DeviceExtension;
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+
+ Srb = Stack->Parameters.Scsi.Srb;
+ if (Srb == NULL)
+ {
+ 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)
+ {
+ 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_EXECUTE_SCSI:
+ case SRB_FUNCTION_IO_CONTROL:
+#ifdef USE_DEVICE_QUEUES
+ if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
+ {
+ IoMarkIrpPending(Irp);
+ IoStartPacket (DeviceObject, Irp, NULL, NULL);
+ }
+ else
+ {
+ KIRQL oldIrql;
+
+ KeRaiseIrql (DISPATCH_LEVEL,
+ &oldIrql);
+
+ if (!KeInsertByKeyDeviceQueue (&LunExtension->DeviceQueue,
+ &Irp->Tail.Overlay.DeviceQueueEntry,
+ Srb->QueueSortKey))
+ {
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ IoMarkIrpPending(Irp);
+ IoStartPacket (DeviceObject, Irp, NULL, NULL);
+ }
+
+ KeLowerIrql (oldIrql);
+ }
+#else
+ IoMarkIrpPending(Irp);
+ IoStartPacket (DeviceObject, Irp, NULL, NULL);
+#endif
+ return(STATUS_PENDING);
+
+ case SRB_FUNCTION_SHUTDOWN:
+ case SRB_FUNCTION_FLUSH:
+ if (DeviceExtension->PortConfig->CachesData == TRUE)
+ {
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+ return(STATUS_PENDING);
+ }
+ break;
+
+ case SRB_FUNCTION_CLAIM_DEVICE:
+ DPRINT (" SRB_FUNCTION_CLAIM_DEVICE\n");
+
+ /* Reference device object and keep the device object */
+ ObReferenceObject(DeviceObject);
+ LunExtension->DeviceObject = DeviceObject;
+ LunExtension->DeviceClaimed = TRUE;
+ Srb->DataBuffer = DeviceObject;
+ break;
+
+ 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);
+
+ /* Dereference device object and clear the device object */
+ ObDereferenceObject(LunExtension->DeviceObject);
+ LunExtension->DeviceObject = NULL;
+ LunExtension->DeviceClaimed = FALSE;
+ break;
+
+ default:
+ DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = DataSize;
+
+ 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 STDCALL
+ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION Stack;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+
+ DPRINT("ScsiPortDeviceControl()\n");
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ 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");
+
+ *((PIO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer) =
+ DeviceExtension->PortCapabilities;
+
+ Irp->IoStatus.Information = sizeof(PIO_SCSI_CAPABILITIES);
+ }
+ break;
+
+ case IOCTL_SCSI_GET_INQUIRY_DATA:
+ {
+ DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
+
+ /* 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;
+
+ default:
+ DPRINT1(" unknown ioctl code: 0x%lX\n",
+ Stack->Parameters.DeviceIoControl.IoControlCode);
+ break;
+ }
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return(STATUS_SUCCESS);
+}
+
+
+static VOID STDCALL
+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;
+ KIRQL oldIrql;
+
+ DPRINT("ScsiPortStartIo() called!\n");
+
+ DeviceExtension = DeviceObject->DeviceExtension;
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ DPRINT("DeviceExtension %p\n", DeviceExtension);
+
+ oldIrql = KeGetCurrentIrql();
+
+ if (IrpStack->MajorFunction != IRP_MJ_SCSI)
+ {
+ DPRINT("No IRP_MJ_SCSI!\n");
+ Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp,
+ IO_NO_INCREMENT);
+ if (oldIrql < DISPATCH_LEVEL)
+ {
+ KeRaiseIrql (DISPATCH_LEVEL,
+ &oldIrql);
+ IoStartNextPacket (DeviceObject,
+ FALSE);
+ KeLowerIrql (oldIrql);
+ }
+ else
+ {
+ IoStartNextPacket (DeviceObject,
+ FALSE);
+ }
+ return;
+ }
+
+ Srb = IrpStack->Parameters.Scsi.Srb;
+
+ LunExtension = SpiGetLunExtension(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+ if (LunExtension == NULL)
+ {
+ DPRINT("Can't get LunExtension!\n");
+ Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp,
+ IO_NO_INCREMENT);
+ if (oldIrql < DISPATCH_LEVEL)
+ {
+ KeRaiseIrql (DISPATCH_LEVEL,
+ &oldIrql);
+ IoStartNextPacket (DeviceObject,
+ FALSE);
+ KeLowerIrql (oldIrql);
+ }
+ else
+ {
+ IoStartNextPacket (DeviceObject,
+ FALSE);
+ }
+ return;
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = Srb->DataTransferLength;
+
+ DeviceExtension->CurrentIrp = Irp;
+
+ if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
+ ScsiPortStartPacket,
+ DeviceExtension))
+ {
+ DPRINT("Synchronization failed!\n");
+
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp,
+ IO_NO_INCREMENT);
+ if (oldIrql < DISPATCH_LEVEL)
+ {
+ KeRaiseIrql (DISPATCH_LEVEL,
+ &oldIrql);
+ IoStartNextPacket (DeviceObject,
+ FALSE);
+ KeLowerIrql (oldIrql);
+ }
+ else
+ {
+ IoStartNextPacket (DeviceObject,
+ FALSE);
+ }
+ }
+
+ KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
+ if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
+ {
+ DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
+ IoCompleteRequest(Irp,
+ IO_NO_INCREMENT);
+ }
+
+ if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
+ {
+ DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
+ IoStartNextPacket(DeviceObject,
+ FALSE);
+ KeLowerIrql(oldIrql);
+ }
+ else
+ {
+ KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
+ }
+
+ DPRINT("ScsiPortStartIo() done\n");
+}
+
+
+static BOOLEAN STDCALL
+ScsiPortStartPacket(IN OUT PVOID Context)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PIO_STACK_LOCATION IrpStack;
+ PSCSI_REQUEST_BLOCK Srb;
+
+ DPRINT("ScsiPortStartPacket() called\n");
+
+ DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context;
+
+ IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
+ Srb = IrpStack->Parameters.Scsi.Srb;
+
+ /* Allocte SRB extension */
+ if (DeviceExtension->SrbExtensionSize != 0)
+ {
+ Srb->SrbExtension = DeviceExtension->VirtualAddress;
+ }
+
+ return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
+ Srb));
+}
+
+
+static PSCSI_PORT_LUN_EXTENSION
+SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun)
+{
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ ULONG LunExtensionSize;
+
+ 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)
+ {
+ return NULL;
+ }
+
+ RtlZeroMemory(LunExtension,
+ LunExtensionSize);
+
+ InsertTailList(&DeviceExtension->LunExtensionListHead,
+ &LunExtension->List);
+
+ LunExtension->PathId = PathId;
+ LunExtension->TargetId = TargetId;
+ LunExtension->Lun = Lun;
+
+ KeInitializeDeviceQueue (&LunExtension->DeviceQueue);
+
+ return LunExtension;
+}
+
+
+static VOID
+SpiRemoveLunExtension (IN PSCSI_PORT_LUN_EXTENSION LunExtension)
+{
+ DPRINT("SpiRemoveLunExtension(%p) called\n",
+ LunExtension);
+
+ if (LunExtension == NULL)
+ return;
+
+ RemoveEntryList (&LunExtension->List);
+
+
+ /* Release LUN extersion data */
+
+
+ ExFreePool (LunExtension);
+
+ return;
+}
+
+
+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;
+ PLIST_ENTRY Entry;
+
+ DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
+ DeviceExtension, PathId, TargetId, Lun);
+
+ if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
+ return NULL;
+
+ Entry = DeviceExtension->LunExtensionListHead.Flink;
+ while (Entry != &DeviceExtension->LunExtensionListHead)
+ {
+ LunExtension = CONTAINING_RECORD(Entry,
+ SCSI_PORT_LUN_EXTENSION,
+ List);
+ if (LunExtension->PathId == PathId &&
+ LunExtension->TargetId == TargetId &&
+ LunExtension->Lun == Lun)
+ {
+ return LunExtension;
+ }
+
+ Entry = Entry->Flink;
+ }
+
+ return NULL;
+}
+
+
+static NTSTATUS
+SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
+ IN OUT PSCSI_REQUEST_BLOCK Srb)
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ PIO_STACK_LOCATION IrpStack;
+ PKEVENT Event;
+ PIRP Irp;
+ NTSTATUS Status;
+
+ DPRINT ("SpiSendInquiry() called\n");
+
+ Event = ExAllocatePool (NonPagedPool,
+ sizeof(KEVENT));
+ if (Event == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ KeInitializeEvent (Event,
+ NotificationEvent,
+ FALSE);
+
+ Irp = IoBuildDeviceIoControlRequest (IOCTL_SCSI_EXECUTE_OUT,
+ DeviceObject,
+ NULL,
+ 0,
+ Srb->DataBuffer,
+ Srb->DataTransferLength,
+ TRUE,
+ Event,
+ &IoStatusBlock);
+ if (Irp == NULL)
+ {
+ DPRINT("IoBuildDeviceIoControlRequest() failed\n");
+ ExFreePool (Event);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Attach Srb to the Irp */
+ IrpStack = IoGetNextIrpStackLocation (Irp);
+ IrpStack->Parameters.Scsi.Srb = Srb;
+ Srb->OriginalRequest = Irp;
+
+ /* Call the driver */
+ Status = IoCallDriver (DeviceObject,
+ Irp);
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject (Event,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = IoStatusBlock.Status;
+ }
+
+ ExFreePool (Event);
+
+ return Status;
+}
+
+
+static VOID
+SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ SCSI_REQUEST_BLOCK Srb;
+ PCDB Cdb;
+ ULONG Bus;
+ ULONG Target;
+ ULONG Lun;
+ NTSTATUS Status;
+
+ DPRINT ("SpiScanAdapter() called\n");
+
+ RtlZeroMemory(&Srb,
+ sizeof(SCSI_REQUEST_BLOCK));
+ Srb.SrbFlags = SRB_FLAGS_DATA_IN;
+ Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
+ Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
+ Srb.DataTransferLength = 255; //256;
+ Srb.CdbLength = 6;
+
+ Cdb = (PCDB) &Srb.Cdb;
+
+ Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
+ Cdb->CDB6INQUIRY.AllocationLength = 255;
+
+ for (Bus = 0; Bus < DeviceExtension->PortConfig->NumberOfBuses; Bus++)
+ {
+ Srb.PathId = Bus;
+
+ for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
+ {
+ Srb.TargetId = Target;
+
+ for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
+ {
+ Srb.Lun = Lun;
+ Srb.SrbStatus = SRB_STATUS_SUCCESS;
+
+ Cdb->CDB6INQUIRY.LogicalUnitNumber = Lun;
+
+ LunExtension = SpiAllocateLunExtension (DeviceExtension,
+ Bus,
+ Target,
+ Lun);
+ if (LunExtension == NULL)
+ {
+ DPRINT("Failed to allocate the LUN extension!\n");
+ ExFreePool(Srb.DataBuffer);
+ return;
+ }
+
+ Status = SpiSendInquiry (DeviceExtension->DeviceObject,
+ &Srb);
+ DPRINT ("Status %lx Srb.SrbStatus %x\n", Status, Srb.SrbStatus);
+
+ if (NT_SUCCESS(Status) &&
+ (Srb.SrbStatus == SRB_STATUS_SUCCESS ||
+ Srb.SrbStatus == SRB_STATUS_DATA_OVERRUN) &&
+ ((PINQUIRYDATA)Srb.DataBuffer)->DeviceTypeQualifier == 0)
+ {
+ /* Copy inquiry data */
+ RtlCopyMemory (&LunExtension->InquiryData,
+ Srb.DataBuffer,
+ sizeof(INQUIRYDATA));
+ }
+ else
+ {
+ SpiRemoveLunExtension (LunExtension);
+ }
+ }
+ }
+ }
+
+ ExFreePool(Srb.DataBuffer);
+
+ DPRINT ("SpiScanAdapter() done\n");
+}
+
+
+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;
+
+ DPRINT("SpiGetInquiryData() called\n");
+
+ /* Copy inquiry data to the port device extension */
+ AdapterBusInfo->NumberOfBuses = DeviceExtension->PortConfig->NumberOfBuses;
+
+ UnitInfo = (PSCSI_INQUIRY_DATA)
+ ((PUCHAR)AdapterBusInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
+ (sizeof(SCSI_BUS_DATA) * (AdapterBusInfo->NumberOfBuses - 1)));
+
+ for (Bus = 0; Bus < AdapterBusInfo->NumberOfBuses; Bus++)
+ {
+ AdapterBusInfo->BusData[Bus].InitiatorBusId =
+ DeviceExtension->PortConfig->InitiatorBusId[Bus];
+ AdapterBusInfo->BusData[Bus].InquiryDataOffset =
+ (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterBusInfo);
+
+ PrevUnit = NULL;
+ UnitCount = 0;
+
+ 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);
+
+ 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;
+ }
+ }
+
+ DPRINT("Data size: %lu\n", (ULONG)UnitInfo - (ULONG)AdapterBusInfo);
+
+ return (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterBusInfo);
+}
+
+
+static BOOLEAN STDCALL
+ScsiPortIsr(IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ BOOLEAN Result;
+
+ DPRINT("ScsiPortIsr() called!\n");
+
+ DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
+
+ Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
+ if (Result == FALSE)
+ {
+ return(FALSE);
+ }
+
+ if (DeviceExtension->IrpFlags)
+ {
+ IoRequestDpc(DeviceExtension->DeviceObject,
+ DeviceExtension->CurrentIrp,
+ DeviceExtension);
+ }
+
+ return(TRUE);
+}
+
+
+// ScsiPortDpcForIsr
+// DESCRIPTION:
+//
+// RUN LEVEL:
+//
+// ARGUMENTS:
+// IN PKDPC Dpc
+// IN PDEVICE_OBJECT DpcDeviceObject
+// IN PIRP DpcIrp
+// IN PVOID DpcContext
+//
+static VOID STDCALL
+ScsiPortDpcForIsr(IN PKDPC Dpc,
+ IN PDEVICE_OBJECT DpcDeviceObject,
+ IN PIRP DpcIrp,
+ IN PVOID DpcContext)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PIO_STACK_LOCATION IrpStack;
+ PSCSI_REQUEST_BLOCK Srb;
+
+ DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
+ Dpc, DpcDeviceObject, DpcIrp, DpcContext);
+
+ DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
+
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->IrpLock);
+ if (DeviceExtension->IrpFlags)
+ {
+ IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
+ Srb = IrpStack->Parameters.Scsi.Srb;
+
+ if (DeviceExtension->OriginalSrb != NULL)
+ {
+ DPRINT("Got sense data!\n");
+
+ DPRINT("Valid: %x\n", DeviceExtension->InternalSenseData.Valid);
+ DPRINT("ErrorCode: %x\n", DeviceExtension->InternalSenseData.ErrorCode);
+ DPRINT("SenseKey: %x\n", DeviceExtension->InternalSenseData.SenseKey);
+ DPRINT("SenseCode: %x\n", DeviceExtension->InternalSenseData.AdditionalSenseCode);
+
+ /* Copy sense data */
+ if (DeviceExtension->OriginalSrb->SenseInfoBufferLength != 0)
+ {
+ RtlCopyMemory(DeviceExtension->OriginalSrb->SenseInfoBuffer,
+ &DeviceExtension->InternalSenseData,
+ sizeof(SENSE_DATA));
+ DeviceExtension->OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+ }
+
+ /* Clear current sense data */
+ RtlZeroMemory(&DeviceExtension->InternalSenseData, sizeof(SENSE_DATA));
+
+ IrpStack->Parameters.Scsi.Srb = DeviceExtension->OriginalSrb;
+ ScsiPortFreeSenseRequestSrb (DeviceExtension);
+ }
+ else if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) &&
+ (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION))
+ {
+ DPRINT("SCSIOP_REQUEST_SENSE required!\n");
+
+ DeviceExtension->OriginalSrb = Srb;
+ IrpStack->Parameters.Scsi.Srb = ScsiPortInitSenseRequestSrb(DeviceExtension,
+ Srb);
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
+ if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
+ ScsiPortStartPacket,
+ DeviceExtension))
+ {
+ DPRINT1("Synchronization failed!\n");
+
+ DpcIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ DpcIrp->IoStatus.Information = 0;
+ IoCompleteRequest(DpcIrp,
+ IO_NO_INCREMENT);
+ IoStartNextPacket(DpcDeviceObject,
+ FALSE);
+ }
+
+ return;
+ }
+
+ DeviceExtension->CurrentIrp = NULL;
+
+// DpcIrp->IoStatus.Information = 0;
+// DpcIrp->IoStatus.Status = STATUS_SUCCESS;
+
+ if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
+ {
+ DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
+ IoCompleteRequest(DpcIrp, IO_NO_INCREMENT);
+ }
+
+ if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
+ {
+ DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
+ IoStartNextPacket(DpcDeviceObject, FALSE);
+ }
+ else
+ {
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
+ }
+ }
+ else
+ {
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
+ }
+
+ DPRINT("ScsiPortDpcForIsr() done\n");
+}
+
+
+// ScsiPortIoTimer
+// DESCRIPTION:
+// This function handles timeouts and other time delayed processing
+//
+// RUN LEVEL:
+//
+// ARGUMENTS:
+// IN PDEVICE_OBJECT DeviceObject Device object registered with timer
+// IN PVOID Context the Controller extension for the
+// controller the device is on
+//
+static VOID STDCALL
+ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
+ PVOID Context)
+{
+ DPRINT1("ScsiPortIoTimer()\n");
+}
+
+
+static PSCSI_REQUEST_BLOCK
+ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ PSCSI_REQUEST_BLOCK OriginalSrb)
+{
+ PSCSI_REQUEST_BLOCK Srb;
+ PCDB Cdb;
+
+ Srb = &DeviceExtension->InternalSrb;
+
+ RtlZeroMemory(Srb,
+ sizeof(SCSI_REQUEST_BLOCK));
+
+ 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->TimeOutValue = 4;
+
+ Srb->CdbLength = 6;
+ Srb->DataBuffer = &DeviceExtension->InternalSenseData;
+ Srb->DataTransferLength = sizeof(SENSE_DATA);
+
+ Cdb = (PCDB)Srb->Cdb;
+ Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
+ Cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
+
+ return(Srb);
+}
+
+
+static VOID
+ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+ DeviceExtension->OriginalSrb = NULL;
+}
+
+
+/**********************************************************************
+ * NAME INTERNAL
+ * SpiBuildDeviceMap
+ *
+ * DESCRIPTION
+ * Builds the registry device map of all device which are attached
+ * to the given SCSI HBA port. The device map is located at:
+ * \Registry\Machine\DeviceMap\Scsi
+ *
+ * RUN LEVEL
+ * PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ * DeviceExtension
+ * ...
+ *
+ * RegistryPath
+ * Name of registry driver service key.
+ *
+ * RETURNS
+ * NTSTATUS
+ */
+
+static NTSTATUS
+SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ PUNICODE_STRING RegistryPath)
+{
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING KeyName;
+ UNICODE_STRING ValueName;
+ WCHAR NameBuffer[64];
+ ULONG Disposition;
+ HANDLE ScsiKey;
+ HANDLE ScsiPortKey = NULL;
+ HANDLE ScsiBusKey = NULL;
+ HANDLE ScsiInitiatorKey = NULL;
+ HANDLE ScsiTargetKey = NULL;
+ HANDLE ScsiLunKey = NULL;
+ ULONG BusNumber;
+ ULONG Target;
+ ULONG CurrentTarget;
+ ULONG Lun;
+ PWCHAR DriverName;
+ ULONG UlongData;
+ PWCHAR TypeName;
+ NTSTATUS Status;
+
+ DPRINT("SpiBuildDeviceMap() called\n");
+
+ if (DeviceExtension == NULL || RegistryPath == NULL)
+ {
+ DPRINT1("Invalid parameter\n");
+ return(STATUS_INVALID_PARAMETER);
+ }
+
+ /* Open or create the 'Scsi' subkey */
+ RtlRosInitUnicodeStringFromLiteral(&KeyName,
+ L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
+ 0,
+ NULL);
+ Status = ZwCreateKey(&ScsiKey,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ &Disposition);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+ return(Status);
+ }
+
+ /* Create new 'Scsi Port X' subkey */
+ DPRINT("Scsi Port %lu\n",
+ DeviceExtension->PortNumber);
+
+ swprintf(NameBuffer,
+ L"Scsi Port %lu",
+ DeviceExtension->PortNumber);
+ RtlInitUnicodeString(&KeyName,
+ NameBuffer);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ 0,
+ ScsiKey,
+ NULL);
+ Status = ZwCreateKey(&ScsiPortKey,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ &Disposition);
+ ZwClose(ScsiKey);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+ return(Status);
+ }
+
+ /*
+ * Create port-specific values
+ */
+
+ /* Set 'DMA Enabled' (REG_DWORD) value */
+ UlongData = (ULONG)!DeviceExtension->PortCapabilities->AdapterUsesPio;
+ DPRINT(" DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE");
+ RtlInitUnicodeString(&ValueName,
+ L"DMA Enabled");
+ Status = ZwSetValueKey(ScsiPortKey,
+ &ValueName,
+ 0,
+ REG_DWORD,
+ &UlongData,
+ sizeof(ULONG));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
+ ZwClose(ScsiPortKey);
+ return(Status);
+ }
+
+ /* Set 'Driver' (REG_SZ) value */
+ DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
+ RtlInitUnicodeString(&ValueName,
+ L"Driver");
+ Status = ZwSetValueKey(ScsiPortKey,
+ &ValueName,
+ 0,
+ REG_SZ,
+ DriverName,
+ (wcslen(DriverName) + 1) * sizeof(WCHAR));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
+ ZwClose(ScsiPortKey);
+ return(Status);
+ }
+
+ /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
+ UlongData = (ULONG)DeviceExtension->PortConfig->BusInterruptLevel;
+ DPRINT(" Interrupt = %lu\n", UlongData);
+ RtlInitUnicodeString(&ValueName,
+ L"Interrupt");
+ Status = ZwSetValueKey(ScsiPortKey,
+ &ValueName,
+ 0,
+ REG_DWORD,
+ &UlongData,
+ sizeof(ULONG));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
+ ZwClose(ScsiPortKey);
+ return(Status);
+ }
+
+ /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
+ UlongData = ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig->AccessRanges[0].RangeStart);
+ DPRINT(" IOAddress = %lx\n", UlongData);
+ RtlInitUnicodeString(&ValueName,
+ L"IOAddress");
+ Status = ZwSetValueKey(ScsiPortKey,
+ &ValueName,
+ 0,
+ REG_DWORD,
+ &UlongData,
+ sizeof(ULONG));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
+ ZwClose(ScsiPortKey);
+ return(Status);
+ }
+
+ /* Enumerate buses */
+ for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig->NumberOfBuses; BusNumber++)
+ {
+ /* Create 'Scsi Bus X' key */
+ DPRINT(" Scsi Bus %lu\n", BusNumber);
+ swprintf(NameBuffer,
+ L"Scsi Bus %lu",
+ BusNumber);
+ RtlInitUnicodeString(&KeyName,
+ NameBuffer);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ 0,
+ ScsiPortKey,
+ NULL);
+ Status = ZwCreateKey(&ScsiBusKey,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ &Disposition);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+ goto ByeBye;
+ }
+
+ /* Create 'Initiator Id X' key */
+ DPRINT(" Initiator Id %u\n",
+ DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
+ swprintf(NameBuffer,
+ L"Initiator Id %u",
+ (unsigned int)(UCHAR)DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
+ RtlInitUnicodeString(&KeyName,
+ NameBuffer);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ 0,
+ ScsiBusKey,
+ NULL);
+ Status = ZwCreateKey(&ScsiInitiatorKey,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ &Disposition);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+ goto ByeBye;
+ }
+
+ /* FIXME: Are there any initiator values (??) */
+
+ ZwClose(ScsiInitiatorKey);
+ ScsiInitiatorKey = NULL;
+
+
+ /* Enumerate targets */
+ CurrentTarget = (ULONG)-1;
+ ScsiTargetKey = NULL;
+ for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
+ {
+ for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
+ {
+ LunExtension = SpiGetLunExtension(DeviceExtension,
+ BusNumber,
+ Target,
+ Lun);
+ if (LunExtension != NULL)
+ {
+ if (Target != CurrentTarget)
+ {
+ /* Close old target key */
+ if (ScsiTargetKey != NULL)
+ {
+ ZwClose(ScsiTargetKey);
+ ScsiTargetKey = NULL;
+ }
+
+ /* Create 'Target Id X' key */
+ DPRINT(" Target Id %lu\n", Target);
+ swprintf(NameBuffer,
+ L"Target Id %lu",
+ Target);
+ RtlInitUnicodeString(&KeyName,
+ NameBuffer);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ 0,
+ ScsiBusKey,
+ NULL);
+ Status = ZwCreateKey(&ScsiTargetKey,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ &Disposition);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+ goto ByeBye;
+ }
+
+ CurrentTarget = Target;
+ }
+
+ /* Create 'Logical Unit Id X' key */
+ DPRINT(" Logical Unit Id %lu\n", Lun);
+ swprintf(NameBuffer,
+ L"Logical Unit Id %lu",
+ Lun);
+ RtlInitUnicodeString(&KeyName,
+ NameBuffer);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ 0,
+ ScsiTargetKey,
+ NULL);
+ Status = ZwCreateKey(&ScsiLunKey,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ &Disposition);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+ goto ByeBye;
+ }
+
+ /* Set 'Identifier' (REG_SZ) value */
+ swprintf(NameBuffer,
+ L"%.8S%.16S%.4S",
+ LunExtension->InquiryData.VendorId,
+ LunExtension->InquiryData.ProductId,
+ LunExtension->InquiryData.ProductRevisionLevel);
+ DPRINT(" Identifier = '%S'\n", NameBuffer);
+ RtlInitUnicodeString(&ValueName,
+ L"Identifier");
+ Status = ZwSetValueKey(ScsiLunKey,
+ &ValueName,
+ 0,
+ REG_SZ,
+ NameBuffer,
+ (wcslen(NameBuffer) + 1) * sizeof(WCHAR));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
+ goto ByeBye;
+ }
+
+ /* Set 'Type' (REG_SZ) value */
+ switch (LunExtension->InquiryData.DeviceType)
+ {
+ case 0:
+ TypeName = L"DiskPeripheral";
+ break;
+ case 1:
+ TypeName = L"TapePeripheral";
+ break;
+ case 2:
+ TypeName = L"PrinterPeripheral";
+ break;
+ case 4:
+ TypeName = L"WormPeripheral";
+ break;
+ case 5:
+ TypeName = L"CdRomPeripheral";
+ break;
+ case 6:
+ TypeName = L"ScannerPeripheral";
+ break;
+ case 7:
+ TypeName = L"OpticalDiskPeripheral";
+ break;
+ case 8:
+ TypeName = L"MediumChangerPeripheral";
+ break;
+ case 9:
+ TypeName = L"CommunicationPeripheral";
+ break;
+ default:
+ TypeName = L"OtherPeripheral";
+ break;
+ }
+ DPRINT(" Type = '%S'\n", TypeName);
+ RtlInitUnicodeString(&ValueName,
+ L"Type");
+ Status = ZwSetValueKey(ScsiLunKey,
+ &ValueName,
+ 0,
+ REG_SZ,
+ TypeName,
+ (wcslen(TypeName) + 1) * sizeof(WCHAR));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
+ goto ByeBye;
+ }
+
+ ZwClose(ScsiLunKey);
+ ScsiLunKey = NULL;
+ }
+ }
+
+ /* Close old target key */
+ if (ScsiTargetKey != NULL)
+ {
+ ZwClose(ScsiTargetKey);
+ ScsiTargetKey = NULL;
+ }
+ }
+
+ ZwClose(ScsiBusKey);
+ ScsiBusKey = NULL;
+ }
+
+ByeBye:
+ if (ScsiLunKey != NULL)
+ ZwClose (ScsiLunKey);
+
+ if (ScsiInitiatorKey != NULL)
+ ZwClose (ScsiInitiatorKey);
+
+ if (ScsiTargetKey != NULL)
+ ZwClose (ScsiTargetKey);
+
+ if (ScsiBusKey != NULL)
+ ZwClose (ScsiBusKey);
+
+ if (ScsiPortKey != NULL)
+ ZwClose (ScsiPortKey);
+
+ DPRINT("SpiBuildDeviceMap() done\n");
+
+ return Status;
+}
+
+/* EOF */