Implemented IOCTL_SCSI_MINIPORT.
[reactos.git] / reactos / drivers / storage / scsiport / scsiport.c
index 093f41c..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.37 2003/09/25 23:23:21 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"
 
-//#define USE_DEVICE_QUEUES
-
 /* TYPES *********************************************************************/
 
 #define IRP_FLAG_COMPLETE      0x00000001
 #define IRP_FLAG_NEXT          0x00000002
 #define IRP_FLAG_NEXT_LU       0x00000004
 
-
 /* GLOBALS *******************************************************************/
 
+static ULONG InternalDebugLevel = 0;
+
+static VOID
+SpiProcessRequests(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                  PIRP NextIrp);
+
+static VOID
+SpiStartIo(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+          PIRP Irp);
+
 static BOOLEAN
 SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
                     IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
                     IN ULONG BusNumber,
-                    IN OUT PULONG NextDeviceNumber,
-                    IN OUT PULONG NextFunctionNumber);
+                    IN OUT PPCI_SLOT_NUMBER NextSlotNumber);
 
 static NTSTATUS STDCALL
 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
@@ -70,24 +77,9 @@ 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 NTSTATUS
-ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
-                        IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
-                        IN ULONG PortCount,
-                        IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension);
 
 static PSCSI_PORT_LUN_EXTENSION
 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
@@ -95,14 +87,23 @@ SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
                         IN UCHAR TargetId,
                         IN UCHAR Lun);
 
+static VOID
+SpiRemoveLunExtension (IN PSCSI_PORT_LUN_EXTENSION LunExtension);
+
 static PSCSI_PORT_LUN_EXTENSION
 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
                    IN UCHAR PathId,
                    IN UCHAR TargetId,
                    IN UCHAR Lun);
 
+static NTSTATUS
+SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
+               IN OUT PSCSI_REQUEST_BLOCK Srb,
+               IN OUT PIO_STATUS_BLOCK IoStatusBlock,
+               IN OUT PKEVENT Event);
+
 static VOID
-SpiInquirePort (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
+SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
 
 static ULONG
 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
@@ -113,23 +114,34 @@ 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 *****************************************************************/
 
@@ -197,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);
@@ -220,14 +230,56 @@ ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
                        IN UCHAR Lun,
                        IN UCHAR SrbStatus)
 {
-  DPRINT("ScsiPortCompleteRequest()\n");
-  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)
 {
@@ -323,7 +375,7 @@ ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
   ULONG AddressSpace;
   PVOID MappedAddress;
 
-  DPRINT("ScsiPortGetDeviceBase() called\n");
+  DPRINT ("ScsiPortGetDeviceBase() called\n");
 
   AddressSpace = (ULONG)InIoSpace;
   if (HalTranslateBusAddress(BusType,
@@ -339,7 +391,7 @@ ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
 
   MappedAddress = MmMapIoSpace(TranslatedAddress,
                               NumberOfBytes,
-                              FALSE);
+                              MmNonCached);
 
   DeviceBase = ExAllocatePool(NonPagedPool,
                              sizeof(SCSI_PORT_DEVICE_BASE));
@@ -414,8 +466,10 @@ ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
 {
   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);
@@ -424,36 +478,83 @@ ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
                                      SCSI_PORT_DEVICE_EXTENSION,
                                      MiniPortDeviceExtension);
 
-  *Length = 0;
-
+  if (Length != NULL)
+    {
+      *Length = 0;
+    }
   if (Srb == NULL)
     {
-      if ((ULONG_PTR)DeviceExtension->VirtualAddress > (ULONG_PTR)VirtualAddress)
+      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)
        {
-         PhysicalAddress.QuadPart = 0ULL;
-         return PhysicalAddress;
+         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;
+           }
        }
 
-      Offset = (ULONG_PTR)VirtualAddress - (ULONG_PTR)DeviceExtension->VirtualAddress;
-      if (Offset >= DeviceExtension->CommonBufferLength)
+      PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
+      if (PhysicalAddress.QuadPart == 0LL)
        {
-         PhysicalAddress.QuadPart = 0ULL;
+         CHECKPOINT;
          return PhysicalAddress;
        }
 
-      PhysicalAddress.QuadPart =
-       DeviceExtension->PhysicalAddress.QuadPart + (ULONGLONG)Offset;
-      BufferLength = DeviceExtension->CommonBufferLength - Offset;
+      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);
+       }
     }
-  else
+  if (Length != NULL)
     {
-      /* FIXME */
-      DPRINT1("Srb != NULL is not implemented yet!\n");
-      UNIMPLEMENTED;
+      *Length = BufferLength;
     }
-
-  *Length = BufferLength;
-
+  DPRINT("Address %I64x, Length %d\n", PhysicalAddress.QuadPart, BufferLength);
   return PhysicalAddress;
 }
 
@@ -462,14 +563,15 @@ ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
  * @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)
 {
-  DPRINT("ScsiPortGetSrb()\n");
+  DPRINT1("ScsiPortGetSrb() unimplemented\n");
   UNIMPLEMENTED;
+  return NULL;
 }
 
 
@@ -526,9 +628,31 @@ ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
          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;
+  DeviceExtension->CommonBufferLength =
+    NumberOfBytes + PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * DeviceExtension->MaxSrbExtensions);
   DeviceExtension->VirtualAddress =
     HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
                            DeviceExtension->CommonBufferLength,
@@ -541,7 +665,8 @@ ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
       return NULL;
     }
 
-  return DeviceExtension->VirtualAddress;
+  return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress +
+                 PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * DeviceExtension->MaxSrbExtensions));
 }
 
 
@@ -609,24 +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;
-  PSCSI_PORT_DEVICE_EXTENSION RealDeviceExtension;
+//  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 NextBusNumber = 0;
-  ULONG NextDeviceNumber = 0;
-  ULONG NextFunctionNumber = 0;
+  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) ||
@@ -634,96 +795,160 @@ ScsiPortInitialize(IN PVOID Argument1,
       (HwInitializationData->HwResetBus == NULL))
     return(STATUS_INVALID_PARAMETER);
 
-  DriverObject->DriverStartIo = ScsiPortStartIo;
-  DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)ScsiPortCreateClose;
-  DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)ScsiPortCreateClose;
-  DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)ScsiPortDeviceControl;
-  DriverObject->MajorFunction[IRP_MJ_SCSI] = (PDRIVER_DISPATCH)ScsiPortDispatchScsi;
-
+  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->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
-  PseudoDeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
-  PseudoDeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
-
-  PortConfig = &PseudoDeviceExtension->PortConfig;
-
-  PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
-  PortConfig->SystemIoBusNumber = 0;
-  PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
-//  PortConfig->BusInterruptLevel = oz_dev_pci_conf_inb (pciconfp, OZ_DEV_PCI_CONF_B_INTLINE);
-//  PortConfig->BusInterruptVector = ;
-  PortConfig->InterruptMode =
-   (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
-  PortConfig->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
-  PortConfig->NumberOfPhysicalBreaks = SP_UNINITIALIZED_VALUE;
-  PortConfig->DmaChannel = SP_UNINITIALIZED_VALUE;
-  PortConfig->DmaPort = SP_UNINITIALIZED_VALUE;
-//  PortConfig->DmaWidth =
-//  PortConfig->DmaSpeed =
-//  PortConfig->AlignmentMask =
-  PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
-//  PortConfig->NumberOfBuses =
-
-  for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
-    PortConfig->InitiatorBusId[i] = 255;
-
-//  PortConfig->ScatterGather =
-//  PortConfig->Master =
-//  PortConfig->CachesData =
-//  PortConfig->AdapterScansDown =
-  PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
-  PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
-//  PortConfig->Dma32BitAddresses =
-//  PortConfig->DemandMode =
-  PortConfig->MapBuffers = HwInitializationData->MapBuffers;
-  PortConfig->NeedPhysicalAddresses = HwInitializationData->NeedPhysicalAddresses;
-  PortConfig->TaggedQueuing = HwInitializationData->TaggedQueuing;
-  PortConfig->AutoRequestSense = HwInitializationData->AutoRequestSense;
-  PortConfig->MultipleRequestPerLu = HwInitializationData->MultipleRequestPerLu;
-  PortConfig->ReceiveEvent = HwInitializationData->ReceiveEvent;
-//  PortConfig->RealModeInitialized =
-//  PortConfig->BufferAccessScsiPortControlled =
-  PortConfig->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS;
-//  PortConfig->MaximumNumberOfLogicalUnits = SCSI_MAXIMUM_LOGICAL_UNITS;
-  PortConfig->SlotNumber = 0;
-
-  PortConfig->AccessRanges =
-    ExAllocatePool(PagedPool,
-                  sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
-
-
-  MaxBus = (PortConfig->AdapterInterfaceType == PCIBus) ? 8 : 1;
+  DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
+    HwInitializationData->DeviceExtensionSize;
+  PortConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION) +
+    HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE);
+
 
+  MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
   DPRINT("MaxBus: %lu\n", MaxBus);
 
+  PortDeviceObject = NULL;
+  BusNumber = 0;
+  SlotNumber.u.AsULONG = 0;
   while (TRUE)
     {
-      DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
+      /* Create a unicode device name */
+      swprintf (NameBuffer,
+               L"\\Device\\ScsiPort%lu",
+               SystemConfig->ScsiPortCount);
+      RtlInitUnicodeString (&DeviceName,
+                           NameBuffer);
+
+      DPRINT("Creating device: %wZ\n", &DeviceName);
+
+      /* Create the port device */
+      Status = IoCreateDevice (DriverObject,
+                              DeviceExtensionSize,
+                              &DeviceName,
+                              FILE_DEVICE_CONTROLLER,
+                              0,
+                              FALSE,
+                              &PortDeviceObject);
+      if (!NT_SUCCESS(Status))
+       {
+         DbgPrint ("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
+         PortDeviceObject = NULL;
+         goto ByeBye;
+       }
+
+      DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
+
+      /* 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;
 
-      InitializeListHead(&PseudoDeviceExtension->DeviceBaseListHead);
+      /* Initialize the device base list */
+      InitializeListHead (&DeviceExtension->DeviceBaseListHead);
 
-//      RtlZeroMemory(AccessRanges,
-//                 sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
+      /* Initialize the irp lists */
+      InitializeListHead (&DeviceExtension->PendingIrpListHead);
+      DeviceExtension->NextIrp = NULL;
+      DeviceExtension->PendingIrpCount = 0;
+      DeviceExtension->ActiveIrpCount = 0;
 
-      PseudoDeviceExtension->AdapterObject = NULL;
-      PseudoDeviceExtension->MapRegisterCount = 0;
-      PseudoDeviceExtension->PhysicalAddress.QuadPart = 0ULL;
-      PseudoDeviceExtension->VirtualAddress = NULL;
-      PseudoDeviceExtension->CommonBufferLength = 0;
+      /* Initialize LUN-Extension list */
+      InitializeListHead (&DeviceExtension->LunExtensionListHead);
 
-      RtlZeroMemory(PseudoDeviceExtension->MiniPortDeviceExtension,
-                   PseudoDeviceExtension->MiniPortExtensionSize);
+      /* 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) &&
@@ -738,84 +963,241 @@ ScsiPortInitialize(IN PVOID Argument1,
                 HwInitializationData->DeviceId);
 
          if (!SpiGetPciConfigData (HwInitializationData,
-                                   &PseudoDeviceExtension->PortConfig,
-                                   NextBusNumber,
-                                   &NextDeviceNumber,
-                                   &NextFunctionNumber))
+                                   PortConfig,
+                                   BusNumber,
+                                   &SlotNumber))
            {
-             ExFreePool(PortConfig->AccessRanges);
-             ExFreePool(PseudoDeviceExtension);
-
-             return STATUS_UNSUCCESSFUL;
+             Status = STATUS_UNSUCCESSFUL;
+             goto ByeBye;
            }
        }
 
       /* Note: HwFindAdapter is called once for each bus */
       Again = FALSE;
-      Result = (HwInitializationData->HwFindAdapter)(&PseudoDeviceExtension->MiniPortDeviceExtension,
+      DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
+      Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension,
                                                     HwContext,
-                                                    0, /* BusInformation */
-                                                    "",        /* ArgumentString */
-                                                    &PseudoDeviceExtension->PortConfig,
+                                                    0,  /* BusInformation */
+                                                    "", /* ArgumentString */
+                                                    PortConfig,
                                                     &Again);
       DPRINT("HwFindAdapter() Result: %lu  Again: %s\n",
             Result, (Again) ? "True" : "False");
 
       if (Result == SP_RETURN_FOUND)
        {
-         DPRINT("ScsiPortInitialize(): Found HBA!\n");
+         DPRINT("ScsiPortInitialize(): Found HBA! (%x)\n", PortConfig->BusInterruptVector);
 
-         Status = ScsiPortCreatePortDevice(DriverObject,
-                                           PseudoDeviceExtension,
-                                           SystemConfig->ScsiPortCount,
-                                           &RealDeviceExtension);
+#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);
+
+#endif
+
+          if (DeviceExtension->VirtualAddress == NULL && DeviceExtension->SrbExtensionSize)
+           {
+             ScsiPortGetUncachedExtension(&DeviceExtension->MiniPortDeviceExtension,
+                                          PortConfig,
+                                          0);
+           }
 
+         /* 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("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status);
+             DbgPrint("Could not connect interrupt %d\n",
+                      PortConfig->BusInterruptVector);
+             goto ByeBye;
+           }
+
+         if (!(HwInitializationData->HwInitialize)(&DeviceExtension->MiniPortDeviceExtension))
+           {
+             DbgPrint("HwInitialize() failed!");
+             Status = STATUS_UNSUCCESSFUL;
+             goto ByeBye;
+           }
 
-             ExFreePool(PortConfig->AccessRanges);
-             ExFreePool(PseudoDeviceExtension);
+         /* 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;
+           }
 
-             return(Status);
+         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;
            }
 
-         /* Get inquiry data */
-         SpiInquirePort (RealDeviceExtension);
+         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 (RealDeviceExtension,
+         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 */
-         SystemConfig->AtDiskPrimaryAddressClaimed = PortConfig->AtdiskPrimaryClaimed;
-         SystemConfig->AtDiskSecondaryAddressClaimed = PortConfig->AtdiskSecondaryClaimed;
+         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;
-         NextBusNumber++;
-         NextDeviceNumber = 0;
-         NextFunctionNumber = 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;
 }
 
 
@@ -848,6 +1230,8 @@ ScsiPortLogError(IN PVOID HwDeviceExtension,
   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,
@@ -891,11 +1275,6 @@ 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)
@@ -907,13 +1286,14 @@ ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
          Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
 
          DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
-         DeviceExtension->IrpFlags |= IRP_FLAG_COMPLETE;
+         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:
@@ -921,17 +1301,24 @@ ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
          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);
 
-         DPRINT1 ("Notify: NextLuRequest(PathId %u  TargetId %u  Lun %u)\n",
+         DPRINT ("Notify: NextLuRequest(PathId %u  TargetId %u  Lun %u)\n",
                   PathId, TargetId, Lun);
-         /* FIXME: Implement it! */
-
-//       DeviceExtension->IrpFlags |= IRP_FLAG_NEXT_LU;
 
+          LunExtension = SpiGetLunExtension(DeviceExtension,
+                                           PathId,
+                                           TargetId,
+                                           Lun);
+         if (LunExtension)
+           {
+             DeviceExtension->Flags |= IRP_FLAG_NEXT_LU;
+             LunExtension->Flags |= IRP_FLAG_NEXT_LU;
+           }
        }
        break;
 
@@ -944,6 +1331,16 @@ ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
        DPRINT1 ("Unsupported notification %lu\n", NotificationType);
        break;
     }
+  if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
+    {
+      IoRequestDpc(DeviceExtension->DeviceObject,
+                   NULL,
+                  DeviceExtension);
+    }
+  else
+    {
+      SpiProcessRequests(DeviceExtension, NULL);
+    }
 
   va_end(ap);
 }
@@ -994,8 +1391,7 @@ static BOOLEAN
 SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
                     IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
                     IN ULONG BusNumber,
-                    IN OUT PULONG NextDeviceNumber,
-                    IN OUT PULONG NextFunctionNumber)
+                    IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
 {
   PCI_COMMON_CONFIG PciConfig;
   PCI_SLOT_NUMBER SlotNumber;
@@ -1004,26 +1400,28 @@ SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
   ULONG FunctionNumber;
   CHAR VendorIdString[8];
   CHAR DeviceIdString[8];
+  ULONG i;
+  ULONG RangeLength;
 
-  DPRINT1("SpiGetPciConfiguration() called\n");
+  DPRINT ("SpiGetPciConfiguration() called\n");
 
-  if (*NextFunctionNumber > 7)
+  if (NextSlotNumber->u.bits.FunctionNumber >= PCI_MAX_FUNCTION)
     {
-      *NextFunctionNumber = 0;
-      (*NextDeviceNumber)++;
+      NextSlotNumber->u.bits.FunctionNumber = 0;
+      NextSlotNumber->u.bits.DeviceNumber++;
     }
 
-  if (*NextDeviceNumber > 31)
+  if (NextSlotNumber->u.bits.DeviceNumber >= PCI_MAX_DEVICES)
     {
-      *NextDeviceNumber = 0;
+      NextSlotNumber->u.bits.DeviceNumber = 0;
       return FALSE;
     }
 
-  for (DeviceNumber = *NextDeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
+  for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
     {
       SlotNumber.u.bits.DeviceNumber = DeviceNumber;
 
-      for (FunctionNumber = *NextFunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
+      for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
        {
          SlotNumber.u.bits.FunctionNumber = FunctionNumber;
 
@@ -1050,17 +1448,72 @@ SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
          if (!_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) &&
              !_strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
            {
-             DPRINT1 ("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
-                      PciConfig.VendorID,
-                      PciConfig.DeviceID,
-                      BusNumber,
-                      SlotNumber.u.bits.DeviceNumber,
-                      SlotNumber.u.bits.FunctionNumber);
-
+             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;
 
-             *NextDeviceNumber = DeviceNumber;
-             *NextFunctionNumber = FunctionNumber + 1;
+             /* 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;
            }
@@ -1071,10 +1524,10 @@ SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
              break;
            }
        }
-       *NextFunctionNumber = 0;
+       NextSlotNumber->u.bits.FunctionNumber = 0;
     }
 
-  DPRINT1("No device found\n");
+  DPRINT ("No device found\n");
 
   return FALSE;
 }
@@ -1098,9 +1551,6 @@ SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
  *     Irp
  *             Pointer to an IRP.
  *
- *     ...
-               Additional output data (see printf()).
- *
  * RETURN VALUE
  *     Status.
  */
@@ -1192,46 +1642,28 @@ ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
     {
       case SRB_FUNCTION_EXECUTE_SCSI:
       case SRB_FUNCTION_IO_CONTROL:
-#ifdef USE_DEVICE_QUEUES
-       if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
-         {
-           IoStartPacket (DeviceObject, Irp, NULL, NULL);
-         }
-       else
-         {
-           KIRQL oldIrql;
-
-           KeRaiseIrql (DISPATCH_LEVEL,
-                        &oldIrql);
-
-           if (!KeInsertByKeyDeviceQueue (&LunExtension->DeviceQueue,
-                                          &Irp->Tail.Overlay.DeviceQueueEntry,
-                                          Srb->QueueSortKey))
-             {
-               Srb->SrbStatus = SRB_STATUS_SUCCESS;
-               IoStartPacket (DeviceObject, Irp, NULL, NULL);
-             }
-
-           KeLowerIrql (oldIrql);
-         }
-#else
-        IoStartPacket (DeviceObject, Irp, NULL, NULL);
-#endif
+        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:
-       DPRINT("  SRB_FUNCTION_CLAIM_DEVICE\n");
+       DPRINT ("  SRB_FUNCTION_CLAIM_DEVICE\n");
 
-       /* Reference device object and keep the pointer */
+       /* Reference device object and keep the device object */
        ObReferenceObject(DeviceObject);
        LunExtension->DeviceObject = DeviceObject;
        LunExtension->DeviceClaimed = TRUE;
@@ -1239,24 +1671,14 @@ ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
        break;
 
       case SRB_FUNCTION_RELEASE_DEVICE:
-       {
-         PSCSI_PORT_LUN_EXTENSION LunExtension;
-
-         DPRINT("  SRB_FUNCTION_RELEASE_DEVICE\n");
-         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)
-           {
-             /* Dereference device object */
-             ObDereferenceObject(LunExtension->DeviceObject);
-             LunExtension->DeviceObject = NULL;
-             LunExtension->DeviceClaimed = FALSE;
-           }
-       }
+       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:
@@ -1297,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;
 
 
@@ -1315,7 +1737,7 @@ ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
          DPRINT("  IOCTL_SCSI_GET_DUMP_POINTERS\n");
          DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
          DumpPointers->DeviceObject = DeviceObject;
-         
+
          Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
        }
        break;
@@ -1342,324 +1764,229 @@ ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
          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 VOID STDCALL
-ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
-               IN PIRP Irp)
+static NTSTATUS STDCALL
+SpiCompletion(IN PDEVICE_OBJECT DeviceObject,
+             IN PIRP Irp,
+             IN PVOID Context)
 {
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  PIO_STACK_LOCATION IrpStack;
   PSCSI_REQUEST_BLOCK Srb;
-  KIRQL oldIrql;
-  BOOLEAN Result;
-
-  DPRINT("ScsiPortStartIo() called!\n");
+  
+  DPRINT("SpiCompletion(DeviceObject %x, Irp %x, Context %x)\n",
+         DeviceObject, Irp, Context);
 
-  DeviceExtension = DeviceObject->DeviceExtension;
-  IrpStack = IoGetCurrentIrpStackLocation(Irp);
-
-  DPRINT("DeviceExtension %p\n", DeviceExtension);
+  Srb = (PSCSI_REQUEST_BLOCK)Context;
+  Irp->IoStatus.Information = 0;
 
-  if (IrpStack->MajorFunction != IRP_MJ_SCSI)
+  switch (SRB_STATUS(Srb->SrbStatus))
     {
-      DPRINT("No IRP_MJ_SCSI!\n");
-      Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
-      Irp->IoStatus.Information = 0;
-      IoCompleteRequest (Irp,
-                        IO_NO_INCREMENT);
-      IoStartNextPacket (DeviceObject,
-                        FALSE);
-      return;
-    }
-
-  Srb = IrpStack->Parameters.Scsi.Srb;
+      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;
 
-  LunExtension = SpiGetLunExtension(DeviceExtension,
-                                   Srb->PathId,
-                                   Srb->TargetId,
-                                   Srb->Lun);
-  if (LunExtension == NULL)
-    {
-      DPRINT("No IRP_MJ_SCSI!\n");
-      Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
-      Irp->IoStatus.Information = 0;
-      IoCompleteRequest (Irp,
-                        IO_NO_INCREMENT);
-      IoStartNextPacket (DeviceObject,
-                        FALSE);
-      return;
-    }
+      case SRB_STATUS_NO_DEVICE:
+        Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
+        break;
 
-  Irp->IoStatus.Status = STATUS_SUCCESS;
-  Irp->IoStatus.Information = Srb->DataTransferLength;
+      case SRB_STATUS_BUSY:
+       Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
+        break;
 
-  DeviceExtension->CurrentIrp = Irp;
+      case SRB_STATUS_DATA_OVERRUN:
+       Irp->IoStatus.Status = STATUS_DATA_OVERRUN;
+        Irp->IoStatus.Information = Srb->DataTransferLength;
+        break;
 
-  if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
-                             ScsiPortStartPacket,
-                             DeviceExtension))
-    {
-      DPRINT("Synchronization failed!\n");
+      case SRB_STATUS_INVALID_REQUEST:
+        Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+        break;
 
-      Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
-      Irp->IoStatus.Information = 0;
-      IoCompleteRequest(Irp,
-                       IO_NO_INCREMENT);
-      IoStartNextPacket(DeviceObject,
-                       FALSE);
+      default:
+       Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
+       break;
     }
 
-  KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
-  if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
-    {
-      DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
-      IoCompleteRequest(Irp,
-                       IO_NO_INCREMENT);
-    }
+  ExFreePool(Srb);
 
-  if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
-    {
-      DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
-      KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
-      IoStartNextPacket(DeviceObject,
-                       FALSE);
-    }
-  else
+  if (Irp->PendingReturned)
     {
-      KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
+      IoMarkIrpPending (Irp);
     }
-
-  DPRINT("ScsiPortStartIo() done\n");
+  return Irp->IoStatus.Status;
 }
 
-
-static BOOLEAN STDCALL
-ScsiPortStartPacket(IN OUT PVOID Context)
+static NTSTATUS
+SpiScsiMiniport(IN PDEVICE_OBJECT DeviceObject,
+               IN PIRP Irp)
 {
   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+  PSRB_IO_CONTROL SrbIoControl;
   PIO_STACK_LOCATION IrpStack;
   PSCSI_REQUEST_BLOCK Srb;
+  PSCSI_PORT_LUN_EXTENSION LunExtension;
+  
+  DPRINT("SpiScsiMiniport(DeviceObject %x, Irp %x)\n",
+         DeviceObject, Irp);
 
-  DPRINT("ScsiPortStartPacket() called\n");
-
-  DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context;
+  DeviceExtension = DeviceObject->DeviceExtension;
+  SrbIoControl = (PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer;
 
-  IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
-  Srb = IrpStack->Parameters.Scsi.Srb;
+  IrpStack = IoGetCurrentIrpStackLocation(Irp);
+  if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1)
+    {
+      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;
+    }
 
-  return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
-                                   Srb));
+  Srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
+  if (Srb == NULL)
+    {
+      Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_INSUFFICIENT_RESOURCES;
+    }
+  RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
+  Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+  Srb->OriginalRequest = Irp;
+  Srb->Function = SRB_FUNCTION_IO_CONTROL;
+  Srb->DataBuffer = (PVOID)SrbIoControl;
+  Srb->DataTransferLength = sizeof(SRB_IO_CONTROL) + SrbIoControl->Length;
+
+  /* We using the first extension from the list. The miniport driver is responsible to find the correct device. */
+  LunExtension = CONTAINING_RECORD(DeviceExtension->LunExtensionListHead.Flink,
+                                  SCSI_PORT_LUN_EXTENSION,
+                                  List);
+  Srb->PathId = LunExtension->PathId;
+  Srb->TargetId = LunExtension->TargetId;
+  Srb->Lun = LunExtension->Lun;
+  
+  IrpStack = IoGetNextIrpStackLocation(Irp);
+  
+  IrpStack->MajorFunction = IRP_MJ_SCSI;
+  IrpStack->Parameters.Scsi.Srb = Srb;
+
+  IoSetCompletionRoutine(Irp,
+                        SpiCompletion,
+                        Srb,
+                        TRUE,
+                        TRUE,
+                        TRUE);
+
+  return IoCallDriver(DeviceObject, Irp);
 }
 
-
-/**********************************************************************
- * NAME                                                        INTERNAL
- *     ScsiPortCreatePortDevice
- *
- * DESCRIPTION
- *     Creates and initializes a SCSI port device object.
- *
- * RUN LEVEL
- *     PASSIVE_LEVEL
- *
- * ARGUMENTS
- *     DriverObject
- *             ...
- *
- *     PseudoDeviceExtension
- *             ...
- *
- *     PortNumber
- *             ...
- *
- * RETURNS
- *     NTSTATUS
- */
-
-static NTSTATUS
-ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
-                        IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
-                        IN ULONG PortNumber,
-                        IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension)
+static VOID
+SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                       PSCSI_REQUEST_BLOCK Srb)
 {
-  PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension;
-  PIO_SCSI_CAPABILITIES PortCapabilities;
-  PDEVICE_OBJECT PortDeviceObject;
-  WCHAR NameBuffer[80];
-  UNICODE_STRING DeviceName;
-  WCHAR DosNameBuffer[80];
-  UNICODE_STRING DosDeviceName;
-  NTSTATUS Status;
-  ULONG AccessRangeSize;
-  ULONG MappedIrq;
-  KIRQL Dirql;
-  KAFFINITY Affinity;
-
-  DPRINT("ScsiPortCreatePortDevice() called\n");
-
-  *RealDeviceExtension = NULL;
-
-  MappedIrq = HalGetInterruptVector(PseudoDeviceExtension->PortConfig.AdapterInterfaceType,
-                                   PseudoDeviceExtension->PortConfig.SystemIoBusNumber,
-                                   PseudoDeviceExtension->PortConfig.BusInterruptLevel,
-                                   PseudoDeviceExtension->PortConfig.BusInterruptVector,
-                                   &Dirql,
-                                   &Affinity);
+  ULONG index;
 
-  /* Create a unicode device name */
-  swprintf(NameBuffer,
-          L"\\Device\\ScsiPort%lu",
-          PortNumber);
-  RtlInitUnicodeString(&DeviceName,
-                      NameBuffer);
+  DPRINT("SpiAllocateSrbExtension\n");
 
-  DPRINT("Creating device: %wZ\n", &DeviceName);
+  DPRINT("DeviceExtension->VirtualAddress %x, DeviceExtension->SrbExtensionSize %x\n",
+         DeviceExtension->VirtualAddress, DeviceExtension->SrbExtensionSize);
 
-  /* Create the port device */
-  Status = IoCreateDevice(DriverObject,
-                         PseudoDeviceExtension->Length,
-                         &DeviceName,
-                         FILE_DEVICE_CONTROLLER,
-                         0,
-                         FALSE,
-                         &PortDeviceObject);
-  if (!NT_SUCCESS(Status))
+  Srb->SrbExtension = NULL;
+  if (DeviceExtension->VirtualAddress != NULL &&
+      DeviceExtension->SrbExtensionSize > 0)
     {
-      DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
-      return(Status);
+      index = RtlFindClearBitsAndSet(&DeviceExtension->SrbExtensionAllocMap, 1, 0);
+      if (index != 0xffffffff)
+        {
+         DeviceExtension->CurrentSrbExtensions++;
+          Srb->SrbExtension = (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + index * DeviceExtension->SrbExtensionSize);
+       }
     }
+  DPRINT("%x\n", Srb->SrbExtension);
+}
 
-  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);
+static VOID
+SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                   PSCSI_REQUEST_BLOCK Srb)
+{
+  ULONG index;
 
-  /* Copy device base list */
-  if (IsListEmpty(&PseudoDeviceExtension->DeviceBaseListHead))
-    {
-      InitializeListHead(&PortDeviceExtension->DeviceBaseListHead);
-    }
-  else
+  if (DeviceExtension->VirtualAddress != NULL &&
+      DeviceExtension->SrbExtensionSize > 0 &&
+      Srb->SrbExtension != NULL)
     {
-      PseudoDeviceExtension->DeviceBaseListHead.Flink =
-       PortDeviceExtension->DeviceBaseListHead.Flink;
-      PseudoDeviceExtension->DeviceBaseListHead.Blink =
-       PortDeviceExtension->DeviceBaseListHead.Blink;
-      PortDeviceExtension->DeviceBaseListHead.Blink->Flink =
-       &PortDeviceExtension->DeviceBaseListHead;
-      PortDeviceExtension->DeviceBaseListHead.Flink->Blink =
-       &PortDeviceExtension->DeviceBaseListHead;
+      index = ((ULONG_PTR)Srb->SrbExtension - (ULONG_PTR)DeviceExtension->VirtualAddress) / DeviceExtension->SrbExtensionSize;
+      RtlClearBits(&DeviceExtension->SrbExtensionAllocMap, index, 1);
+      DeviceExtension->CurrentSrbExtensions--;
     }
+  Srb->SrbExtension = NULL;
+}
 
-  PortDeviceExtension->DeviceObject = PortDeviceObject;
-  PortDeviceExtension->PortNumber = PortNumber;
-
-  /* Initialize the spin lock in the controller extension */
-  KeInitializeSpinLock(&PortDeviceExtension->IrpLock);
-  KeInitializeSpinLock(&PortDeviceExtension->SpinLock);
-
-  /* Register an interrupt handler for this device */
-  Status = IoConnectInterrupt(&PortDeviceExtension->Interrupt,
-                             ScsiPortIsr,
-                             PortDeviceExtension,
-                             &PortDeviceExtension->SpinLock,
-                             MappedIrq,
-                             Dirql,
-                             Dirql,
-                             PortDeviceExtension->PortConfig.InterruptMode,
-                             TRUE,
-                             Affinity,
-                             FALSE);
-  if (!NT_SUCCESS(Status))
-    {
-      DbgPrint("Could not Connect Interrupt %d\n",
-              PortDeviceExtension->PortConfig.BusInterruptVector);
-      IoDeleteDevice(PortDeviceObject);
-      return(Status);
-    }
 
-  /* 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 / PAGE_SIZE;
-  PortCapabilities->SupportedAsynchronousEvents = 0; /* FIXME */
-  PortCapabilities->AlignmentMask =
-    PortDeviceExtension->PortConfig.AlignmentMask;
-  PortCapabilities->TaggedQueuing =
-    PortDeviceExtension->PortConfig.TaggedQueuing;
-  PortCapabilities->AdapterScansDown =
-    PortDeviceExtension->PortConfig.AdapterScansDown;
-  PortCapabilities->AdapterUsesPio = TRUE; /* FIXME */
-
-  /* Initialize LUN-Extension list */
-  InitializeListHead(&PortDeviceExtension->LunExtensionListHead);
-
-  DPRINT("DeviceExtension %p\n", PortDeviceExtension);
-
-  /* FIXME: Copy more configuration data? */
-
-
-  /* Create the dos device link */
-  swprintf(DosNameBuffer,
-          L"\\??\\Scsi%lu:",
-          PortNumber);
-  RtlInitUnicodeString(&DosDeviceName,
-                      DosNameBuffer);
-
-  IoCreateSymbolicLink(&DosDeviceName,
-                      &DeviceName);
-
-  *RealDeviceExtension = PortDeviceExtension;
-
-  DPRINT("ScsiPortCreatePortDevice() done\n");
+static BOOLEAN STDCALL
+ScsiPortStartPacket(IN OUT PVOID Context)
+{
+  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+  PSCSI_REQUEST_BLOCK Srb;
+  PIRP Irp;
+  PIO_STACK_LOCATION IrpStack;
 
-  return(STATUS_SUCCESS);
+  DPRINT("ScsiPortStartPacket(Context %x) called\n", Context);
+
+  Srb = (PSCSI_REQUEST_BLOCK)Context;
+  Irp = (PIRP)Srb->OriginalRequest;
+  IrpStack = IoGetCurrentIrpStackLocation(Irp);
+  DeviceExtension = IrpStack->DeviceObject->DeviceExtension;
+
+  return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
+                                   Srb));
 }
 
 
@@ -1696,12 +2023,36 @@ SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
   LunExtension->TargetId = TargetId;
   LunExtension->Lun = Lun;
 
-  KeInitializeDeviceQueue (&LunExtension->DeviceQueue);
+  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,
@@ -1737,68 +2088,202 @@ SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
 }
 
 
-static VOID
-SpiInquirePort(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+static NTSTATUS
+SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
+               IN OUT PSCSI_REQUEST_BLOCK Srb,
+               IN OUT PIO_STATUS_BLOCK IoStatusBlock,
+               IN OUT PKEVENT Event)
 {
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  SCSI_REQUEST_BLOCK Srb;
-  ULONG Bus;
-  ULONG Target;
-  ULONG Lun;
-  BOOLEAN Result;
+  PIO_STACK_LOCATION IrpStack;
+  PIRP Irp;
+  NTSTATUS Status;
 
-  DPRINT("SpiInquirePort() called\n");
+  DPRINT ("SpiSendInquiry() called\n");
 
-  DeviceExtension->Initializing = TRUE;
 
-  RtlZeroMemory(&Srb,
-               sizeof(SCSI_REQUEST_BLOCK));
-  Srb.SrbFlags = SRB_FLAGS_DATA_IN;
-  Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
-  Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
-  Srb.DataTransferLength = 256;
-  Srb.Cdb[0] = SCSIOP_INQUIRY;
+  KeInitializeEvent (Event,
+                    NotificationEvent,
+                    FALSE);
 
-  for (Bus = 0; Bus < DeviceExtension->PortConfig.NumberOfBuses; Bus++)
+  Irp = IoBuildDeviceIoControlRequest (IOCTL_SCSI_EXECUTE_OUT,
+                                      DeviceObject,
+                                      NULL,
+                                      0,
+                                      Srb->DataBuffer,
+                                      Srb->DataTransferLength,
+                                      TRUE,
+                                      Event,
+                                      IoStatusBlock);
+  if (Irp == NULL)
     {
-      Srb.PathId = Bus;
+      DPRINT("IoBuildDeviceIoControlRequest() failed\n");
+      return STATUS_INSUFFICIENT_RESOURCES;
+    }
 
-      for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
-       {
-         Srb.TargetId = Target;
+  /* Attach Srb to the Irp */
+  IrpStack = IoGetNextIrpStackLocation (Irp);
+  IrpStack->Parameters.Scsi.Srb = Srb;
+  Srb->OriginalRequest = Irp;
 
-         for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
-           {
-             Srb.Lun = Lun;
-             Srb.SrbStatus = SRB_STATUS_SUCCESS;
+  /* Call the driver */
+  Status = IoCallDriver (DeviceObject,
+                        Irp);
 
-             Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
-                                                 &Srb);
-             DPRINT("Result %s  Srb.SrbStatus %lx\n", (Result) ? "TRUE" : "FALSE", Srb.SrbStatus);
+  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;
 
-             if (Result == TRUE && Srb.SrbStatus == SRB_STATUS_SUCCESS)
+  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)
+    {
+      return;
+    }
+  EventArray = (PVOID*)((PUCHAR)ScanDataArray + MaxCount * sizeof(SCSI_PORT_SCAN_ADAPTER));
+  WaitBlockArray = (PKWAIT_BLOCK)((PUCHAR)EventArray + MaxCount * sizeof(PVOID));
+
+  for (Bus = 0; Bus < DeviceExtension->PortConfig->NumberOfBuses; Bus++)
+    {
+      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)
                {
-                 LunExtension = SpiAllocateLunExtension(DeviceExtension,
-                                                        Bus,
-                                                        Target,
-                                                        Lun);
-                 if (LunExtension != NULL)
-                   {
-                     /* Copy inquiry data */
-                     memcpy(&LunExtension->InquiryData,
-                            Srb.DataBuffer,
-                            sizeof(INQUIRYDATA));
-                   }
+                 /* 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);
 
-  ExFreePool(Srb.DataBuffer);
-
-  DeviceExtension->Initializing = FALSE;
+  ExFreePool(ScanDataArray);
 
-  DPRINT("SpiInquirePort() done\n");
+  DPRINT ("SpiScanAdapter() done\n");
 }
 
 
@@ -1816,7 +2301,7 @@ SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
   DPRINT("SpiGetInquiryData() called\n");
 
   /* Copy inquiry data to the port device extension */
-  AdapterBusInfo->NumberOfBuses = DeviceExtension->PortConfig.NumberOfBuses;
+  AdapterBusInfo->NumberOfBuses = DeviceExtension->PortConfig->NumberOfBuses;
 
   UnitInfo = (PSCSI_INQUIRY_DATA)
        ((PUCHAR)AdapterBusInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
@@ -1825,14 +2310,14 @@ SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
   for (Bus = 0; Bus < AdapterBusInfo->NumberOfBuses; Bus++)
     {
       AdapterBusInfo->BusData[Bus].InitiatorBusId =
-       DeviceExtension->PortConfig.InitiatorBusId[Bus];
+       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++)
        {
          for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
            {
@@ -1844,16 +2329,19 @@ SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
                {
                  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;
-                 memcpy(&UnitInfo->InquiryData,
-                        &LunExtension->InquiryData,
-                        INQUIRYDATABUFFERSIZE);
+                 RtlCopyMemory (&UnitInfo->InquiryData,
+                                &LunExtension->InquiryData,
+                                INQUIRYDATABUFFERSIZE);
                  if (PrevUnit != NULL)
-                   PrevUnit->NextInquiryDataOffset = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterBusInfo);
+                   {
+                     PrevUnit->NextInquiryDataOffset =
+                       (ULONG)((ULONG_PTR)UnitInfo-(ULONG_PTR)AdapterBusInfo);
+                   }
                  PrevUnit = UnitInfo;
                  UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
                  UnitCount++;
@@ -1863,7 +2351,9 @@ SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
       DPRINT("UnitCount: %lu\n", UnitCount);
       AdapterBusInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
       if (UnitCount == 0)
-       AdapterBusInfo->BusData[Bus].InquiryDataOffset = 0;
+       {
+         AdapterBusInfo->BusData[Bus].InquiryDataOffset = 0;
+       }
     }
 
   DPRINT("Data size: %lu\n", (ULONG)UnitInfo - (ULONG)AdapterBusInfo);
@@ -1877,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:
@@ -1912,105 +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;
-  KIRQL oldIrql;
 
-  DPRINT("ScsiPortDpcForIsr(Dpc %p  DpcDeviceObject %p  DpcIrp %p  DpcContext %p)\n",
+  DPRINT("ScsiPortDpc(Dpc %p  DpcDeviceObject %p  DpcIrp %p  DpcContext %p)\n",
         Dpc, DpcDeviceObject, DpcIrp, DpcContext);
 
   DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
 
-  KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
-  if (DeviceExtension->IrpFlags)
-    {
-      IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
-      Srb = IrpStack->Parameters.Scsi.Srb;
-
-      if (DeviceExtension->OriginalSrb != NULL)
-       {
-         DPRINT("Got sense data!\n");
-
-         DPRINT("Valid: %x\n", DeviceExtension->InternalSenseData.Valid);
-         DPRINT("ErrorCode: %x\n", DeviceExtension->InternalSenseData.ErrorCode);
-         DPRINT("SenseKey: %x\n", DeviceExtension->InternalSenseData.SenseKey);
-         DPRINT("SenseCode: %x\n", DeviceExtension->InternalSenseData.AdditionalSenseCode);
+  SpiProcessRequests(DeviceExtension, NULL);
 
-         /* 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);
-         KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
-         if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
-                                     ScsiPortStartPacket,
-                                     DeviceExtension))
-           {
-             DPRINT1("Synchronization failed!\n");
-
-             DpcIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
-             DpcIrp->IoStatus.Information = 0;
-             IoCompleteRequest(DpcIrp,
-                               IO_NO_INCREMENT);
-             IoStartNextPacket(DpcDeviceObject,
-                               FALSE);
-           }
-
-         return;
-       }
-
-      DeviceExtension->CurrentIrp = NULL;
-
-//      DpcIrp->IoStatus.Information = 0;
-//      DpcIrp->IoStatus.Status = STATUS_SUCCESS;
-
-      if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
-       {
-         DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
-         IoCompleteRequest(DpcIrp, IO_NO_INCREMENT);
-       }
-
-      if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
-       {
-         DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
-         KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
-         IoStartNextPacket(DpcDeviceObject, FALSE);
-       }
-      else
-       {
-         KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
-       }
-    }
-  else
-    {
-      KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
-    }
-
-  DPRINT("ScsiPortDpcForIsr() done\n");
+  DPRINT("ScsiPortDpc() done\n");
 }
 
 
@@ -2034,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;
@@ -2064,14 +2468,6 @@ ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
   return(Srb);
 }
 
-
-static VOID
-ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
-{
-  DeviceExtension->OriginalSrb = NULL;
-}
-
-
 /**********************************************************************
  * NAME                                                        INTERNAL
  *     SpiBuildDeviceMap
@@ -2101,7 +2497,8 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
 {
   PSCSI_PORT_LUN_EXTENSION LunExtension;
   OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING KeyName;
+  UNICODE_STRING KeyName =
+    RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
   UNICODE_STRING ValueName;
   WCHAR NameBuffer[64];
   ULONG Disposition;
@@ -2129,8 +2526,6 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
     }
 
   /* Open or create the 'Scsi' subkey */
-  RtlInitUnicodeStringFromLiteral(&KeyName,
-                                 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
   InitializeObjectAttributes(&ObjectAttributes,
                             &KeyName,
                             OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
@@ -2217,7 +2612,7 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
     }
 
   /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
-  UlongData = (ULONG)DeviceExtension->PortConfig.BusInterruptLevel;
+  UlongData = (ULONG)DeviceExtension->PortConfig->BusInterruptLevel;
   DPRINT("  Interrupt = %lu\n", UlongData);
   RtlInitUnicodeString(&ValueName,
                       L"Interrupt");
@@ -2235,7 +2630,7 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
     }
 
   /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
-  UlongData = ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig.AccessRanges[0].RangeStart);
+  UlongData = ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension->PortConfig->AccessRanges)[0].RangeStart);
   DPRINT("  IOAddress = %lx\n", UlongData);
   RtlInitUnicodeString(&ValueName,
                       L"IOAddress");
@@ -2253,7 +2648,7 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
     }
 
   /* Enumerate buses */
-  for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig.NumberOfBuses; BusNumber++)
+  for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig->NumberOfBuses; BusNumber++)
     {
       /* Create 'Scsi Bus X' key */
       DPRINT("    Scsi Bus %lu\n", BusNumber);
@@ -2282,10 +2677,10 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
 
       /* Create 'Initiator Id X' key */
       DPRINT("      Initiator Id %u\n",
-             DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
+             DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
       swprintf(NameBuffer,
               L"Initiator Id %u",
-              DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
+              (unsigned int)(UCHAR)DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
       RtlInitUnicodeString(&KeyName,
                           NameBuffer);
       InitializeObjectAttributes(&ObjectAttributes,
@@ -2315,7 +2710,7 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
       /* Enumerate targets */
       CurrentTarget = (ULONG)-1;
       ScsiTargetKey = NULL;
-      for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
+      for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
        {
          for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
            {
@@ -2495,4 +2890,393 @@ ByeBye:
   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);
+
+   DPRINT("SpiProcessRequests() done\n");
+ }
+
+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");
+}
+
+
+
 /* EOF */