Branch scsiport from the "before hbirr rewrite" state (rev. 8950).
authorAleksey Bragin <aleksey@reactos.org>
Tue, 27 Mar 2007 10:07:57 +0000 (10:07 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Tue, 27 Mar 2007 10:07:57 +0000 (10:07 +0000)
svn path=/trunk/; revision=26185

reactos/drivers/storage/scsiport-new/.cvsignore [new file with mode: 0644]
reactos/drivers/storage/scsiport-new/makefile [new file with mode: 0644]
reactos/drivers/storage/scsiport-new/scsiport.c [new file with mode: 0644]
reactos/drivers/storage/scsiport-new/scsiport.def [new file with mode: 0644]
reactos/drivers/storage/scsiport-new/scsiport.edf [new file with mode: 0644]
reactos/drivers/storage/scsiport-new/scsiport.rc [new file with mode: 0644]
reactos/drivers/storage/scsiport-new/scsiport_int.h [new file with mode: 0644]

diff --git a/reactos/drivers/storage/scsiport-new/.cvsignore b/reactos/drivers/storage/scsiport-new/.cvsignore
new file mode 100644 (file)
index 0000000..f95558e
--- /dev/null
@@ -0,0 +1,8 @@
+base.tmp
+junk.tmp
+temp.exp
+scsiport.coff
+*.o
+*.sym
+*.sys
+*.map
diff --git a/reactos/drivers/storage/scsiport-new/makefile b/reactos/drivers/storage/scsiport-new/makefile
new file mode 100644 (file)
index 0000000..ef51fa0
--- /dev/null
@@ -0,0 +1,17 @@
+# $Id: makefile,v 1.6 2003/11/13 14:20:03 ekohl Exp $
+
+PATH_TO_TOP = ../../..
+
+TARGET_BOOTSTRAP = yes
+
+TARGET_TYPE = export_driver
+
+TARGET_NAME = scsiport
+
+TARGET_OBJECTS = $(TARGET_NAME).o
+
+TARGET_CFLAGS = -Werror -Wall
+
+include $(PATH_TO_TOP)/rules.mak
+
+include $(TOOLS_PATH)/helper.mk
diff --git a/reactos/drivers/storage/scsiport-new/scsiport.c b/reactos/drivers/storage/scsiport-new/scsiport.c
new file mode 100644 (file)
index 0000000..5f748ea
--- /dev/null
@@ -0,0 +1,2669 @@
+/*
+ *  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 */
diff --git a/reactos/drivers/storage/scsiport-new/scsiport.def b/reactos/drivers/storage/scsiport-new/scsiport.def
new file mode 100644 (file)
index 0000000..47708a8
--- /dev/null
@@ -0,0 +1,52 @@
+; $Id: scsiport.def,v 1.2 2001/07/23 06:13:48 ekohl Exp $
+;
+; scsiport.def - export definition file for scsiport driver
+;
+LIBRARY SCSIPORT.SYS
+EXPORTS
+ScsiDebugPrint
+ScsiPortCompleteRequest@20
+ScsiPortConvertPhysicalAddressToUlong@8
+ScsiPortConvertUlongToPhysicalAddress@4
+ScsiPortFlushDma@4
+ScsiPortFreeDeviceBase@8
+ScsiPortGetBusData@24
+ScsiPortGetDeviceBase@28
+ScsiPortGetLogicalUnit@16
+ScsiPortGetPhysicalAddress@16
+ScsiPortGetSrb@20
+ScsiPortGetUncachedExtension@12
+ScsiPortGetVirtualAddress@12
+ScsiPortInitialize@16
+ScsiPortIoMapTransfer@16
+ScsiPortLogError@28
+ScsiPortMoveMemory@12
+ScsiPortNotification
+ScsiPortReadPortBufferUchar@12
+ScsiPortReadPortBufferUshort@12
+ScsiPortReadPortBufferUlong@12
+ScsiPortReadPortUchar@4
+ScsiPortReadPortUshort@4
+ScsiPortReadPortUlong@4
+ScsiPortReadRegisterBufferUchar@12
+ScsiPortReadRegisterBufferUshort@12
+ScsiPortReadRegisterBufferUlong@12
+ScsiPortReadRegisterUchar@4
+ScsiPortReadRegisterUshort@4
+ScsiPortReadRegisterUlong@4
+ScsiPortSetBusDataByOffset@28
+ScsiPortStallExecution@4
+ScsiPortValidateRange@28
+ScsiPortWritePortBufferUchar@12
+ScsiPortWritePortBufferUshort@12
+ScsiPortWritePortBufferUlong@12
+ScsiPortWritePortUchar@8
+ScsiPortWritePortUshort@8
+ScsiPortWritePortUlong@8
+ScsiPortWriteRegisterBufferUchar@12
+ScsiPortWriteRegisterBufferUshort@12
+ScsiPortWriteRegisterBufferUlong@12
+ScsiPortWriteRegisterUchar@8
+ScsiPortWriteRegisterUshort@8
+ScsiPortWriteRegisterUlong@8
+;EOF
diff --git a/reactos/drivers/storage/scsiport-new/scsiport.edf b/reactos/drivers/storage/scsiport-new/scsiport.edf
new file mode 100644 (file)
index 0000000..8c2545b
--- /dev/null
@@ -0,0 +1,52 @@
+; $Id: scsiport.edf,v 1.5 2002/06/26 18:39:50 hbirr Exp $
+;
+; scsiport.def - export definition file for scsiport driver
+;
+LIBRARY SCSIPORT.SYS
+EXPORTS
+ScsiDebugPrint
+ScsiPortCompleteRequest=ScsiPortCompleteRequest@20
+ScsiPortConvertPhysicalAddressToUlong=ScsiPortConvertPhysicalAddressToUlong@8
+ScsiPortConvertUlongToPhysicalAddress=NTOSKRNL.RtlConvertUlongToLargeInteger
+ScsiPortFlushDma=ScsiPortFlushDma@4
+ScsiPortFreeDeviceBase=ScsiPortFreeDeviceBase@8
+ScsiPortGetBusData=ScsiPortGetBusData@24
+ScsiPortGetDeviceBase=ScsiPortGetDeviceBase@28
+ScsiPortGetLogicalUnit=ScsiPortGetLogicalUnit@16
+ScsiPortGetPhysicalAddress=ScsiPortGetPhysicalAddress@16
+ScsiPortGetSrb=ScsiPortGetSrb@20
+ScsiPortGetUncachedExtension=ScsiPortGetUncachedExtension@12
+ScsiPortGetVirtualAddress=ScsiPortGetVirtualAddress@12
+ScsiPortInitialize=ScsiPortInitialize@16
+ScsiPortIoMapTransfer=ScsiPortIoMapTransfer@16
+ScsiPortLogError=ScsiPortLogError@28
+ScsiPortMoveMemory=ScsiPortMoveMemory@12
+ScsiPortNotification
+ScsiPortReadPortBufferUchar=HAL.READ_PORT_BUFFER_UCHAR
+ScsiPortReadPortBufferUshort=HAL.READ_PORT_BUFFER_USHORT
+ScsiPortReadPortBufferUlong=HAL.READ_PORT_BUFFER_ULONG
+ScsiPortReadPortUchar=HAL.READ_PORT_UCHAR
+ScsiPortReadPortUshort=HAL.READ_PORT_USHORT
+ScsiPortReadPortUlong=HAL.READ_PORT_ULONG
+ScsiPortReadRegisterBufferUchar=NTOSKRNL.READ_REGISTER_BUFFER_UCHAR
+ScsiPortReadRegisterBufferUshort=NTOSKRNL.READ_REGISTER_BUFFER_USHORT
+ScsiPortReadRegisterBufferUlong=NTOSKRNL.READ_REGISTER_BUFFER_ULONG
+ScsiPortReadRegisterUchar=NTOSKRNL.READ_REGISTER_UCHAR
+ScsiPortReadRegisterUshort=NTOSKRNL.READ_REGISTER_USHORT
+ScsiPortReadRegisterUlong=NTOSKRNL.READ_REGISTER_ULONG
+ScsiPortSetBusDataByOffset=ScsiPortSetBusDataByOffset@28
+ScsiPortStallExecution=HAL.KeStallExecutionProcessor
+ScsiPortValidateRange=ScsiPortValidateRange@28
+ScsiPortWritePortUchar=HAL.WRITE_PORT_UCHAR
+ScsiPortWritePortUshort=HAL.WRITE_PORT_USHORT
+ScsiPortWritePortUlong=HAL.WRITE_PORT_ULONG
+ScsiPortWritePortBufferUchar=HAL.WRITE_PORT_BUFFER_UCHAR
+ScsiPortWritePortBufferUshort=HAL.WRITE_PORT_BUFFER_USHORT
+ScsiPortWritePortBufferUlong=HAL.WRITE_PORT_BUFFER_ULONG
+ScsiPortWriteRegisterBufferUchar=NTOSKRNL.WRITE_REGISTER_BUFFER_UCHAR
+ScsiPortWriteRegisterBufferUshort=NTOSKRNL.WRITE_REGISTER_BUFFER_USHORT
+ScsiPortWriteRegisterBufferUlong=NTOSKRNL.WRITE_REGISTER_BUFFER_ULONG
+ScsiPortWriteRegisterUchar=NTOSKRNL.WRITE_REGISTER_UCHAR
+ScsiPortWriteRegisterUshort=NTOSKRNL.WRITE_REGISTER_USHORT
+ScsiPortWriteRegisterUlong=NTOSKRNL.WRITE_REGISTER_ULONG
+;EOF
diff --git a/reactos/drivers/storage/scsiport-new/scsiport.rc b/reactos/drivers/storage/scsiport-new/scsiport.rc
new file mode 100644 (file)
index 0000000..a4939b8
--- /dev/null
@@ -0,0 +1,37 @@
+#include <defines.h>
+#include <reactos/resource.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+       FILEVERSION     RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD
+       PRODUCTVERSION  RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD
+       FILEFLAGSMASK   0x3fL
+#ifdef _DEBUG
+       FILEFLAGS       0x1L
+#else
+       FILEFLAGS       0x0L
+#endif
+       FILEOS          0x40004L
+       FILETYPE        0x2L
+       FILESUBTYPE     0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName",       RES_STR_COMPANY_NAME
+            VALUE "FileDescription",   "SCSI Port Driver\0"
+            VALUE "FileVersion",       "0.0.0\0"
+            VALUE "InternalName",      "scsiport\0"
+            VALUE "LegalCopyright",    RES_STR_LEGAL_COPYRIGHT
+            VALUE "OriginalFilename",  "scsiport.sys\0"
+            VALUE "ProductName",       RES_STR_PRODUCT_NAME
+            VALUE "ProductVersion",    RES_STR_PRODUCT_VERSION
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
diff --git a/reactos/drivers/storage/scsiport-new/scsiport_int.h b/reactos/drivers/storage/scsiport-new/scsiport_int.h
new file mode 100644 (file)
index 0000000..1f0012c
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * SCSI_PORT_TIMER_STATES
+ *
+ * DESCRIPTION
+ *     An enumeration containing the states in the timer DFA
+ */
+typedef enum _SCSI_PORT_TIMER_STATES
+{
+  IDETimerIdle,
+  IDETimerCmdWait,
+  IDETimerResetWaitForBusyNegate,
+  IDETimerResetWaitForDrdyAssert
+} SCSI_PORT_TIMER_STATES;
+
+
+typedef struct _SCSI_PORT_DEVICE_BASE
+{
+  LIST_ENTRY List;
+
+  PVOID MappedAddress;
+  ULONG NumberOfBytes;
+  SCSI_PHYSICAL_ADDRESS IoAddress;
+  ULONG SystemIoBusNumber;
+} SCSI_PORT_DEVICE_BASE, *PSCSI_PORT_DEVICE_BASE;
+
+
+typedef struct _SCSI_PORT_LUN_EXTENSION
+{
+  LIST_ENTRY List;
+
+  UCHAR PathId;
+  UCHAR TargetId;
+  UCHAR Lun;
+
+  BOOLEAN DeviceClaimed;
+  PDEVICE_OBJECT DeviceObject;
+
+  INQUIRYDATA InquiryData;
+
+  KDEVICE_QUEUE DeviceQueue;
+
+  /* More data? */
+
+  UCHAR MiniportLunExtension[1]; /* must be the last entry */
+} SCSI_PORT_LUN_EXTENSION, *PSCSI_PORT_LUN_EXTENSION;
+
+
+/*
+ * SCSI_PORT_DEVICE_EXTENSION
+ *
+ * DESCRIPTION
+ *     First part of the port objects device extension. The second
+ *     part is the miniport-specific device extension.
+ */
+
+typedef struct _SCSI_PORT_DEVICE_EXTENSION
+{
+  ULONG Length;
+  ULONG MiniPortExtensionSize;
+  PPORT_CONFIGURATION_INFORMATION PortConfig;
+  ULONG PortNumber;
+
+  KSPIN_LOCK IrpLock;
+  KSPIN_LOCK SpinLock;
+  PKINTERRUPT Interrupt;
+  PIRP                   CurrentIrp;
+  ULONG IrpFlags;
+
+  SCSI_PORT_TIMER_STATES TimerState;
+  LONG                   TimerCount;
+
+  LIST_ENTRY DeviceBaseListHead;
+
+  ULONG LunExtensionSize;
+  LIST_ENTRY LunExtensionListHead;
+
+  ULONG SrbExtensionSize;
+
+  PIO_SCSI_CAPABILITIES PortCapabilities;
+
+  PDEVICE_OBJECT DeviceObject;
+  PCONTROLLER_OBJECT ControllerObject;
+
+  PHW_STARTIO HwStartIo;
+  PHW_INTERRUPT HwInterrupt;
+
+  PSCSI_REQUEST_BLOCK OriginalSrb;
+  SCSI_REQUEST_BLOCK InternalSrb;
+  SENSE_DATA InternalSenseData;
+
+  /* DMA related stuff */
+  PADAPTER_OBJECT AdapterObject;
+  ULONG MapRegisterCount;
+
+  PHYSICAL_ADDRESS PhysicalAddress;
+  PVOID VirtualAddress;
+  ULONG CommonBufferLength;
+
+  UCHAR MiniPortDeviceExtension[1]; /* must be the last entry */
+} SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION;