Implemented IOCTL_SCSI_MINIPORT.
[reactos.git] / reactos / drivers / storage / scsiport / scsiport.c
index 40d3d42..600b799 100644 (file)
  *  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.21 2002/09/19 16:18:50 ekohl Exp $
+/* $Id$
  *
  * 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)
+ *                  Hartmut Birr
  */
 
 /* INCLUDES *****************************************************************/
 #include <ddk/srb.h>
 #include <ddk/scsi.h>
 #include <ddk/ntddscsi.h>
+#include <ddk/ntddstor.h>
+#include <ddk/ntdddisk.h>
+#include <stdio.h>
 
 #define NDEBUG
 #include <debug.h>
 
-
-#define VERSION "0.0.1"
-
+#include "scsiport_int.h"
 
 /* TYPES *********************************************************************/
 
+#define IRP_FLAG_COMPLETE      0x00000001
+#define IRP_FLAG_NEXT          0x00000002
+#define IRP_FLAG_NEXT_LU       0x00000004
 
-typedef enum _SCSI_PORT_TIMER_STATES
-{
-  IDETimerIdle,
-  IDETimerCmdWait,
-  IDETimerResetWaitForBusyNegate,
-  IDETimerResetWaitForDrdyAssert
-} SCSI_PORT_TIMER_STATES;
-
-
-/*
- * 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;
-  PORT_CONFIGURATION_INFORMATION PortConfig;
-  ULONG PortNumber;
-  
-  KSPIN_LOCK SpinLock;
-  PKINTERRUPT Interrupt;
-  PIRP                   CurrentIrp;
-  ULONG IrpFlags;
-  
-  SCSI_PORT_TIMER_STATES TimerState;
-  LONG                   TimerCount;
-  
-  BOOLEAN Initializing;
-  
-  ULONG PortBusInfoSize;
-  PSCSI_ADAPTER_BUS_INFO PortBusInfo;
-  
-  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;
-  
-  UCHAR MiniPortDeviceExtension[1]; /* must be the last entry */
-} SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION;
-
-
-/*
- * SCSI_PORT_TIMER_STATES
- *
- * DESCRIPTION
- *     An enumeration containing the states in the timer DFA
- */
-
+/* GLOBALS *******************************************************************/
 
+static ULONG InternalDebugLevel = 0;
 
-#define IRP_FLAG_COMPLETE      0x00000001
-#define IRP_FLAG_NEXT          0x00000002
+static VOID
+SpiProcessRequests(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                  PIRP NextIrp);
 
+static VOID
+SpiStartIo(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+          PIRP Irp);
 
-/* 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,
@@ -122,44 +77,71 @@ static NTSTATUS STDCALL
 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
                      IN PIRP Irp);
 
-static VOID STDCALL
-ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
-               IN PIRP Irp);
-
-static IO_ALLOCATION_ACTION STDCALL
-ScsiPortAllocateController(IN PDEVICE_OBJECT DeviceObject,
-                          IN PIRP Irp,
-                          IN PVOID MapRegisterBase,
-                          IN PVOID Context);
-
 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
-ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
-                        IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
-                        IN ULONG PortCount);
+SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
+               IN OUT PSCSI_REQUEST_BLOCK Srb,
+               IN OUT PIO_STATUS_BLOCK IoStatusBlock,
+               IN OUT PKEVENT Event);
 
 static VOID
-ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
+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);
+ScsiPortDpc(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);
+ScsiPortInitSenseRequestSrb(PSCSI_REQUEST_BLOCK OriginalSrb);
+
+static NTSTATUS
+SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                  PUNICODE_STRING RegistryPath);
+
+static VOID
+SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                       PSCSI_REQUEST_BLOCK Srb);
+
+static VOID
+SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                   PSCSI_REQUEST_BLOCK Srb);
+
+
+static NTSTATUS
+SpiScsiMiniport(IN PDEVICE_OBJECT DeviceObject,
+               IN PIRP Irp);
 
 /* FUNCTIONS *****************************************************************/
 
@@ -215,6 +197,8 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
  *
  * RETURN VALUE
  *     None.
+ *
+ * @implemented
  */
 
 VOID
@@ -225,10 +209,8 @@ ScsiDebugPrint(IN ULONG DebugPrintLevel,
   char Buffer[256];
   va_list ap;
 
-#if 0
-  if (DebugPrintLevel > InternalDebugLevel)
+  if (DebugPrintLevel >= InternalDebugLevel)
     return;
-#endif
 
   va_start(ap, DebugMessage);
   vsprintf(Buffer, DebugMessage, ap);
@@ -238,6 +220,9 @@ ScsiDebugPrint(IN ULONG DebugPrintLevel,
 }
 
 
+/*
+ * @unimplemented
+ */
 VOID STDCALL
 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
                        IN UCHAR PathId,
@@ -245,32 +230,118 @@ ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
                        IN UCHAR Lun,
                        IN UCHAR SrbStatus)
 {
-  UNIMPLEMENTED;
+  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+  PSCSI_PORT_LUN_EXTENSION LunExtension;
+  PLIST_ENTRY Entry;
+  PIRP Irp;
+  PSCSI_REQUEST_BLOCK Srb;
+
+  DPRINT("ScsiPortCompleteRequest(HwDeviceExtension %x, PathId %d, TargetId %d, Lun %d, SrbStatus %x)\n",
+         HwDeviceExtension, PathId, TargetId, Lun, SrbStatus);
+
+  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+                                     SCSI_PORT_DEVICE_EXTENSION,
+                                     MiniPortDeviceExtension);
+
+  Entry = DeviceExtension->LunExtensionListHead.Flink;
+  while (Entry != &DeviceExtension->LunExtensionListHead)
+    {
+      LunExtension = CONTAINING_RECORD(Entry,
+                                      SCSI_PORT_LUN_EXTENSION,
+                                      List);
+
+
+
+      if (PathId == (UCHAR)SP_UNTAGGED ||
+         (PathId == LunExtension->PathId && TargetId == (UCHAR)SP_UNTAGGED) ||
+          (PathId == LunExtension->PathId && TargetId == LunExtension->TargetId && Lun == (UCHAR)SP_UNTAGGED) ||
+          (PathId == LunExtension->PathId && TargetId == LunExtension->TargetId && Lun == LunExtension->Lun))
+        {
+         Irp = LunExtension->NextIrp;
+         while (Irp)
+           {
+             Srb = (PSCSI_REQUEST_BLOCK)Irp->Tail.Overlay.DriverContext[3];
+             if (Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)
+               {
+                 Srb->SrbStatus = SrbStatus;
+                 ScsiPortNotification(RequestComplete,
+                                      HwDeviceExtension,
+                                      Srb);
+               }
+              Irp = Irp->Tail.Overlay.DriverContext[1];
+           }
+       }
+      Entry = Entry->Flink;
+    }
 }
 
 
+/*
+ * @implemented
+ */
+#undef ScsiPortConvertPhysicalAddressToUlong
 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)
 {
-  UNIMPLEMENTED;
+  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,
@@ -287,6 +358,9 @@ ScsiPortGetBusData(IN PVOID DeviceExtension,
 }
 
 
+/*
+ * @implemented
+ */
 PVOID STDCALL
 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
                      IN INTERFACE_TYPE BusType,
@@ -295,82 +369,332 @@ ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
                      IN ULONG NumberOfBytes,
                      IN BOOLEAN InIoSpace)
 {
-  ULONG AddressSpace;
+  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
   PHYSICAL_ADDRESS TranslatedAddress;
-  PVOID VirtualAddress;
-  PVOID Buffer;
-  BOOLEAN rc;
+  PSCSI_PORT_DEVICE_BASE DeviceBase;
+  ULONG AddressSpace;
+  PVOID MappedAddress;
 
-  AddressSpace = (ULONG)InIoSpace;
+  DPRINT ("ScsiPortGetDeviceBase() called\n");
 
-  if (!HalTranslateBusAddress(BusType,
-                             SystemIoBusNumber,
-                             IoAddress,
-                             &AddressSpace,
-                             &TranslatedAddress))
+  AddressSpace = (ULONG)InIoSpace;
+  if (HalTranslateBusAddress(BusType,
+                            SystemIoBusNumber,
+                            IoAddress,
+                            &AddressSpace,
+                            &TranslatedAddress) == FALSE)
     return NULL;
 
   /* i/o space */
   if (AddressSpace != 0)
-    return (PVOID)TranslatedAddress.u.LowPart;
+    return((PVOID)TranslatedAddress.u.LowPart);
+
+  MappedAddress = MmMapIoSpace(TranslatedAddress,
+                              NumberOfBytes,
+                              MmNonCached);
+
+  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;
 
-  VirtualAddress = MmMapIoSpace(TranslatedAddress,
-                               NumberOfBytes,
-                               FALSE);
+  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+                                     SCSI_PORT_DEVICE_EXTENSION,
+                                     MiniPortDeviceExtension);
 
-  Buffer = ExAllocatePool(NonPagedPool,0x20);
-  if (Buffer == NULL)
-    return VirtualAddress;
+  InsertHeadList(&DeviceExtension->DeviceBaseListHead,
+                &DeviceBase->List);
 
-  return NULL;  /* ?? */
+  return(MappedAddress);
 }
 
 
+/*
+ * @implemented
+ */
 PVOID STDCALL
 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
                       IN UCHAR PathId,
                       IN UCHAR TargetId,
                       IN UCHAR Lun)
 {
-  UNIMPLEMENTED;
+  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)
 {
-  UNIMPLEMENTED;
+  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);
+
+  if (Length != NULL)
+    {
+      *Length = 0;
+    }
+  if (Srb == NULL)
+    {
+      EndAddress = (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + DeviceExtension->CommonBufferLength);
+      if (VirtualAddress >= DeviceExtension->VirtualAddress && VirtualAddress < EndAddress)
+        {
+         Offset = (ULONG_PTR)VirtualAddress - (ULONG_PTR)DeviceExtension->VirtualAddress;
+         PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset;
+          BufferLength = (ULONG_PTR)EndAddress - (ULONG_PTR)VirtualAddress;
+       }
+      else
+        {
+         /*
+          * The given virtual address is not within the range
+          * of the drivers uncached extension or srb extension.
+          */
+         /*
+          * FIXME:
+          *   Check if the address is a sense info buffer of an active srb.
+          */
+         PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
+         if (PhysicalAddress.QuadPart == 0LL)
+           {
+             CHECKPOINT;
+             return PhysicalAddress;
+           }
+         BufferLength = PAGE_SIZE - PhysicalAddress.u.LowPart % PAGE_SIZE;
+       }
+    }
+  else
+    {
+      EndAddress = (PVOID)((ULONG_PTR)Srb->DataBuffer + Srb->DataTransferLength);
+      if (VirtualAddress == NULL)
+       {
+         VirtualAddress = Srb->DataBuffer;
+       }
+      else if (VirtualAddress < Srb->DataBuffer || VirtualAddress >= EndAddress)
+       {
+         EndAddress = (PVOID)((ULONG_PTR)Srb->SenseInfoBuffer + Srb->SenseInfoBufferLength);
+         if (VirtualAddress < Srb->SenseInfoBuffer || VirtualAddress >= EndAddress)
+           {
+             PhysicalAddress.QuadPart = 0LL;
+             CHECKPOINT;
+             return PhysicalAddress;
+           }
+       }
+
+      PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
+      if (PhysicalAddress.QuadPart == 0LL)
+       {
+         CHECKPOINT;
+         return PhysicalAddress;
+       }
+
+      BufferLength = PAGE_SIZE - (ULONG_PTR)VirtualAddress % PAGE_SIZE;
+      while ((ULONG_PTR)VirtualAddress + BufferLength < (ULONG_PTR)EndAddress)
+       {
+         NextPhysicalAddress = MmGetPhysicalAddress((PVOID)((ULONG_PTR)VirtualAddress + BufferLength));
+         if (PhysicalAddress.QuadPart + BufferLength != NextPhysicalAddress.QuadPart)
+           {
+             break;
+           }
+         BufferLength += PAGE_SIZE;
+       }
+      if ((ULONG_PTR)VirtualAddress + BufferLength >= (ULONG_PTR)EndAddress)
+       {
+         BufferLength = (ULONG)((ULONG_PTR)EndAddress - (ULONG_PTR)VirtualAddress);
+       }
+    }
+  if (Length != NULL)
+    {
+      *Length = BufferLength;
+    }
+  DPRINT("Address %I64x, Length %d\n", PhysicalAddress.QuadPart, BufferLength);
+  return PhysicalAddress;
 }
 
 
+/*
+ * @unimplemented
+ */
 PSCSI_REQUEST_BLOCK STDCALL
-ScsiPortGetSrb(IN PVOID DeviceExtension,
+ScsiPortGetSrb(IN PVOID HwDeviceExtension,
               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)
 {
-  UNIMPLEMENTED;
+  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;
+       }
+    }
+  if (DeviceExtension->SrbExtensionSize > 0)
+    {
+      PVOID Buffer;
+      DeviceExtension->CurrentSrbExtensions = 0;
+      if (DeviceExtension->PortConfig->MultipleRequestPerLu)
+        {
+          DeviceExtension->MaxSrbExtensions = 1024;
+       }
+      else
+        {
+         DeviceExtension->MaxSrbExtensions = 32;
+       }
+      Buffer = ExAllocatePool(NonPagedPool, ROUND_UP(DeviceExtension->MaxSrbExtensions / 8, sizeof(ULONG)));
+      if (Buffer == NULL)
+        {
+          KEBUGCHECK(0);
+          return NULL;
+        }
+      RtlInitializeBitMap(&DeviceExtension->SrbExtensionAllocMap, Buffer, DeviceExtension->MaxSrbExtensions);
+      RtlClearAllBits(&DeviceExtension->SrbExtensionAllocMap);
+    }
+
+  /* Allocate a common DMA buffer */
+  DeviceExtension->CommonBufferLength =
+    NumberOfBytes + PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * DeviceExtension->MaxSrbExtensions);
+  DeviceExtension->VirtualAddress =
+    HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
+                           DeviceExtension->CommonBufferLength,
+                           &DeviceExtension->PhysicalAddress,
+                           FALSE);
+  if (DeviceExtension->VirtualAddress == NULL)
+    {
+      DPRINT1("HalAllocateCommonBuffer() failed!\n");
+      DeviceExtension->CommonBufferLength = 0;
+      return NULL;
+    }
+
+  return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress +
+                 PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * DeviceExtension->MaxSrbExtensions));
 }
 
 
+/*
+ * @implemented
+ */
 PVOID STDCALL
 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
                          IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
 {
-  UNIMPLEMENTED;
+  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);
 }
 
 
@@ -399,6 +723,8 @@ ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
  *
  * RETURN VALUE
  *     Status.
+ *
+ * @implemented
  */
 
 ULONG STDCALL
@@ -408,20 +734,60 @@ ScsiPortInitialize(IN PVOID Argument1,
                   IN PVOID HwContext)
 {
   PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
-  PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
-  PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension;
+//  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;
-  PACCESS_RANGE AccessRanges;
-  ULONG ExtensionSize;
+  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");
 
+  DPRINT ("ScsiPortInitialize() called!\n");
+#if 0
+  DPRINT1("HwInitializationDataSize: %d\n", HwInitializationData->HwInitializationDataSize);
+  DPRINT1("AdapterInterfaceType:     %d\n", HwInitializationData->AdapterInterfaceType);
+  DPRINT1("HwInitialize:             %x\n", HwInitializationData->HwInitialize);
+  DPRINT1("HwStartIo:                %x\n", HwInitializationData->HwStartIo);
+  DPRINT1("HwInterrupt:              %x\n", HwInitializationData->HwInterrupt);
+  DPRINT1("HwFindAdapter:            %x\n", HwInitializationData->HwFindAdapter);
+  DPRINT1("HwResetBus:               %x\n", HwInitializationData->HwResetBus);
+  DPRINT1("HwDmaStarted:             %x\n", HwInitializationData->HwDmaStarted);
+  DPRINT1("HwAdapterState:           %x\n", HwInitializationData->HwAdapterState);
+  DPRINT1("DeviceExtensionSize:      %d\n", HwInitializationData->DeviceExtensionSize);
+  DPRINT1("SpecificLuExtensionSize:  %d\n", HwInitializationData->SpecificLuExtensionSize);
+  DPRINT1("SrbExtensionSize:         %d\n", HwInitializationData->SrbExtensionSize);
+  DPRINT1("NumberOfAccessRanges:     %d\n", HwInitializationData->NumberOfAccessRanges);
+  DPRINT1("Reserved:                 %x\n", HwInitializationData->Reserved);
+  DPRINT1("MapBuffers:               %d\n", HwInitializationData->MapBuffers);
+  DPRINT1("NeedPhysicalAddresses:    %d\n", HwInitializationData->NeedPhysicalAddresses);
+  DPRINT1("TaggedQueueing:           %d\n", HwInitializationData->TaggedQueueing);
+  DPRINT1("AutoRequestSense:         %d\n", HwInitializationData->AutoRequestSense);
+  DPRINT1("MultipleRequestPerLu:     %d\n", HwInitializationData->MultipleRequestPerLu);
+  DPRINT1("ReceiveEvent:             %d\n", HwInitializationData->ReceiveEvent);
+  DPRINT1("VendorIdLength:           %d\n", HwInitializationData->VendorIdLength);
+  DPRINT1("VendorId:                 %x\n", HwInitializationData->VendorId);
+  DPRINT1("ReservedUshort:           %d\n", HwInitializationData->ReservedUshort);
+  DPRINT1("DeviceIdLength:           %d\n", HwInitializationData->DeviceIdLength);
+  DPRINT1("DeviceId:                 %x\n", HwInitializationData->DeviceId);
+#endif
   if ((HwInitializationData->HwInitialize == NULL) ||
       (HwInitializationData->HwStartIo == NULL) ||
       (HwInitializationData->HwInterrupt == NULL) ||
@@ -429,124 +795,429 @@ ScsiPortInitialize(IN PVOID Argument1,
       (HwInitializationData->HwResetBus == NULL))
     return(STATUS_INVALID_PARAMETER);
 
-  DriverObject->DriverStartIo = ScsiPortStartIo;
+  DriverObject->DriverStartIo = NULL;
   DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
   DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
   DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
   DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
 
-
   SystemConfig = IoGetConfigurationInformation();
 
-  ExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
-                 HwInitializationData->DeviceExtensionSize;
-  PseudoDeviceExtension = ExAllocatePool(PagedPool,
-                                        ExtensionSize);
-  RtlZeroMemory(PseudoDeviceExtension,
-               ExtensionSize);
-  PseudoDeviceExtension->Length = ExtensionSize;
-  PseudoDeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
-  PseudoDeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
-  PseudoDeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
-
-  PortConfig = &PseudoDeviceExtension->PortConfig;
-
-  PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
-  PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
-  PortConfig->InterruptMode =
-   (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
-  PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
-  PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
-  PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
-
-  PortConfig->AccessRanges =
-    ExAllocatePool(PagedPool,
-                  sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
+  DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
+    HwInitializationData->DeviceExtensionSize;
+  PortConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION) +
+    HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE);
 
 
-  PortConfig->SystemIoBusNumber = 0;
-  PortConfig->SlotNumber = 0;
-
-  MaxBus = (PortConfig->AdapterInterfaceType == PCIBus) ? 8 : 1;
-
+  MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
   DPRINT("MaxBus: %lu\n", MaxBus);
 
+  PortDeviceObject = NULL;
+  BusNumber = 0;
+  SlotNumber.u.AsULONG = 0;
   while (TRUE)
     {
-      DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
-
-//      RtlZeroMemory(AccessRanges,
-//                 sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
+      /* 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;
+       }
 
-      RtlZeroMemory(PseudoDeviceExtension->MiniPortDeviceExtension,
-                   PseudoDeviceExtension->MiniPortExtensionSize);
+      DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
+
+      /* Increase the stacksize. We reenter our device on IOCTL_SCSI_MINIPORT */
+      PortDeviceObject->StackSize++;
+
+      /* Set the buffering strategy here... */
+      PortDeviceObject->Flags |= DO_DIRECT_IO;
+      PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
+
+      DeviceExtension = PortDeviceObject->DeviceExtension;
+      RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
+      DeviceExtension->Length = DeviceExtensionSize;
+      DeviceExtension->DeviceObject = PortDeviceObject;
+      DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
+
+      DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
+      DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
+      DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
+      DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
+      DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
+
+      DeviceExtension->AdapterObject = NULL;
+      DeviceExtension->MapRegisterCount = 0;
+      DeviceExtension->PhysicalAddress.QuadPart = 0ULL;
+      DeviceExtension->VirtualAddress = NULL;
+      DeviceExtension->CommonBufferLength = 0;
+
+      /* Initialize the device base list */
+      InitializeListHead (&DeviceExtension->DeviceBaseListHead);
+
+      /* Initialize the irp lists */
+      InitializeListHead (&DeviceExtension->PendingIrpListHead);
+      DeviceExtension->NextIrp = NULL;
+      DeviceExtension->PendingIrpCount = 0;
+      DeviceExtension->ActiveIrpCount = 0;
+
+      /* Initialize LUN-Extension list */
+      InitializeListHead (&DeviceExtension->LunExtensionListHead);
+
+      /* Initialize the spin lock in the controller extension */
+      KeInitializeSpinLock (&DeviceExtension->Lock);
+
+      /* Initialize the DPC object */
+      IoInitializeDpcRequest (PortDeviceObject,
+                             ScsiPortDpc);
+
+      /* Initialize the device timer */
+      DeviceExtension->TimerState = IDETimerIdle;
+      DeviceExtension->TimerCount = 0;
+      IoInitializeTimer (PortDeviceObject,
+                        ScsiPortIoTimer,
+                        DeviceExtension);
+
+      /* Allocate and initialize port configuration info */
+      DeviceExtension->PortConfig = ExAllocatePool (NonPagedPool,
+                                                   PortConfigSize);
+      if (DeviceExtension->PortConfig == NULL)
+       {
+         Status = STATUS_INSUFFICIENT_RESOURCES;
+         goto ByeBye;
+       }
+      RtlZeroMemory (DeviceExtension->PortConfig,
+                    PortConfigSize);
+
+      PortConfig = DeviceExtension->PortConfig;
+      PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
+      PortConfig->SystemIoBusNumber = BusNumber;
+      PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
+      PortConfig->InterruptMode =
+       (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
+      PortConfig->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
+      PortConfig->NumberOfPhysicalBreaks = SP_UNINITIALIZED_VALUE;
+      PortConfig->DmaChannel = SP_UNINITIALIZED_VALUE;
+      PortConfig->DmaPort = SP_UNINITIALIZED_VALUE;
+      PortConfig->DmaWidth = 0;
+      PortConfig->DmaSpeed = Compatible;
+      PortConfig->AlignmentMask = 0;
+      PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
+      PortConfig->NumberOfBuses = 0;
+
+      for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
+       PortConfig->InitiatorBusId[i] = 255;
+
+      PortConfig->ScatterGather = FALSE;
+      PortConfig->Master = FALSE;
+      PortConfig->CachesData = FALSE;
+      PortConfig->AdapterScansDown = FALSE;
+      PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
+      PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
+      PortConfig->Dma32BitAddresses = FALSE;
+      PortConfig->DemandMode = FALSE;
+      PortConfig->MapBuffers = HwInitializationData->MapBuffers;
+      PortConfig->NeedPhysicalAddresses = HwInitializationData->NeedPhysicalAddresses;
+      PortConfig->TaggedQueuing = HwInitializationData->TaggedQueuing;
+      PortConfig->AutoRequestSense = HwInitializationData->AutoRequestSense;
+      PortConfig->MultipleRequestPerLu = HwInitializationData->MultipleRequestPerLu;
+      PortConfig->ReceiveEvent = HwInitializationData->ReceiveEvent;
+      PortConfig->RealModeInitialized = FALSE;
+      PortConfig->BufferAccessScsiPortControlled = FALSE;
+      PortConfig->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS;
+//      PortConfig->MaximumNumberOfLogicalUnits = SCSI_MAXIMUM_LOGICAL_UNITS;
+
+      PortConfig->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
+      PortConfig->SpecificLuExtensionSize = HwInitializationData->SpecificLuExtensionSize;
+
+      PortConfig->AccessRanges = (ACCESS_RANGE(*)[])(PortConfig + 1);
+
+      /* 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 */
-      Result = (HwInitializationData->HwFindAdapter)(&PseudoDeviceExtension->MiniPortDeviceExtension,
+      Again = FALSE;
+      DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
+      Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension,
                                                     HwContext,
-                                                    NULL,      /* BusInformation */
-                                                    NULL,      /* ArgumentString */
-                                                    &PseudoDeviceExtension->PortConfig,
+                                                    0,  /* BusInformation */
+                                                    "", /* ArgumentString */
+                                                    PortConfig,
                                                     &Again);
-      DPRINT("HwFindAdapter() result: %lu\n", Result);
+      DPRINT("HwFindAdapter() Result: %lu  Again: %s\n",
+            Result, (Again) ? "True" : "False");
 
       if (Result == SP_RETURN_FOUND)
        {
-         DPRINT("ScsiPortInitialize(): Found HBA!\n");
+         DPRINT("ScsiPortInitialize(): Found HBA! (%x)\n", PortConfig->BusInterruptVector);
 
-         Status = ScsiPortCreatePortDevice(DriverObject,
-                                           PseudoDeviceExtension,
-                                           SystemConfig->ScsiPortCount);
+#if 0
+         DPRINT1("SystemIoBusNumber:               %x\n", PortConfig->SystemIoBusNumber);
+         DPRINT1("AdapterInterfaceType:            %x\n", PortConfig->AdapterInterfaceType);
+         DPRINT1("BusInterruptLevel:               %x\n", PortConfig->BusInterruptLevel);
+         DPRINT1("BusInterruptVector:              %x\n", PortConfig->BusInterruptVector);
+         DPRINT1("InterruptMode:                   %x\n", PortConfig->InterruptMode);
+         DPRINT1("MaximumTransferLength:           %x\n", PortConfig->MaximumTransferLength);
+         DPRINT1("NumberOfPhysicalBreaks:          %x\n", PortConfig->NumberOfPhysicalBreaks);
+         DPRINT1("DmaChannel:                      %x\n", PortConfig->DmaChannel);
+         DPRINT1("DmaPort:                         %d\n", PortConfig->DmaPort);
+         DPRINT1("DmaWidth:                        %d\n", PortConfig->DmaWidth);
+         DPRINT1("DmaSpeed:                        %d\n", PortConfig->DmaSpeed);
+         DPRINT1("AlignmentMask:                   %d\n", PortConfig->AlignmentMask);
+         DPRINT1("NumberOfAccessRanges:            %d\n", PortConfig->NumberOfAccessRanges);
+         DPRINT1("NumberOfBuses:                   %d\n", PortConfig->NumberOfBuses);
+         DPRINT1("ScatterGather:                   %d\n", PortConfig->ScatterGather);
+         DPRINT1("Master:                          %d\n", PortConfig->Master);
+         DPRINT1("CachesData:                      %d\n", PortConfig->CachesData);
+         DPRINT1("AdapterScansDown:                %d\n", PortConfig->AdapterScansDown);
+         DPRINT1("AtdiskPrimaryClaimed:            %d\n", PortConfig->AtdiskPrimaryClaimed);
+         DPRINT1("AtdiskSecondaryClaimed:          %d\n", PortConfig->AtdiskSecondaryClaimed);
+         DPRINT1("Dma32BitAddresses:               %d\n", PortConfig->Dma32BitAddresses);
+         DPRINT1("DemandMode:                      %d\n", PortConfig->DemandMode);
+         DPRINT1("MapBuffers:                      %d\n", PortConfig->MapBuffers);
+         DPRINT1("NeedPhysicalAddresses:           %d\n", PortConfig->NeedPhysicalAddresses);
+         DPRINT1("TaggedQueuing:                   %d\n", PortConfig->TaggedQueuing);
+         DPRINT1("AutoRequestSense:                %d\n", PortConfig->AutoRequestSense);
+         DPRINT1("MultipleRequestPerLu:            %d\n", PortConfig->MultipleRequestPerLu);
+         DPRINT1("ReceiveEvent:                    %d\n", PortConfig->ReceiveEvent);
+         DPRINT1("RealModeInitialized:             %d\n", PortConfig->RealModeInitialized);
+         DPRINT1("BufferAccessScsiPortControlled:  %d\n", PortConfig->BufferAccessScsiPortControlled);
+         DPRINT1("MaximumNumberOfTargets:          %d\n", PortConfig->MaximumNumberOfTargets);
+         DPRINT1("SlotNumber:                      %d\n", PortConfig->SlotNumber);
+         DPRINT1("BusInterruptLevel2:              %x\n", PortConfig->BusInterruptLevel2);
+         DPRINT1("BusInterruptVector2:             %x\n", PortConfig->BusInterruptVector2);
+         DPRINT1("InterruptMode2:                  %x\n", PortConfig->InterruptMode2);
+         DPRINT1("DmaChannel2:                     %d\n", PortConfig->DmaChannel2);
+         DPRINT1("DmaPort2:                        %d\n", PortConfig->DmaPort2);
+         DPRINT1("DmaWidth2:                       %d\n", PortConfig->DmaWidth2);
+         DPRINT1("DmaSpeed2:                       %d\n", PortConfig->DmaSpeed2);
+         DPRINT1("DeviceExtensionSize:             %d\n", PortConfig->DeviceExtensionSize);
+         DPRINT1("SpecificLuExtensionSize:         %d\n", PortConfig->SpecificLuExtensionSize);
+         DPRINT1("SrbExtensionSize:                %d\n", PortConfig->SrbExtensionSize);
 
-         if (!NT_SUCCESS(Status))
-           {
-             DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status);
+#endif
 
-             ExFreePool(PortConfig->AccessRanges);
-             ExFreePool(PseudoDeviceExtension);
+          if (DeviceExtension->VirtualAddress == NULL && DeviceExtension->SrbExtensionSize)
+           {
+             ScsiPortGetUncachedExtension(&DeviceExtension->MiniPortDeviceExtension,
+                                          PortConfig,
+                                          0);
+           }
 
-             return(Status);
+         /* Register an interrupt handler for this device */
+         MappedIrq = HalGetInterruptVector(PortConfig->AdapterInterfaceType,
+                                           PortConfig->SystemIoBusNumber,
+                                           PortConfig->BusInterruptLevel,
+#if 1
+/*
+ * FIXME:
+ *   Something is wrong in our interrupt conecting code.
+ *   The promise Ultra100TX driver returns 0 for BusInterruptVector
+ *   and a nonzero value for BusInterruptLevel. The driver does only
+ *   work with this fix.
+ */
+                                           PortConfig->BusInterruptLevel,
+#else
+                                           PortConfig->BusInterruptVector,
+#endif
+                                           &Dirql,
+                                           &Affinity);
+         DPRINT("AdapterInterfaceType %x, SystemIoBusNumber %x, BusInterruptLevel %x, BusInterruptVector %x\n",
+                 PortConfig->AdapterInterfaceType, PortConfig->SystemIoBusNumber,
+                 PortConfig->BusInterruptLevel, PortConfig->BusInterruptVector);
+         Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
+                                     ScsiPortIsr,
+                                     DeviceExtension,
+                                     NULL,
+                                     MappedIrq,
+                                     Dirql,
+                                     Dirql,
+                                     PortConfig->InterruptMode,
+                                     TRUE,
+                                     Affinity,
+                                     FALSE);
+         if (!NT_SUCCESS(Status))
+           {
+             DbgPrint("Could not connect interrupt %d\n",
+                      PortConfig->BusInterruptVector);
+             goto ByeBye;
            }
 
-         /* Update the configuration info */
-         SystemConfig->AtDiskPrimaryAddressClaimed = PortConfig->AtdiskPrimaryClaimed;
-         SystemConfig->AtDiskSecondaryAddressClaimed = PortConfig->AtdiskSecondaryClaimed;
+         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);
+          if (PortConfig->ScatterGather == FALSE ||
+             PortConfig->NumberOfPhysicalBreaks >= (0x100000000LL >> PAGE_SHIFT) ||
+             PortConfig->MaximumTransferLength < PortConfig->NumberOfPhysicalBreaks * PAGE_SIZE)
+           {
+             PortCapabilities->MaximumTransferLength =
+               PortConfig->MaximumTransferLength;
+           }
+         else
+           {
+             PortCapabilities->MaximumTransferLength =
+               PortConfig->NumberOfPhysicalBreaks * PAGE_SIZE;
+           }
+
+         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;
        }
-
-      if (Again == FALSE)
+      else
        {
-         PortConfig->SystemIoBusNumber++;
-         PortConfig->SlotNumber = 0;
+         DPRINT("HwFindAdapter() Result: %lu\n", Result);
+
+         ExFreePool (PortConfig);
+         IoDeleteDevice (PortDeviceObject);
+         PortDeviceObject = NULL;
        }
 
-      DPRINT("Bus: %lu  MaxBus: %lu\n", PortConfig->SystemIoBusNumber, MaxBus);
-      if (PortConfig->SystemIoBusNumber >= MaxBus)
+      DPRINT("Bus: %lu  MaxBus: %lu\n", BusNumber, MaxBus);
+      if (BusNumber >= MaxBus)
        {
          DPRINT("Scanned all buses!\n");
-         break;
+         Status = STATUS_SUCCESS;
+         goto ByeBye;
+       }
+
+      if (Again == FALSE)
+       {
+         BusNumber++;
+         SlotNumber.u.AsULONG = 0;
        }
     }
 
-  ExFreePool(PortConfig->AccessRanges);
-  ExFreePool(PseudoDeviceExtension);
+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(STATUS_SUCCESS);
+  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,
@@ -556,10 +1227,24 @@ ScsiPortLogError(IN PVOID HwDeviceExtension,
                 IN ULONG ErrorCode,
                 IN ULONG UniqueId)
 {
-  UNIMPLEMENTED;
+  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+
+  DPRINT1("ScsiPortLogError() called\n");
+  DPRINT1("Srb %x, PathId %d, TargetId %d, Lun %d, ErrorCode %x, UniqueId %x\n",
+          Srb, PathId, TargetId, Lun, ErrorCode, UniqueId);
+
+  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+                                     SCSI_PORT_DEVICE_EXTENSION,
+                                     MiniPortDeviceExtension);
+
+
+  DPRINT("ScsiPortLogError() done\n");
 }
 
 
+/*
+ * @implemented
+ */
 VOID STDCALL
 ScsiPortMoveMemory(OUT PVOID Destination,
                   IN PVOID Source,
@@ -571,12 +1256,16 @@ ScsiPortMoveMemory(OUT PVOID Destination,
 }
 
 
+/*
+ * @implemented
+ */
 VOID
 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
                     IN PVOID HwDeviceExtension,
                     ...)
 {
   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+  va_list ap;
 
   DPRINT("ScsiPortNotification() called\n");
 
@@ -586,29 +1275,80 @@ ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
 
   DPRINT("DeviceExtension %p\n", DeviceExtension);
 
-  DPRINT("Initializing = %s\n", (DeviceExtension->Initializing)?"TRUE":"FALSE");
-
-  if (DeviceExtension->Initializing == TRUE)
-    return;
+  va_start(ap, HwDeviceExtension);
 
   switch (NotificationType)
     {
       case RequestComplete:
-       DPRINT("Notify: RequestComplete\n");
-       DeviceExtension->IrpFlags |= IRP_FLAG_COMPLETE;
+       {
+         PSCSI_REQUEST_BLOCK Srb;
+
+         Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
+
+         DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
+         DeviceExtension->Flags |= IRP_FLAG_COMPLETE;
+         Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
+       }
        break;
 
       case NextRequest:
        DPRINT("Notify: NextRequest\n");
-       DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
+       DeviceExtension->Flags |= IRP_FLAG_NEXT;
+       break;
+
+      case NextLuRequest:
+       {
+         UCHAR PathId;
+         UCHAR TargetId;
+         UCHAR Lun;
+          PSCSI_PORT_LUN_EXTENSION LunExtension;
+
+         PathId = (UCHAR) va_arg (ap, int);
+         TargetId = (UCHAR) va_arg (ap, int);
+         Lun = (UCHAR) va_arg (ap, int);
+
+         DPRINT ("Notify: NextLuRequest(PathId %u  TargetId %u  Lun %u)\n",
+                  PathId, TargetId, Lun);
+
+          LunExtension = SpiGetLunExtension(DeviceExtension,
+                                           PathId,
+                                           TargetId,
+                                           Lun);
+         if (LunExtension)
+           {
+             DeviceExtension->Flags |= IRP_FLAG_NEXT_LU;
+             LunExtension->Flags |= IRP_FLAG_NEXT_LU;
+           }
+       }
+       break;
+
+      case ResetDetected:
+       DPRINT1("Notify: ResetDetected\n");
+       /* FIXME: ??? */
        break;
 
       default:
+       DPRINT1 ("Unsupported notification %lu\n", NotificationType);
        break;
     }
+  if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
+    {
+      IoRequestDpc(DeviceExtension->DeviceObject,
+                   NULL,
+                  DeviceExtension);
+    }
+  else
+    {
+      SpiProcessRequests(DeviceExtension, NULL);
+    }
+
+  va_end(ap);
 }
 
 
+/*
+ * @implemented
+ */
 ULONG STDCALL
 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
                           IN ULONG BusDataType,
@@ -618,6 +1358,7 @@ ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
                           IN ULONG Offset,
                           IN ULONG Length)
 {
+  DPRINT("ScsiPortSetBusDataByOffset()\n");
   return(HalSetBusDataByOffset(BusDataType,
                               SystemIoBusNumber,
                               SlotNumber,
@@ -627,6 +1368,9 @@ ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
 }
 
 
+/*
+ * @implemented
+ */
 BOOLEAN STDCALL
 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
                      IN INTERFACE_TYPE BusType,
@@ -635,12 +1379,161 @@ ScsiPortValidateRange(IN PVOID HwDeviceExtension,
                      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;
+
+              PortConfig->SlotNumber = NextSlotNumber->u.AsULONG;
+
+             NextSlotNumber->u.bits.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
@@ -658,9 +1551,6 @@ ScsiPortValidateRange(IN PVOID HwDeviceExtension,
  *     Irp
  *             Pointer to an IRP.
  *
- *     ...
-               Additional output data (see printf()).
- *
  * RETURN VALUE
  *     Status.
  */
@@ -702,6 +1592,7 @@ 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;
@@ -730,107 +1621,64 @@ ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
   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:
-       IoStartPacket(DeviceObject, Irp, NULL, NULL);
+      case SRB_FUNCTION_IO_CONTROL:
+        IoMarkIrpPending(Irp);
+       Srb->OriginalRequest = LunExtension;
+        Irp->Tail.Overlay.DriverContext[3] = Srb;
+       SpiProcessRequests(DeviceExtension, Irp);
        return(STATUS_PENDING);
 
       case SRB_FUNCTION_SHUTDOWN:
       case SRB_FUNCTION_FLUSH:
-       if (DeviceExtension->PortConfig.CachesData == TRUE)
+       if (DeviceExtension->PortConfig->CachesData == TRUE)
          {
-           IoStartPacket(DeviceObject, Irp, NULL, NULL);
+            IoMarkIrpPending(Irp);
+           Srb->OriginalRequest = LunExtension;
+            Irp->Tail.Overlay.DriverContext[3] = Srb;
+           SpiProcessRequests(DeviceExtension, Irp);
            return(STATUS_PENDING);
          }
        break;
 
       case SRB_FUNCTION_CLAIM_DEVICE:
-       {
-         PSCSI_ADAPTER_BUS_INFO AdapterInfo;
-         PSCSI_INQUIRY_DATA UnitInfo;
-         PINQUIRYDATA InquiryData;
-
-         DPRINT("  SRB_FUNCTION_CLAIM_DEVICE\n");
-         DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
-
-         Srb->DataBuffer = NULL;
-
-         if (DeviceExtension->PortBusInfo != NULL)
-           {
-             AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
-
-             if (AdapterInfo->BusData[Srb->PathId].NumberOfLogicalUnits == 0)
-               break;
-
-             UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
-               AdapterInfo->BusData[Srb->PathId].InquiryDataOffset);
-
-             while (AdapterInfo->BusData[Srb->PathId].InquiryDataOffset)
-               {
-                 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
-
-                 if ((UnitInfo->TargetId == Srb->TargetId) &&
-                     (UnitInfo->Lun == Srb->Lun) &&
-                     (UnitInfo->DeviceClaimed == FALSE))
-                   {
-                     UnitInfo->DeviceClaimed = TRUE;
-                     DPRINT("Claimed device!\n");
-
-                     /* FIXME: Hack!!!!! */
-                     Srb->DataBuffer = DeviceObject;
-
-                     break;
-                   }
+       DPRINT ("  SRB_FUNCTION_CLAIM_DEVICE\n");
 
-                 if (UnitInfo->NextInquiryDataOffset == 0)
-                   break;
-
-                 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo + UnitInfo->NextInquiryDataOffset);
-               }
-           }
-       }
+       /* 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:
-       {
-         PSCSI_ADAPTER_BUS_INFO AdapterInfo;
-         PSCSI_INQUIRY_DATA UnitInfo;
-         PINQUIRYDATA InquiryData;
-
-         DPRINT("  SRB_FUNCTION_RELEASE_DEVICE\n");
-         DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
-
-         if (DeviceExtension->PortBusInfo != NULL)
-           {
-             AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
-
-             if (AdapterInfo->BusData[Srb->PathId].NumberOfLogicalUnits == 0)
-               break;
-
-             UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
-               AdapterInfo->BusData[Srb->PathId].InquiryDataOffset);
-
-             while (AdapterInfo->BusData[Srb->PathId].InquiryDataOffset)
-               {
-                 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
-
-                 if ((UnitInfo->TargetId == Srb->TargetId) &&
-                     (UnitInfo->Lun == Srb->Lun) &&
-                     (UnitInfo->DeviceClaimed == TRUE))
-                   {
-                     UnitInfo->DeviceClaimed = FALSE;
-                     DPRINT("Released device!\n");
-                     break;
-                   }
-
-                 if (UnitInfo->NextInquiryDataOffset == 0)
-                   break;
-
-                 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo + UnitInfo->NextInquiryDataOffset);
-               }
-           }
-       }
+       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:
@@ -871,10 +1719,10 @@ ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
 {
   PIO_STACK_LOCATION Stack;
   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+  NTSTATUS Status = STATUS_SUCCESS;
 
   DPRINT("ScsiPortDeviceControl()\n");
 
-  Irp->IoStatus.Status = STATUS_SUCCESS;
   Irp->IoStatus.Information = 0;
 
 
@@ -883,6 +1731,16 @@ ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
 
   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:
        {
@@ -900,99 +1758,215 @@ ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
          DPRINT("  IOCTL_SCSI_GET_INQUIRY_DATA\n");
 
          /* Copy inquiry data to the port device extension */
-         memcpy(Irp->AssociatedIrp.SystemBuffer,
-                DeviceExtension->PortBusInfo,
-                DeviceExtension->PortBusInfoSize);
-
-         DPRINT("BufferSize: %lu\n", DeviceExtension->PortBusInfoSize);
-         Irp->IoStatus.Information = DeviceExtension->PortBusInfoSize;
+         Irp->IoStatus.Information =
+           SpiGetInquiryData(DeviceExtension,
+                             Irp->AssociatedIrp.SystemBuffer);
+         DPRINT("Inquiry data size: %lu\n", Irp->IoStatus.Information);
        }
        break;
+      
+      case IOCTL_SCSI_PASS_THROUGH:
+        DPRINT("  IOCTL_SCSI_PASS_THROUGH\n");
+        Status = STATUS_NOT_IMPLEMENTED;
+        break;
+
+      case IOCTL_SCSI_PASS_THROUGH_DIRECT:
+        DPRINT("  IOCTL_SCSI_PASS_THROUGH_DIRECT\n");
+        Status = STATUS_NOT_IMPLEMENTED;
+        break;
+
+      case IOCTL_SCSI_MINIPORT:
+        DPRINT1("  IOCTL_SCSI_MINIPORT\n");
+        DPRINT1("  Signature: %.8s\n", ((PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer)->Signature);
+        DPRINT1("  ControlCode: 0x%lX\n", ((PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer)->ControlCode);
+        return SpiScsiMiniport(DeviceObject, Irp);
 
       default:
        DPRINT1("  unknown ioctl code: 0x%lX\n",
               Stack->Parameters.DeviceIoControl.IoControlCode);
+        Status = STATUS_INVALID_DEVICE_REQUEST;
        break;
     }
 
+  Irp->IoStatus.Status = Status;
   IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
-  return(STATUS_SUCCESS);
+  return Status;
 }
 
+static NTSTATUS STDCALL
+SpiCompletion(IN PDEVICE_OBJECT DeviceObject,
+             IN PIRP Irp,
+             IN PVOID Context)
+{
+  PSCSI_REQUEST_BLOCK Srb;
+  
+  DPRINT("SpiCompletion(DeviceObject %x, Irp %x, Context %x)\n",
+         DeviceObject, Irp, Context);
+
+  Srb = (PSCSI_REQUEST_BLOCK)Context;
+  Irp->IoStatus.Information = 0;
 
-static VOID STDCALL
-ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
-               IN PIRP Irp)
+  switch (SRB_STATUS(Srb->SrbStatus))
+    {
+      case SRB_STATUS_SUCCESS:
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+        Irp->IoStatus.Information = Srb->DataTransferLength;
+        break;
+
+      case SRB_STATUS_INVALID_PATH_ID:
+      case SRB_STATUS_INVALID_TARGET_ID:
+      case SRB_STATUS_INVALID_LUN:
+      case SRB_STATUS_NO_HBA:
+        Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
+       break;
+
+      case SRB_STATUS_NO_DEVICE:
+        Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
+        break;
+
+      case SRB_STATUS_BUSY:
+       Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
+        break;
+
+      case SRB_STATUS_DATA_OVERRUN:
+       Irp->IoStatus.Status = STATUS_DATA_OVERRUN;
+        Irp->IoStatus.Information = Srb->DataTransferLength;
+        break;
+
+      case SRB_STATUS_INVALID_REQUEST:
+        Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+        break;
+
+      default:
+       Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
+       break;
+    }
+
+  ExFreePool(Srb);
+
+  if (Irp->PendingReturned)
+    {
+      IoMarkIrpPending (Irp);
+    }
+  return Irp->IoStatus.Status;
+}
+
+static NTSTATUS
+SpiScsiMiniport(IN PDEVICE_OBJECT DeviceObject,
+               IN PIRP Irp)
 {
   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+  PSRB_IO_CONTROL SrbIoControl;
   PIO_STACK_LOCATION IrpStack;
-  KIRQL OldIrql;
-
-  DPRINT("ScsiPortStartIo() called!\n");
+  PSCSI_REQUEST_BLOCK Srb;
+  PSCSI_PORT_LUN_EXTENSION LunExtension;
+  
+  DPRINT("SpiScsiMiniport(DeviceObject %x, Irp %x)\n",
+         DeviceObject, Irp);
 
   DeviceExtension = DeviceObject->DeviceExtension;
-  IrpStack = IoGetCurrentIrpStackLocation(Irp);
-
-  // FIXME: implement the supported functions
+  SrbIoControl = (PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer;
 
-  switch (IrpStack->MajorFunction)
+  IrpStack = IoGetCurrentIrpStackLocation(Irp);
+  if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1)
     {
-      case IRP_MJ_SCSI:
-       {
-         BOOLEAN Result;
-         PSCSI_REQUEST_BLOCK Srb;
+      Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_INVALID_PARAMETER;
+    }
+  if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SRB_IO_CONTROL) + SrbIoControl->Length)
+    {
+      Irp->IoStatus.Information = sizeof(SRB_IO_CONTROL) + SrbIoControl->Length;
+      Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_BUFFER_TOO_SMALL;
+    }
+  if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
+    {
+      Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
+      Irp->IoStatus.Information = 0;
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_NO_SUCH_DEVICE;
+    }
 
-         DPRINT("IRP_MJ_SCSI\n");
+  Srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
+  if (Srb == NULL)
+    {
+      Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_INSUFFICIENT_RESOURCES;
+    }
+  RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
+  Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+  Srb->OriginalRequest = Irp;
+  Srb->Function = SRB_FUNCTION_IO_CONTROL;
+  Srb->DataBuffer = (PVOID)SrbIoControl;
+  Srb->DataTransferLength = sizeof(SRB_IO_CONTROL) + SrbIoControl->Length;
+
+  /* We using the first extension from the list. The miniport driver is responsible to find the correct device. */
+  LunExtension = CONTAINING_RECORD(DeviceExtension->LunExtensionListHead.Flink,
+                                  SCSI_PORT_LUN_EXTENSION,
+                                  List);
+  Srb->PathId = LunExtension->PathId;
+  Srb->TargetId = LunExtension->TargetId;
+  Srb->Lun = LunExtension->Lun;
+  
+  IrpStack = IoGetNextIrpStackLocation(Irp);
+  
+  IrpStack->MajorFunction = IRP_MJ_SCSI;
+  IrpStack->Parameters.Scsi.Srb = Srb;
 
-         Srb = IrpStack->Parameters.Scsi.Srb;
+  IoSetCompletionRoutine(Irp,
+                        SpiCompletion,
+                        Srb,
+                        TRUE,
+                        TRUE,
+                        TRUE);
 
-         DPRINT("DeviceExtension %p\n", DeviceExtension);
+  return IoCallDriver(DeviceObject, Irp);
+}
 
-         Irp->IoStatus.Status = STATUS_SUCCESS;
-         Irp->IoStatus.Information = Srb->DataTransferLength;
+static VOID
+SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                       PSCSI_REQUEST_BLOCK Srb)
+{
+  ULONG index;
 
-         DeviceExtension->CurrentIrp = Irp;
+  DPRINT("SpiAllocateSrbExtension\n");
 
-         if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
-                                     ScsiPortStartPacket,
-                                     DeviceExtension))
-           {
-               DPRINT("Synchronization failed!\n");
-
-               Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
-               Irp->IoStatus.Information = 0;
-               IoCompleteRequest(Irp,
-                                 IO_NO_INCREMENT);
-               IoStartNextPacket(DeviceObject,
-                                 FALSE);
-           }
-         if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
-           {
-               DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
-               IoCompleteRequest(Irp,
-                                 IO_NO_INCREMENT);
-           }
+  DPRINT("DeviceExtension->VirtualAddress %x, DeviceExtension->SrbExtensionSize %x\n",
+         DeviceExtension->VirtualAddress, DeviceExtension->SrbExtensionSize);
 
-         if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
-           {
-               DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
-               IoStartNextPacket(DeviceObject,
-                                 FALSE);
-           }
+  Srb->SrbExtension = NULL;
+  if (DeviceExtension->VirtualAddress != NULL &&
+      DeviceExtension->SrbExtensionSize > 0)
+    {
+      index = RtlFindClearBitsAndSet(&DeviceExtension->SrbExtensionAllocMap, 1, 0);
+      if (index != 0xffffffff)
+        {
+         DeviceExtension->CurrentSrbExtensions++;
+          Srb->SrbExtension = (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + index * DeviceExtension->SrbExtensionSize);
        }
-       break;
+    }
+  DPRINT("%x\n", Srb->SrbExtension);
+}
 
-      default:
-       Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
-       Irp->IoStatus.Information = 0;
-       IoCompleteRequest(Irp,
-                         IO_NO_INCREMENT);
-       IoStartNextPacket(DeviceObject,
-                         FALSE);
-       break;
+static VOID
+SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                   PSCSI_REQUEST_BLOCK Srb)
+{
+  ULONG index;
+
+  if (DeviceExtension->VirtualAddress != NULL &&
+      DeviceExtension->SrbExtensionSize > 0 &&
+      Srb->SrbExtension != NULL)
+    {
+      index = ((ULONG_PTR)Srb->SrbExtension - (ULONG_PTR)DeviceExtension->VirtualAddress) / DeviceExtension->SrbExtensionSize;
+      RtlClearBits(&DeviceExtension->SrbExtensionAllocMap, index, 1);
+      DeviceExtension->CurrentSrbExtensions--;
     }
-  DPRINT("ScsiPortStartIo() done\n");
+  Srb->SrbExtension = NULL;
 }
 
 
@@ -1000,293 +1974,391 @@ static BOOLEAN STDCALL
 ScsiPortStartPacket(IN OUT PVOID Context)
 {
   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  PIO_STACK_LOCATION IrpStack;
   PSCSI_REQUEST_BLOCK Srb;
+  PIRP Irp;
+  PIO_STACK_LOCATION IrpStack;
 
-  DPRINT("ScsiPortStartPacket() called\n");
-
-  DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context;
+  DPRINT("ScsiPortStartPacket(Context %x) called\n", Context);
 
-  IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
-  Srb = IrpStack->Parameters.Scsi.Srb;
+  Srb = (PSCSI_REQUEST_BLOCK)Context;
+  Irp = (PIRP)Srb->OriginalRequest;
+  IrpStack = IoGetCurrentIrpStackLocation(Irp);
+  DeviceExtension = IrpStack->DeviceObject->DeviceExtension;
 
   return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
                                    Srb));
 }
 
 
-/**********************************************************************
- * NAME                                                        INTERNAL
- *     ScsiPortCreatePortDevice
- *
- * DESCRIPTION
- *     Creates and initializes a SCSI port device object.
- *
- * RUN LEVEL
- *     PASSIVE_LEVEL
- *
- * ARGUMENTS
- *     DriverObject
- *             ...
- *
- *     PseudoDeviceExtension
- *             ...
- *
- *     PortNumber
- *             ...
- *
- * RETURNS
- *     NTSTATUS
- */
+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;
+
+  LunExtension->PendingIrpCount = 0;
+  LunExtension->ActiveIrpCount = 0;
+
+  LunExtension->NextIrp = NULL;
+
+  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
-ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
-                        IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
-                        IN ULONG PortNumber)
+SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
+               IN OUT PSCSI_REQUEST_BLOCK Srb,
+               IN OUT PIO_STATUS_BLOCK IoStatusBlock,
+               IN OUT PKEVENT Event)
 {
-  PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension;
-  PIO_SCSI_CAPABILITIES PortCapabilities;
-  PDEVICE_OBJECT PortDeviceObject;
-  WCHAR NameBuffer[80];
-  UNICODE_STRING DeviceName;
-  WCHAR DosNameBuffer[80];
-  UNICODE_STRING DosDeviceName;
+  PIO_STACK_LOCATION IrpStack;
+  PIRP Irp;
   NTSTATUS Status;
-  ULONG AccessRangeSize;
 
-#if 0
-  ULONG MappedIrq;
-  KIRQL Dirql;
-  KAFFINITY Affinity;
-#endif
+  DPRINT ("SpiSendInquiry() called\n");
 
-  DPRINT("ScsiPortCreatePortDevice() called\n");
 
-#if 0
-  MappedIrq = HalGetInterruptVector(PseudoDeviceExtension->PortConfig.AdapterInterfaceType,
-                                   PseudoDeviceExtension->PortConfig.SystemIoBusNumber,
-                                   0,
-                                   PseudoDeviceExtension->PortConfig.BusInterruptLevel,
-                                   &Dirql,
-                                   &Affinity);
-#endif
+  KeInitializeEvent (Event,
+                    NotificationEvent,
+                    FALSE);
 
-  /* Create a unicode device name */
-  swprintf(NameBuffer,
-          L"\\Device\\ScsiPort%lu",
-          PortNumber);
-  RtlInitUnicodeString(&DeviceName,
-                      NameBuffer);
+  Irp = IoBuildDeviceIoControlRequest (IOCTL_SCSI_EXECUTE_OUT,
+                                      DeviceObject,
+                                      NULL,
+                                      0,
+                                      Srb->DataBuffer,
+                                      Srb->DataTransferLength,
+                                      TRUE,
+                                      Event,
+                                      IoStatusBlock);
+  if (Irp == NULL)
+    {
+      DPRINT("IoBuildDeviceIoControlRequest() failed\n");
+      return STATUS_INSUFFICIENT_RESOURCES;
+    }
 
-  DPRINT("Creating device: %wZ\n", &DeviceName);
+  /* Attach Srb to the Irp */
+  IrpStack = IoGetNextIrpStackLocation (Irp);
+  IrpStack->Parameters.Scsi.Srb = Srb;
+  Srb->OriginalRequest = Irp;
 
-  /* Create the port device */
-  Status = IoCreateDevice(DriverObject,
-                         PseudoDeviceExtension->Length,
-                         &DeviceName,
-                         FILE_DEVICE_CONTROLLER,
-                         0,
-                         FALSE,
-                         &PortDeviceObject);
-  if (!NT_SUCCESS(Status))
+  /* Call the driver */
+  Status = IoCallDriver (DeviceObject,
+                        Irp);
+
+  return Status;
+}
+
+static VOID
+SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+  PSCSI_REQUEST_BLOCK Srb;
+  PCDB Cdb;
+  ULONG Bus;
+  ULONG Target;
+  PSCSI_PORT_SCAN_ADAPTER ScanDataArray;
+  PSCSI_PORT_SCAN_ADAPTER ScanData;
+  ULONG i;
+  ULONG MaxCount;
+  ULONG WaitCount;
+  ULONG ActiveCount;
+  PVOID* EventArray;
+  PKWAIT_BLOCK WaitBlockArray;
+
+  DPRINT ("SpiScanAdapter() called\n");
+
+  MaxCount = DeviceExtension->PortConfig->NumberOfBuses *
+               DeviceExtension->PortConfig->MaximumNumberOfTargets;
+
+  ScanDataArray = ExAllocatePool(NonPagedPool, MaxCount * (sizeof(SCSI_PORT_SCAN_ADAPTER) + sizeof(PVOID) + sizeof(KWAIT_BLOCK)));
+  if (ScanDataArray == NULL)
     {
-      DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
-      return(Status);
+      return;
     }
+  EventArray = (PVOID*)((PUCHAR)ScanDataArray + MaxCount * sizeof(SCSI_PORT_SCAN_ADAPTER));
+  WaitBlockArray = (PKWAIT_BLOCK)((PUCHAR)EventArray + MaxCount * sizeof(PVOID));
 
-  DPRINT("Created device: %wZ\n", &DeviceName);
-
-  /* Set the buffering strategy here... */
-  PortDeviceObject->Flags |= DO_DIRECT_IO;
-  PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
-
-  PortDeviceExtension = PortDeviceObject->DeviceExtension;
-
-  /* Copy pseudo device extension into the real device extension */
-  memcpy(PortDeviceExtension,
-        PseudoDeviceExtension,
-        PseudoDeviceExtension->Length);
-
-  /* Copy access ranges */
-  AccessRangeSize =
-    sizeof(ACCESS_RANGE) * PseudoDeviceExtension->PortConfig.NumberOfAccessRanges;
-  PortDeviceExtension->PortConfig.AccessRanges = ExAllocatePool(NonPagedPool,
-                                                               AccessRangeSize);
-  memcpy(PortDeviceExtension->PortConfig.AccessRanges,
-        PseudoDeviceExtension->PortConfig.AccessRanges,
-        AccessRangeSize);
-
-  PortDeviceExtension->DeviceObject = PortDeviceObject;
-  PortDeviceExtension->PortNumber = PortNumber;
-
-  /* Initialize the spin lock in the controller extension */
-  KeInitializeSpinLock(&PortDeviceExtension->SpinLock);
-
-  /* Register an interrupt handler for this device */
-  Status = IoConnectInterrupt(&PortDeviceExtension->Interrupt,
-                             ScsiPortIsr,
-                             PortDeviceExtension,
-                             &PortDeviceExtension->SpinLock,
-                             PortDeviceExtension->PortConfig.BusInterruptVector, // MappedIrq,
-                             PortDeviceExtension->PortConfig.BusInterruptLevel, // Dirql,
-                             15, //Dirql,
-                             PortDeviceExtension->PortConfig.InterruptMode,
-                             FALSE,
-                             0xFFFF, //Affinity,
-                             FALSE);
-  if (!NT_SUCCESS(Status))
+  for (Bus = 0; Bus < DeviceExtension->PortConfig->NumberOfBuses; Bus++)
     {
-      DbgPrint("Could not Connect Interrupt %d\n",
-              PortDeviceExtension->PortConfig.BusInterruptVector);
-      return(Status);
+      for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
+       {
+         ScanData = &ScanDataArray[Bus * DeviceExtension->PortConfig->MaximumNumberOfTargets + Target];
+         ScanData->Bus = Bus;
+         ScanData->Target = Target;
+         ScanData->Lun = 0;
+         ScanData->Active = FALSE;
+       }
+    }
+  do
+    {
+      ActiveCount = 0;
+      WaitCount = 0;
+      for (i = 0; i < MaxCount; i++)
+        {
+          ScanData = &ScanDataArray[i];
+         Srb = &ScanData->Srb;
+          if (ScanData->Active)
+            {
+             if (ScanData->Status == STATUS_PENDING &&
+                 0 == KeReadStateEvent(&ScanData->Event))
+               {
+                 ActiveCount++;
+                 continue;
+               }
+             else
+               {
+                  ScanData->Status = ScanData->IoStatusBlock.Status;
+               }
+             ScanData->Active = FALSE;
+             DPRINT ("Target %lu  Lun %lu\n", ScanData->Target, ScanData->Lun);
+             DPRINT ("Status %lx  Srb.SrbStatus %x\n", ScanData->Status, Srb->SrbStatus);
+             DPRINT ("DeviceTypeQualifier %x\n", ((PINQUIRYDATA)Srb->DataBuffer)->DeviceTypeQualifier);
+
+             if (NT_SUCCESS(ScanData->Status) &&
+                 (Srb->SrbStatus == SRB_STATUS_SUCCESS ||
+                  (Srb->SrbStatus == SRB_STATUS_DATA_OVERRUN &&
+                  /*
+                   * FIXME:
+                   *   The NT 4.0 driver from an inic950 based scsi controller
+                   *   returns only 4 byte of inquiry data, but the device name
+                   *   is visible on NT 4.0. We must implement an other way
+                   *   to get the complete inquiry data.
+                   */
+                   Srb->DataTransferLength >= /*INQUIRYDATABUFFERSIZE*/4)) &&
+                 ((PINQUIRYDATA)Srb->DataBuffer)->DeviceTypeQualifier == 0)
+               {
+                 /* Copy inquiry data */
+                 RtlCopyMemory (&ScanData->LunExtension->InquiryData,
+                                Srb->DataBuffer,
+                                min(sizeof(INQUIRYDATA), Srb->DataTransferLength));
+                 ScanData->Lun++;
+               }
+             else
+               {
+                 SpiRemoveLunExtension (ScanData->LunExtension);
+                 ScanData->Lun = SCSI_MAXIMUM_LOGICAL_UNITS;
+               }
+           }
+          if (ScanData->Lun >= SCSI_MAXIMUM_LOGICAL_UNITS)
+            {
+             continue;
+           }
+          RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
+          Srb->SrbFlags = SRB_FLAGS_DATA_IN;
+          Srb->DataBuffer = ScanData->DataBuffer;
+          Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+          Srb->DataTransferLength = 255; //256;
+          Srb->CdbLength = 6;
+          Srb->Lun = ScanData->Lun;
+          Srb->PathId = ScanData->Bus;
+          Srb->TargetId = ScanData->Target;
+          Srb->SrbStatus = SRB_STATUS_SUCCESS;
+         Srb->TimeOutValue = 2;
+          Cdb = (PCDB) &Srb->Cdb;
+
+          Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
+          Cdb->CDB6INQUIRY.AllocationLength = 255;
+          Cdb->CDB6INQUIRY.LogicalUnitNumber = ScanData->Lun;
+
+          RtlZeroMemory(Srb->DataBuffer, 256);
+
+          ScanData->LunExtension = SpiAllocateLunExtension (DeviceExtension,
+                                                           ScanData->Bus,
+                                                           ScanData->Target,
+                                                           ScanData->Lun);
+          if (ScanData->LunExtension == NULL)
+           {
+             DPRINT1("Failed to allocate the LUN extension!\n");
+             ScanData->Lun = SCSI_MAXIMUM_LOGICAL_UNITS;
+             continue;
+           }
+          ScanData->Status = SpiSendInquiry (DeviceExtension->DeviceObject,
+                                            Srb,
+                                            &ScanData->IoStatusBlock,
+                                            &ScanData->Event);
+         ScanData->Active = TRUE;
+         ActiveCount++;
+         if (ScanData->Status == STATUS_PENDING)
+           {
+              EventArray[WaitCount] = &ScanData->Event;
+              WaitCount++;
+            }
+       }
+      if (WaitCount > 0 && WaitCount == ActiveCount)
+        {
+          KeWaitForMultipleObjects(WaitCount,
+                                   EventArray,
+                                  WaitAny,
+                                  Executive,
+                                  KernelMode,
+                                  FALSE,
+                                  NULL,
+                                  WaitBlockArray);
+       }
     }
+  while (ActiveCount > 0);
 
-  /* Initialize the DPC object */
-  IoInitializeDpcRequest(PortDeviceExtension->DeviceObject,
-                        ScsiPortDpcForIsr);
-
-  /* Initialize the device timer */
-  PortDeviceExtension->TimerState = IDETimerIdle;
-  PortDeviceExtension->TimerCount = 0;
-  IoInitializeTimer(PortDeviceExtension->DeviceObject,
-                   ScsiPortIoTimer,
-                   PortDeviceExtension);
-
-  /* Initialize port capabilities */
-  PortCapabilities = ExAllocatePool(NonPagedPool,
-                                   sizeof(IO_SCSI_CAPABILITIES));
-  PortDeviceExtension->PortCapabilities = PortCapabilities;
-  PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
-  PortCapabilities->MaximumTransferLength =
-    PortDeviceExtension->PortConfig.MaximumTransferLength;
-  PortCapabilities->MaximumPhysicalPages =
-    PortCapabilities->MaximumTransferLength / PAGESIZE;
-  PortCapabilities->SupportedAsynchronousEvents = 0; /* FIXME */
-  PortCapabilities->AlignmentMask =
-    PortDeviceExtension->PortConfig.AlignmentMask;
-  PortCapabilities->TaggedQueuing =
-    PortDeviceExtension->PortConfig.TaggedQueuing;
-  PortCapabilities->AdapterScansDown =
-    PortDeviceExtension->PortConfig.AdapterScansDown;
-  PortCapabilities->AdapterUsesPio = TRUE; /* FIXME */
-
-  /* Initialize inquiry data */
-  PortDeviceExtension->PortBusInfoSize = 0;
-  PortDeviceExtension->PortBusInfo = NULL;
-
-  DPRINT("DeviceExtension %p\n", PortDeviceExtension);
-  ScsiPortInquire(PortDeviceExtension);
-
-
-  /* FIXME: Copy more configuration data? */
-
-  /* Create the dos device link */
-  swprintf(DosNameBuffer,
-          L"\\??\\Scsi%lu:",
-          PortNumber);
-  RtlInitUnicodeString(&DosDeviceName,
-                      DosNameBuffer);
-
-  IoCreateSymbolicLink(&DosDeviceName,
-                      &DeviceName);
-
-  DPRINT("ScsiPortCreatePortDevice() done\n");
+  ExFreePool(ScanDataArray);
 
-  return(STATUS_SUCCESS);
+  DPRINT ("SpiScanAdapter() done\n");
 }
 
 
-static VOID
-ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+static ULONG
+SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                 OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo)
 {
-  PSCSI_ADAPTER_BUS_INFO AdapterInfo;
+  PSCSI_PORT_LUN_EXTENSION LunExtension;
   PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
-  SCSI_REQUEST_BLOCK Srb;
   ULONG Bus;
   ULONG Target;
+  ULONG Lun;
   ULONG UnitCount;
-  ULONG DataSize;
-  BOOLEAN Result;
-
-  DPRINT("ScsiPortInquire() called\n");
 
-  DeviceExtension->Initializing = TRUE;
+  DPRINT("SpiGetInquiryData() called\n");
 
   /* Copy inquiry data to the port device extension */
-  AdapterInfo =(PSCSI_ADAPTER_BUS_INFO)ExAllocatePool(NonPagedPool, 4096);
-  RtlZeroMemory(AdapterInfo, 4096);
-  AdapterInfo->NumberOfBuses = DeviceExtension->PortConfig.NumberOfBuses;
+  AdapterBusInfo->NumberOfBuses = DeviceExtension->PortConfig->NumberOfBuses;
 
   UnitInfo = (PSCSI_INQUIRY_DATA)
-       ((PUCHAR)AdapterInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
-        (sizeof(SCSI_BUS_DATA) * (AdapterInfo->NumberOfBuses - 1)));
+       ((PUCHAR)AdapterBusInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
+        (sizeof(SCSI_BUS_DATA) * (AdapterBusInfo->NumberOfBuses - 1)));
 
-  RtlZeroMemory(&Srb,
-               sizeof(SCSI_REQUEST_BLOCK));
-  Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
-  Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
-  Srb.DataTransferLength = 256;
-  Srb.Cdb[0] = SCSIOP_INQUIRY;
-
-  for (Bus = 0; Bus < AdapterInfo->NumberOfBuses; Bus++)
+  for (Bus = 0; Bus < AdapterBusInfo->NumberOfBuses; Bus++)
     {
-      Srb.PathId = Bus;
-
-      AdapterInfo->BusData[Bus].InitiatorBusId = 0;    /* ? */
-      AdapterInfo->BusData[Bus].InquiryDataOffset =
-        (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterInfo);
+      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 (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
        {
-         Srb.TargetId = Target;
-         Srb.Lun = 0;
-         Srb.SrbStatus = SRB_STATUS_SUCCESS;
-
-         Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
-                                             &Srb);
-         DPRINT("Result: %s  Srb.SrbStatus %lx\n", (Result)?"True":"False", Srb.SrbStatus);
-
-         if (Result == TRUE && Srb.SrbStatus == SRB_STATUS_SUCCESS)
+         for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
            {
-             UnitInfo->PathId = Bus;
-             UnitInfo->TargetId = Target;
-             UnitInfo->Lun = 0;
-             UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
-             memcpy(&UnitInfo->InquiryData,
-                    Srb.DataBuffer,
-                    INQUIRYDATABUFFERSIZE);
-             if (PrevUnit != NULL)
-               PrevUnit->NextInquiryDataOffset = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
-             PrevUnit = UnitInfo;
-             UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
-             UnitCount++;
+             LunExtension = SpiGetLunExtension(DeviceExtension,
+                                               Bus,
+                                               Target,
+                                               Lun);
+             if (LunExtension != NULL)
+               {
+                 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
+                        Bus, Target, Lun);
+          RtlZeroMemory(UnitInfo, sizeof(*UnitInfo));
+                 UnitInfo->PathId = Bus;
+                 UnitInfo->TargetId = Target;
+                 UnitInfo->Lun = Lun;
+                 UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
+                 RtlCopyMemory (&UnitInfo->InquiryData,
+                                &LunExtension->InquiryData,
+                                INQUIRYDATABUFFERSIZE);
+                 if (PrevUnit != NULL)
+                   {
+                     PrevUnit->NextInquiryDataOffset =
+                       (ULONG)((ULONG_PTR)UnitInfo-(ULONG_PTR)AdapterBusInfo);
+                   }
+                 PrevUnit = UnitInfo;
+                 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
+                 UnitCount++;
+               }
            }
        }
       DPRINT("UnitCount: %lu\n", UnitCount);
-      AdapterInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
+      AdapterBusInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
       if (UnitCount == 0)
-       AdapterInfo->BusData[Bus].InquiryDataOffset = 0;
+       {
+         AdapterBusInfo->BusData[Bus].InquiryDataOffset = 0;
+       }
     }
-  DataSize = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
-
-  ExFreePool(Srb.DataBuffer);
-
-  DeviceExtension->Initializing = FALSE;
-
-  /* copy inquiry data to the port driver's device extension */
-  DeviceExtension->PortBusInfoSize = DataSize;
-  DeviceExtension->PortBusInfo = ExAllocatePool(NonPagedPool,
-                                               DataSize);
-  RtlCopyMemory(DeviceExtension->PortBusInfo,
-               AdapterInfo,
-               DataSize);
 
-  ExFreePool(AdapterInfo);
+  DPRINT("Data size: %lu\n", (ULONG)UnitInfo - (ULONG)AdapterBusInfo);
 
-  DPRINT("ScsiPortInquire() done\n");
+  return (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterBusInfo);
 }
 
 
@@ -1295,30 +2367,16 @@ 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);
+  return DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
 }
 
 
-//    ScsiPortDpcForIsr
+//    ScsiPortDpc
 //  DESCRIPTION:
 //
 //  RUN LEVEL:
@@ -1330,92 +2388,21 @@ ScsiPortIsr(IN PKINTERRUPT Interrupt,
 //    IN PVOID          DpcContext
 //
 static VOID STDCALL
-ScsiPortDpcForIsr(IN PKDPC Dpc,
-                 IN PDEVICE_OBJECT DpcDeviceObject,
-                 IN PIRP DpcIrp,
-                 IN PVOID DpcContext)
+ScsiPortDpc(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);
+  DPRINT("ScsiPortDpc(Dpc %p  DpcDeviceObject %p  DpcIrp %p  DpcContext %p)\n",
+        Dpc, DpcDeviceObject, DpcIrp, DpcContext);
 
   DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
 
-  IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
-  Srb = IrpStack->Parameters.Scsi.Srb;
+  SpiProcessRequests(DeviceExtension, NULL);
 
-  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;
-      DeviceExtension->OriginalSrb = NULL;
-    }
-  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);
-
-      if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
-                                 ScsiPortStartPacket,
-                                 DeviceExtension))
-       {
-         DPRINT("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;
-      IoStartNextPacket(DpcDeviceObject, FALSE);
-    }
-
-  DPRINT("ScsiPortDpcForIsr() done\n");
+  DPRINT("ScsiPortDpc() done\n");
 }
 
 
@@ -1439,27 +2426,39 @@ ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
 
 
 static PSCSI_REQUEST_BLOCK
-ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                           PSCSI_REQUEST_BLOCK OriginalSrb)
+ScsiPortInitSenseRequestSrb(PSCSI_REQUEST_BLOCK OriginalSrb)
 {
   PSCSI_REQUEST_BLOCK Srb;
+  ULONG Length;
   PCDB Cdb;
 
-  Srb = &DeviceExtension->InternalSrb;
+  Length = sizeof(SCSI_REQUEST_BLOCK) + sizeof(SENSE_DATA) + 32;
+  Srb = ExAllocatePoolWithTag(NonPagedPool,
+                              Length,
+                             TAG('S', 'S', 'r', 'b'));
+  if (Srb == NULL)
+    {
+      return NULL;
+    }
 
-  RtlZeroMemory(Srb,
-               sizeof(SCSI_REQUEST_BLOCK));
+  RtlZeroMemory(Srb, Length);
 
   Srb->PathId = OriginalSrb->PathId;
   Srb->TargetId = OriginalSrb->TargetId;
   Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
   Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
   Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+  Srb->OriginalRequest = OriginalSrb->OriginalRequest;
 
   Srb->TimeOutValue = 4;
 
   Srb->CdbLength = 6;
-  Srb->DataBuffer = &DeviceExtension->InternalSenseData;
+  /* The DataBuffer must be located in contiguous physical memory if
+   * the miniport driver uses dma for the sense info. The size of
+   * the sense data is 18 byte. If the buffer starts at a 32 byte
+   * boundary than is the buffer always in one memory page.
+   */
+  Srb->DataBuffer = (PVOID)ROUND_UP((ULONG_PTR)(Srb + 1), 32);
   Srb->DataTransferLength = sizeof(SENSE_DATA);
 
   Cdb = (PCDB)Srb->Cdb;
@@ -1469,39 +2468,70 @@ ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
   return(Srb);
 }
 
+/**********************************************************************
+ * 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 VOID
-ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
-{
-  DeviceExtension->OriginalSrb = NULL;
-}
-
-
-#if 0
 static NTSTATUS
-ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                  PUNICODE_STRING RegistryPath)
 {
+  PSCSI_PORT_LUN_EXTENSION LunExtension;
   OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING KeyName;
-  WCHAR NameBuffer[32];
+  UNICODE_STRING KeyName =
+    RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
+  UNICODE_STRING ValueName;
+  WCHAR NameBuffer[64];
   ULONG Disposition;
   HANDLE ScsiKey;
-  HANDLE ScsiPortKey;
-  HANDLE ScsiBusKey;
-  HANDLE ScsiTargetKey;
-  HANDLE ScsiUnitKey;
+  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 */
-  RtlInitUnicodeStringFromLiteral(&KeyName,
-       L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
   InitializeObjectAttributes(&ObjectAttributes,
                             &KeyName,
-                            OBJ_OPENIF,
+                            OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
                             0,
                             NULL);
-  Status = NtCreateKey(&ScsiKey,
+  Status = ZwCreateKey(&ScsiKey,
                       KEY_ALL_ACCESS,
                       &ObjectAttributes,
                       0,
@@ -1509,9 +2539,15 @@ ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
                       REG_OPTION_VOLATILE,
                       &Disposition);
   if (!NT_SUCCESS(Status))
-    return(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);
@@ -1522,73 +2558,725 @@ ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
                             0,
                             ScsiKey,
                             NULL);
-  Status = NtCreateKey(&ScsiPortKey,
+  Status = ZwCreateKey(&ScsiPortKey,
                       KEY_ALL_ACCESS,
                       &ObjectAttributes,
                       0,
                       NULL,
                       REG_OPTION_VOLATILE,
                       &Disposition);
+  ZwClose(ScsiKey);
   if (!NT_SUCCESS(Status))
     {
-      NtClose(ScsiKey);
+      DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
       return(Status);
     }
 
-  /* Add port-specific values */
-
-  /* 'DMA Enabled' (REG_DWORD) */
-  DPRINT1("DMA Enabled = %s\n",
-         (DeviceExtension->PortCapabilities->AdapterUsesPio)?"TRUE":"FALSE");
-
-  /* 'Driver' (REG_SZ) */
-
-  /* 'Interrupt' (REG_DWORD) (NT4 only) */
-  DPRINT1("Interrupt = %lx\n", DeviceExtension->PortConfig.BusInterruptLevel);
-
-  /* 'IOAddress' (REG_DWORD) (NT4 only) */
-  DPRINT1("IOAddress = %lx\n",
-         ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig.AccessRanges[0].RangeStart));
-
-
-  /* Create 'Scsi Bus X' keys */
-  for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig.NumberOfBuses; BusNumber++)
-     {
-       swprintf(NameBuffer,
-                L"Scsi Bus %lu",
-                DeviceExtension->PortNumber);
-       RtlInitUnicodeString(&KeyName,
-                            NameBuffer);
-       InitializeObjectAttributes(&ObjectAttributes,
-                                  &KeyName,
-                                  0,
-                                  ScsiPortKey,
-                                  NULL);
-       Status = NtCreateKey(&ScsiBusKey,
-                            KEY_ALL_ACCESS,
-                            &ObjectAttributes,
-                            0,
-                            NULL,
-                            REG_OPTION_VOLATILE,
-                            &Disposition);
-       if (!NT_SUCCESS(Status))
-         {
-           NtClose(ScsiPortKey);
-           NtClose(ScsiKey);
-           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);
 
-       /* Create target keys */
+  if (ScsiTargetKey != NULL)
+    ZwClose (ScsiTargetKey);
 
+  if (ScsiBusKey != NULL)
+    ZwClose (ScsiBusKey);
 
-       NtClose(ScsiBusKey);
+  if (ScsiPortKey != NULL)
+    ZwClose (ScsiPortKey);
+
+  DPRINT("SpiBuildDeviceMap() done\n");
+
+  return Status;
+}
+
+static VOID
+SpiRemoveActiveIrp(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                  PIRP Irp,
+                  PIRP PrevIrp)
+{
+  PSCSI_PORT_LUN_EXTENSION LunExtension;
+  PIRP CurrentIrp;
+  LunExtension = Irp->Tail.Overlay.DriverContext[2];
+  InterlockedDecrement((PLONG)&LunExtension->ActiveIrpCount);
+  InterlockedDecrement((PLONG)&DeviceExtension->ActiveIrpCount);
+  if (PrevIrp)
+    {
+      InterlockedExchangePointer(&PrevIrp->Tail.Overlay.DriverContext[0],
+                                Irp->Tail.Overlay.DriverContext[0]);
+    }
+  else
+    {
+      InterlockedExchangePointer(&DeviceExtension->NextIrp,
+                                Irp->Tail.Overlay.DriverContext[0]);
+    }
+  if (LunExtension->NextIrp == Irp)
+    {
+      InterlockedExchangePointer(&LunExtension->NextIrp,
+                                Irp->Tail.Overlay.DriverContext[1]);
+      return;
+    }
+  else
+    {
+      CurrentIrp = LunExtension->NextIrp;
+      while (CurrentIrp)
+        {
+         if (CurrentIrp->Tail.Overlay.DriverContext[1] == Irp)
+           {
+             InterlockedExchangePointer(&CurrentIrp->Tail.Overlay.DriverContext[1],
+                                        Irp->Tail.Overlay.DriverContext[1]);
+             return;
+           }
+          CurrentIrp = CurrentIrp->Tail.Overlay.DriverContext[1];
+       }
+      KEBUGCHECK(0);
+    }
+}
+
+static VOID
+SpiAddActiveIrp(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+               PIRP Irp)
+{
+  PSCSI_PORT_LUN_EXTENSION LunExtension;
+  PSCSI_REQUEST_BLOCK Srb;
+  LunExtension = Irp->Tail.Overlay.DriverContext[2];
+  Srb = Irp->Tail.Overlay.DriverContext[3];
+  Irp->Tail.Overlay.DriverContext[0] = (PVOID)DeviceExtension->NextIrp;
+  InterlockedExchangePointer(&DeviceExtension->NextIrp, Irp);
+  Irp->Tail.Overlay.DriverContext[1] = (PVOID)LunExtension->NextIrp;
+  InterlockedExchangePointer(&LunExtension->NextIrp, Irp);
+}
+
+static VOID
+SpiProcessRequests(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                  IN PIRP NextIrp)
+{
+  /*
+   * Using of some fields from Srb and Irp while processing requests:
+   *
+   * NextIrp on entry:
+   *   Srb->OriginalRequest -> LunExtension
+   *   Irp->Tail.Overlay.DriverContext[3] -> original Srb
+   *   IoStack->Parameters.Scsi.Srb -> original Srb
+   *
+   * Irp is within the pending irp list:
+   *   Srb->OriginalRequest -> LunExtension
+   *   Irp->Tail.Overlay.DriverContext[0] and DriverContext[1] -> ListEntry for queue
+   *   Irp->Tail.Overlay.DriverContext[2] -> sort key (from Srb->QueueSortKey)
+   *   Irp->Tail.Overlay.DriverContext[3] -> current Srb (original or sense request)
+   *   IoStack->Parameters.Scsi.Srb -> original Srb
+   *
+   * Irp is within the active irp list or while other processing:
+   *   Srb->OriginalRequest -> Irp
+   *   Irp->Tail.Overlay.DriverContext[0] -> next irp, DeviceExtension->NextIrp is head.
+   *   Irp->Tail.Overlay.DriverContext[1] -> next irp, LunExtension->NextIrp is head.
+   *   Irp->Tail.Overlay.DriverContext[2] -> LunExtension
+   *   Irp->Tail.Overlay.DriverContext[3] -> current Srb (original or sense request)
+   *   IoStack->Parameters.Scsi.Srb -> original Srb
+   */
+  PIO_STACK_LOCATION IrpStack;
+  PSCSI_PORT_LUN_EXTENSION LunExtension;
+  PLIST_ENTRY ListEntry;
+  KIRQL oldIrql;
+  PIRP Irp;
+  LIST_ENTRY NextIrpListHead;
+  LIST_ENTRY CompleteIrpListHead;
+  PSCSI_REQUEST_BLOCK Srb;
+  PSCSI_REQUEST_BLOCK OriginalSrb;
+  PIRP PrevIrp;
+
+  DPRINT("SpiProcessRequests() called\n");
+
+  InitializeListHead(&NextIrpListHead);
+  InitializeListHead(&CompleteIrpListHead);
+
+  KeAcquireSpinLock(&DeviceExtension->Lock, &oldIrql);
+
+  if (NextIrp)
+    {
+      Srb = NextIrp->Tail.Overlay.DriverContext[3];
+      /*
+       * FIXME:
+       *   Is this the right place to set this flag ?
+       */
+      NextIrp->Tail.Overlay.DriverContext[2] = (PVOID)Srb->QueueSortKey;
+      LunExtension = Srb->OriginalRequest;
+
+      ListEntry = DeviceExtension->PendingIrpListHead.Flink;
+      while (ListEntry != &DeviceExtension->PendingIrpListHead)
+        {
+          Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
+          if ((ULONG)Irp->Tail.Overlay.DriverContext[2] > Srb->QueueSortKey)
+            {
+              break;
+           }
+          ListEntry = ListEntry->Flink;
+       }
+      InsertTailList(ListEntry, (PLIST_ENTRY)&NextIrp->Tail.Overlay.DriverContext[0]);
+      DeviceExtension->PendingIrpCount++;
+      LunExtension->PendingIrpCount++;
+    }
+
+  while (DeviceExtension->Flags & IRP_FLAG_COMPLETE ||
+         (((DeviceExtension->SrbExtensionSize == 0 || DeviceExtension->CurrentSrbExtensions < DeviceExtension->MaxSrbExtensions) &&
+         DeviceExtension->PendingIrpCount > 0 &&
+         (DeviceExtension->Flags & (IRP_FLAG_NEXT|IRP_FLAG_NEXT_LU) || DeviceExtension->NextIrp == NULL))))
+    {
+      DPRINT ("RequestComplete %d, NextRequest %d, NextLuRequest %d, PendingIrpCount %d, ActiveIrpCount %d\n",
+             DeviceExtension->Flags & IRP_FLAG_COMPLETE ? 1 : 0,
+             DeviceExtension->Flags & IRP_FLAG_NEXT ? 1 : 0,
+             DeviceExtension->Flags & IRP_FLAG_NEXT_LU ? 1 : 0,
+             DeviceExtension->PendingIrpCount,
+             DeviceExtension->ActiveIrpCount);
+
+
+      if (DeviceExtension->Flags & IRP_FLAG_COMPLETE)
+        {
+         DeviceExtension->Flags &= ~IRP_FLAG_COMPLETE;
+         PrevIrp = NULL;
+         Irp = DeviceExtension->NextIrp;
+         while (Irp)
+           {
+             NextIrp = (PIRP)Irp->Tail.Overlay.DriverContext[0];
+             Srb = Irp->Tail.Overlay.DriverContext[3];
+              if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
+               {
+                  BOOLEAN CompleteThisRequest;
+                  LunExtension = Irp->Tail.Overlay.DriverContext[2];
+                 IrpStack = IoGetCurrentIrpStackLocation(Irp);
+                 OriginalSrb = IrpStack->Parameters.Scsi.Srb;
+
+                 if (Srb->SrbStatus == SRB_STATUS_BUSY)
+                   {
+                      CompleteThisRequest = FALSE;
+                     Irp->Tail.Overlay.DriverContext[3] = Srb;
+
+                     SpiRemoveActiveIrp(DeviceExtension, Irp, PrevIrp);
+                      SpiFreeSrbExtension(DeviceExtension, OriginalSrb);
+
+                      Srb->OriginalRequest = LunExtension;
+                      Irp->Tail.Overlay.DriverContext[2] = 0;
+
+                     InsertHeadList(&DeviceExtension->PendingIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
+                     DeviceExtension->PendingIrpCount++;
+                     LunExtension->PendingIrpCount++;
+                     Irp = NextIrp;
+                     continue;
+                   }
+
+                  if (OriginalSrb != Srb)
+                   {
+                     SENSE_DATA* SenseInfoBuffer;
+
+                     SenseInfoBuffer = Srb->DataBuffer;
+
+                     DPRINT("Got sense data!\n");
+
+                     DPRINT("Valid: %x\n", SenseInfoBuffer->Valid);
+                     DPRINT("ErrorCode: %x\n", SenseInfoBuffer->ErrorCode);
+                     DPRINT("SenseKey: %x\n", SenseInfoBuffer->SenseKey);
+                     DPRINT("SenseCode: %x\n", SenseInfoBuffer->AdditionalSenseCode);
+
+                     /* Copy sense data */
+                      RtlCopyMemory(OriginalSrb->SenseInfoBuffer,
+                                   SenseInfoBuffer,
+                                   sizeof(SENSE_DATA));
+                     OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+                      OriginalSrb->SrbExtension = Srb->SrbExtension;
+                     ExFreePool(Srb);
+                     CompleteThisRequest = TRUE;
+                   }
+                 else if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS &&
+                          Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
+                          Srb->SenseInfoBuffer != NULL &&
+                          Srb->SenseInfoBufferLength >= sizeof(SENSE_DATA) &&
+                          !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
+                   {
+                     DPRINT("SCSIOP_REQUEST_SENSE required!\n");
+
+                             Srb = ScsiPortInitSenseRequestSrb(OriginalSrb);
+
+                     if (Srb)
+                       {
+                         CompleteThisRequest = FALSE;
+                         Irp->Tail.Overlay.DriverContext[3] = Srb;
+                         SpiRemoveActiveIrp(DeviceExtension, Irp, PrevIrp);
+                         SpiFreeSrbExtension(DeviceExtension, OriginalSrb);
+
+                          Srb->OriginalRequest = LunExtension;
+                          Irp->Tail.Overlay.DriverContext[2] = 0;
+
+                         InsertHeadList(&DeviceExtension->PendingIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
+                         DeviceExtension->PendingIrpCount++;
+                         LunExtension->PendingIrpCount++;
+                         Irp = NextIrp;
+                         continue;
+                       }
+                     else
+                       {
+                         CompleteThisRequest = TRUE;
+                       }
+                   }
+                 else
+                   {
+                     DPRINT("Complete Request\n");
+                     CompleteThisRequest = TRUE;
+                   }
+                 if (CompleteThisRequest)
+                   {
+                     SpiRemoveActiveIrp(DeviceExtension, Irp, PrevIrp);
+                     InsertHeadList(&CompleteIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
+                      SpiFreeSrbExtension(DeviceExtension, OriginalSrb);
+                   }
+                 else
+                   {
+                     PrevIrp = Irp;
+                   }
+                 Irp = NextIrp;
+                 continue;
+               }
+             PrevIrp = Irp;
+             Irp = NextIrp;
+           }
+       }
+      if (!IsListEmpty(&CompleteIrpListHead))
+        {
+          KeReleaseSpinLockFromDpcLevel(&DeviceExtension->Lock);
+         while (!IsListEmpty(&CompleteIrpListHead))
+           {
+             ListEntry = RemoveTailList(&CompleteIrpListHead);
+             Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
+             IoCompleteRequest(Irp, IO_NO_INCREMENT);
+           }
+         KeAcquireSpinLockAtDpcLevel(&DeviceExtension->Lock);
+        }
+      if (DeviceExtension->Flags & (IRP_FLAG_NEXT|IRP_FLAG_NEXT_LU) &&
+          (DeviceExtension->SrbExtensionSize == 0 || DeviceExtension->CurrentSrbExtensions < DeviceExtension->MaxSrbExtensions))
+        {
+         BOOLEAN StartThisRequest;
+         ListEntry = DeviceExtension->PendingIrpListHead.Flink;
+         while (ListEntry != &DeviceExtension->PendingIrpListHead)
+           {
+             Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
+             ListEntry = ListEntry->Flink;
+             Srb = Irp->Tail.Overlay.DriverContext[3];
+             LunExtension = Srb->OriginalRequest;
+             if (DeviceExtension->SrbExtensionSize > 0 &&
+                 DeviceExtension->CurrentSrbExtensions >= DeviceExtension->MaxSrbExtensions)
+               {
+                 break;
+               }
+             if (LunExtension->Flags & IRP_FLAG_NEXT_LU)
+                {
+                 StartThisRequest = TRUE;
+                 LunExtension->Flags &= ~IRP_FLAG_NEXT_LU;
+                  DeviceExtension->Flags &= ~IRP_FLAG_NEXT_LU;
+               }
+             else if (DeviceExtension->Flags & IRP_FLAG_NEXT &&
+                      LunExtension->ActiveIrpCount == 0)
+               {
+                 StartThisRequest = TRUE;
+                  DeviceExtension->Flags &= ~IRP_FLAG_NEXT;
+               }
+             else
+               {
+                 StartThisRequest = FALSE;
+               }
+             if (StartThisRequest)
+               {
+                 LunExtension->PendingIrpCount--;
+                 DeviceExtension->PendingIrpCount--;
+                 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
+                  LunExtension->ActiveIrpCount++;
+                  DeviceExtension->ActiveIrpCount++;
+
+                  RemoveEntryList((PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
+                 Irp->Tail.Overlay.DriverContext[2] = LunExtension;
+                 Srb->OriginalRequest = Irp;
+                 SpiAllocateSrbExtension(DeviceExtension, Srb);
+
+                  InsertHeadList(&NextIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
+               }
+           }
+       }
+
+      if (!IsListEmpty(&NextIrpListHead))
+        {
+         while (!IsListEmpty(&NextIrpListHead))
+           {
+             ListEntry = RemoveTailList(&NextIrpListHead);
+             Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
+             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->Lock);
+
+             // Start this Irp
+             SpiStartIo(DeviceExtension, Irp);
+             KeAcquireSpinLockAtDpcLevel(&DeviceExtension->Lock);
+           }
+       }
+
+      if (!IsListEmpty(&DeviceExtension->PendingIrpListHead) &&
+         DeviceExtension->NextIrp == NULL &&
+         (DeviceExtension->SrbExtensionSize == 0 || DeviceExtension->CurrentSrbExtensions < DeviceExtension->MaxSrbExtensions))
+        {
+         ListEntry = RemoveHeadList(&DeviceExtension->PendingIrpListHead);
+          Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
+          Srb = Irp->Tail.Overlay.DriverContext[3];
+         LunExtension = Srb->OriginalRequest;
+         Irp->Tail.Overlay.DriverContext[2] = LunExtension;
+         Srb->OriginalRequest = Irp;
+
+         LunExtension->PendingIrpCount--;
+         DeviceExtension->PendingIrpCount--;
+          Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
+         LunExtension->ActiveIrpCount++;
+          DeviceExtension->ActiveIrpCount++;
+
+         SpiAllocateSrbExtension(DeviceExtension, Srb);
+          KeReleaseSpinLockFromDpcLevel(&DeviceExtension->Lock);
+
+          /* Start this irp */
+          SpiStartIo(DeviceExtension, Irp);
+         KeAcquireSpinLockAtDpcLevel(&DeviceExtension->Lock);
+        }
      }
+   KeReleaseSpinLock(&DeviceExtension->Lock, oldIrql);
 
-  NtClose(ScsiPortKey);
-  NtClose(ScsiKey);
+   DPRINT("SpiProcessRequests() done\n");
+ }
 
-  return(Status);
+static VOID
+SpiStartIo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+          IN PIRP Irp)
+{
+  PSCSI_PORT_LUN_EXTENSION LunExtension;
+  PSCSI_REQUEST_BLOCK Srb;
+
+  DPRINT("SpiStartIo() called!\n");
+
+  assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+  Srb = Irp->Tail.Overlay.DriverContext[3];
+  LunExtension = Irp->Tail.Overlay.DriverContext[2];
+
+  Irp->IoStatus.Status = STATUS_SUCCESS;
+  Irp->IoStatus.Information = Srb->DataTransferLength;
+
+  SpiAddActiveIrp(DeviceExtension, Irp);
+
+  if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
+                             ScsiPortStartPacket,
+                              Srb))
+    {
+      DPRINT1("Synchronization failed!\n");
+      DPRINT1("Irp %x, Srb->Function %02x, Srb->Cdb[0] %02x, Srb->SrbStatus %02x\n", Irp, Srb->Function, Srb->Cdb[0], Srb->SrbStatus);
+      ScsiPortNotification(RequestComplete,
+                          &DeviceExtension->MiniPortDeviceExtension,
+                          Srb);
+    }
+
+  DPRINT("SpiStartIo() done\n");
 }
-#endif
+
+
 
 /* EOF */