Return an error instead of STATUS_SUCCESS for functions which are not implemented...
[reactos.git] / reactos / drivers / storage / scsiport / scsiport.c
index 5f748ea..e37fa9e 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.52 2004/04/02 15:43:01 hbirr 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 <rosrtl/string.h>
+#include <ddk/ntddstor.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,
@@ -70,10 +76,6 @@ static NTSTATUS STDCALL
 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
                      IN PIRP Irp);
 
-static VOID STDCALL
-ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
-               IN PIRP Irp);
-
 static BOOLEAN STDCALL
 ScsiPortStartPacket(IN OUT PVOID Context);
 
@@ -95,7 +97,9 @@ SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
 
 static NTSTATUS
 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
-               IN OUT PSCSI_REQUEST_BLOCK Srb);
+               IN OUT PSCSI_REQUEST_BLOCK Srb,
+               IN OUT PIO_STATUS_BLOCK IoStatusBlock,
+               IN OUT PKEVENT Event);
 
 static VOID
 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
@@ -109,26 +113,30 @@ 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);
-
-static VOID
-ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
+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);
+
 
 /* FUNCTIONS *****************************************************************/
 
@@ -196,10 +204,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);
@@ -219,14 +225,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)
 {
@@ -338,7 +386,7 @@ ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
 
   MappedAddress = MmMapIoSpace(TranslatedAddress,
                               NumberOfBytes,
-                              FALSE);
+                              MmNonCached);
 
   DeviceBase = ExAllocatePool(NonPagedPool,
                              sizeof(SCSI_PORT_DEVICE_BASE));
@@ -425,73 +473,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)
-       {
-         PhysicalAddress.QuadPart = 0ULL;
-         return PhysicalAddress;
+      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;
        }
-
-      Offset = (ULONG_PTR)VirtualAddress - (ULONG_PTR)DeviceExtension->VirtualAddress;
-      if (Offset >= DeviceExtension->CommonBufferLength)
-       {
-         PhysicalAddress.QuadPart = 0ULL;
-         return PhysicalAddress;
+      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;
        }
-
-      PhysicalAddress.QuadPart =
-       DeviceExtension->PhysicalAddress.QuadPart + (ULONGLONG)Offset;
-      BufferLength = DeviceExtension->CommonBufferLength - Offset;
     }
   else
     {
-      EndAddress = Srb->DataBuffer + Srb->DataTransferLength;
+      EndAddress = (PVOID)((ULONG_PTR)Srb->DataBuffer + Srb->DataTransferLength);
       if (VirtualAddress == NULL)
        {
          VirtualAddress = Srb->DataBuffer;
        }
       else if (VirtualAddress < Srb->DataBuffer || VirtualAddress >= EndAddress)
        {
-         PhysicalAddress.QuadPart = 0LL;
-         return PhysicalAddress;
+         EndAddress = (PVOID)((ULONG_PTR)Srb->SenseInfoBuffer + Srb->SenseInfoBufferLength);
+         if (VirtualAddress < Srb->SenseInfoBuffer || VirtualAddress >= EndAddress)
+           {
+             PhysicalAddress.QuadPart = 0LL;
+             CHECKPOINT;
+             return PhysicalAddress;
+           }
        }
 
       PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
       if (PhysicalAddress.QuadPart == 0LL)
        {
+         CHECKPOINT;
          return PhysicalAddress;
        }
 
-      Offset = (ULONG_PTR)VirtualAddress & (PAGE_SIZE - 1);
-#if 1
-      /* 
-       * FIXME:
-       *   MmGetPhysicalAddress doesn't return the offset within the page.
-       *   We must set the correct offset.
-       */
-      PhysicalAddress.u.LowPart = (PhysicalAddress.u.LowPart & ~(PAGE_SIZE - 1)) + Offset;
-#endif
-      BufferLength += PAGE_SIZE - Offset;
-      while (VirtualAddress + BufferLength < EndAddress)
+      BufferLength = PAGE_SIZE - (ULONG_PTR)VirtualAddress % PAGE_SIZE;
+      while ((ULONG_PTR)VirtualAddress + BufferLength < (ULONG_PTR)EndAddress)
        {
-         NextPhysicalAddress = MmGetPhysicalAddress(VirtualAddress + BufferLength);
-         if (PhysicalAddress.QuadPart + (ULONGLONG)BufferLength != NextPhysicalAddress.QuadPart)
+         NextPhysicalAddress = MmGetPhysicalAddress((PVOID)((ULONG_PTR)VirtualAddress + BufferLength));
+         if (PhysicalAddress.QuadPart + BufferLength != NextPhysicalAddress.QuadPart)
            {
              break;
            }
          BufferLength += PAGE_SIZE;
        }
-      if (VirtualAddress + BufferLength >= EndAddress)
+      if ((ULONG_PTR)VirtualAddress + BufferLength >= (ULONG_PTR)EndAddress)
        {
-         BufferLength = EndAddress - VirtualAddress;
+         BufferLength = (ULONG)((ULONG_PTR)EndAddress - (ULONG_PTR)VirtualAddress);
        }
     }
-
-  *Length = BufferLength;
-
+  if (Length != NULL)
+    {
+      *Length = BufferLength;
+    }
+  DPRINT("Address %I64x, Length %d\n", PhysicalAddress.QuadPart, BufferLength);
   return PhysicalAddress;
 }
 
@@ -500,7 +558,7 @@ 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,
@@ -565,10 +623,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->SrbExtensionSize;
+    NumberOfBytes + PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * DeviceExtension->MaxSrbExtensions);
   DeviceExtension->VirtualAddress =
     HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
                            DeviceExtension->CommonBufferLength,
@@ -582,7 +661,7 @@ ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
     }
 
   return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress +
-                 DeviceExtension->SrbExtensionSize);
+                 PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * DeviceExtension->MaxSrbExtensions));
 }
 
 
@@ -677,7 +756,33 @@ ScsiPortInitialize(IN PVOID Argument1,
 
 
   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) ||
@@ -685,7 +790,7 @@ ScsiPortInitialize(IN PVOID Argument1,
       (HwInitializationData->HwResetBus == NULL))
     return(STATUS_INVALID_PARAMETER);
 
-  DriverObject->DriverStartIo = ScsiPortStartIo;
+  DriverObject->DriverStartIo = NULL;
   DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
   DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
   DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
@@ -695,7 +800,7 @@ ScsiPortInitialize(IN PVOID Argument1,
 
   DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
     HwInitializationData->DeviceExtensionSize;
-  PortConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION) + 
+  PortConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION) +
     HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE);
 
 
@@ -738,6 +843,7 @@ ScsiPortInitialize(IN PVOID Argument1,
       PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
 
       DeviceExtension = PortDeviceObject->DeviceExtension;
+      RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
       DeviceExtension->Length = DeviceExtensionSize;
       DeviceExtension->DeviceObject = PortDeviceObject;
       DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
@@ -748,27 +854,30 @@ ScsiPortInitialize(IN PVOID Argument1,
       DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
       DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
 
-#if 0
       DeviceExtension->AdapterObject = NULL;
       DeviceExtension->MapRegisterCount = 0;
       DeviceExtension->PhysicalAddress.QuadPart = 0ULL;
       DeviceExtension->VirtualAddress = NULL;
       DeviceExtension->CommonBufferLength = 0;
-#endif
 
       /* Initialize the device base list */
       InitializeListHead (&DeviceExtension->DeviceBaseListHead);
 
+      /* Initialize the irp lists */
+      InitializeListHead (&DeviceExtension->PendingIrpListHead);
+      DeviceExtension->NextIrp = NULL;
+      DeviceExtension->PendingIrpCount = 0;
+      DeviceExtension->ActiveIrpCount = 0;
+
       /* Initialize LUN-Extension list */
       InitializeListHead (&DeviceExtension->LunExtensionListHead);
 
       /* Initialize the spin lock in the controller extension */
-      KeInitializeSpinLock (&DeviceExtension->IrpLock);
-      KeInitializeSpinLock (&DeviceExtension->SpinLock);
+      KeInitializeSpinLock (&DeviceExtension->Lock);
 
       /* Initialize the DPC object */
       IoInitializeDpcRequest (PortDeviceObject,
-                             ScsiPortDpcForIsr);
+                             ScsiPortDpc);
 
       /* Initialize the device timer */
       DeviceExtension->TimerState = IDETimerIdle;
@@ -798,37 +907,38 @@ ScsiPortInitialize(IN PVOID Argument1,
       PortConfig->NumberOfPhysicalBreaks = SP_UNINITIALIZED_VALUE;
       PortConfig->DmaChannel = SP_UNINITIALIZED_VALUE;
       PortConfig->DmaPort = SP_UNINITIALIZED_VALUE;
-//  PortConfig->DmaWidth =
-//  PortConfig->DmaSpeed =
-//  PortConfig->AlignmentMask =
+      PortConfig->DmaWidth = 0;
+      PortConfig->DmaSpeed = Compatible;
+      PortConfig->AlignmentMask = 0;
       PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
-//  PortConfig->NumberOfBuses =
+      PortConfig->NumberOfBuses = 0;
 
       for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
        PortConfig->InitiatorBusId[i] = 255;
 
-//  PortConfig->ScatterGather =
-//  PortConfig->Master =
-//  PortConfig->CachesData =
-//  PortConfig->AdapterScansDown =
+      PortConfig->ScatterGather = FALSE;
+      PortConfig->Master = FALSE;
+      PortConfig->CachesData = FALSE;
+      PortConfig->AdapterScansDown = FALSE;
       PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
       PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
-//  PortConfig->Dma32BitAddresses =
-//  PortConfig->DemandMode =
+      PortConfig->Dma32BitAddresses = FALSE;
+      PortConfig->DemandMode = FALSE;
       PortConfig->MapBuffers = HwInitializationData->MapBuffers;
       PortConfig->NeedPhysicalAddresses = HwInitializationData->NeedPhysicalAddresses;
-      PortConfig->TaggedQueuing = HwInitializationData->TaggedQueueing;
+      PortConfig->TaggedQueuing = HwInitializationData->TaggedQueuing;
       PortConfig->AutoRequestSense = HwInitializationData->AutoRequestSense;
       PortConfig->MultipleRequestPerLu = HwInitializationData->MultipleRequestPerLu;
       PortConfig->ReceiveEvent = HwInitializationData->ReceiveEvent;
-//  PortConfig->RealModeInitialized =
-//  PortConfig->BufferAccessScsiPortControlled =
+      PortConfig->RealModeInitialized = FALSE;
+      PortConfig->BufferAccessScsiPortControlled = FALSE;
       PortConfig->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS;
-//  PortConfig->MaximumNumberOfLogicalUnits = SCSI_MAXIMUM_LOGICAL_UNITS;
+//      PortConfig->MaximumNumberOfLogicalUnits = SCSI_MAXIMUM_LOGICAL_UNITS;
 
-      PortConfig->SlotNumber = SlotNumber.u.AsULONG;
+      PortConfig->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
+      PortConfig->SpecificLuExtensionSize = HwInitializationData->SpecificLuExtensionSize;
 
-      PortConfig->AccessRanges = (PACCESS_RANGE)(PortConfig + 1);
+      PortConfig->AccessRanges = (ACCESS_RANGE(*)[])(PortConfig + 1);
 
       /* Search for matching PCI device */
       if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
@@ -870,17 +980,84 @@ ScsiPortInitialize(IN PVOID Argument1,
        {
          DPRINT("ScsiPortInitialize(): Found HBA! (%x)\n", PortConfig->BusInterruptVector);
 
+#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,
-                                     &DeviceExtension->SpinLock,
+                                     NULL,
                                      MappedIrq,
                                      Dirql,
                                      Dirql,
@@ -914,8 +1091,19 @@ ScsiPortInitialize(IN PVOID Argument1,
 
          PortCapabilities = DeviceExtension->PortCapabilities;
          PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
-         PortCapabilities->MaximumTransferLength =
-           PortConfig->MaximumTransferLength;
+          if (PortConfig->ScatterGather == FALSE ||
+             PortConfig->NumberOfPhysicalBreaks >= (0x100000000LL >> PAGE_SHIFT) ||
+             PortConfig->MaximumTransferLength < PortConfig->NumberOfPhysicalBreaks * PAGE_SIZE)
+           {
+             PortCapabilities->MaximumTransferLength =
+               PortConfig->MaximumTransferLength;
+           }
+         else
+           {
+             PortCapabilities->MaximumTransferLength =
+               PortConfig->NumberOfPhysicalBreaks * PAGE_SIZE;
+           }
+
          PortCapabilities->MaximumPhysicalPages =
            PortCapabilities->MaximumTransferLength / PAGE_SIZE;
          PortCapabilities->SupportedAsynchronousEvents = 0; /* FIXME */
@@ -1034,6 +1222,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,
@@ -1088,13 +1278,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:
@@ -1102,20 +1293,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;
-//       DeviceExtension->IrpFlags |= IRP_FLAG_NEXT_LU;
-
-         /* Hack! */
-         DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
+          LunExtension = SpiGetLunExtension(DeviceExtension,
+                                           PathId,
+                                           TargetId,
+                                           Lun);
+         if (LunExtension)
+           {
+             DeviceExtension->Flags |= IRP_FLAG_NEXT_LU;
+             LunExtension->Flags |= IRP_FLAG_NEXT_LU;
+           }
        }
        break;
 
@@ -1128,6 +1323,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);
 }
@@ -1254,9 +1459,9 @@ SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
 
                  for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
                    {
-                     PortConfig->AccessRanges[i].RangeStart.QuadPart =
+                     (*PortConfig->AccessRanges)[i].RangeStart.QuadPart =
                        PciConfig.u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_ADDRESS_MASK;
-                     if (PortConfig->AccessRanges[i].RangeStart.QuadPart != 0)
+                     if ((*PortConfig->AccessRanges)[i].RangeStart.QuadPart != 0)
                        {
                          RangeLength = (ULONG)-1;
                          HalSetBusDataByOffset (PCIConfiguration,
@@ -1281,9 +1486,9 @@ SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
                                                 sizeof(ULONG));
                          if (RangeLength != 0)
                            {
-                             PortConfig->AccessRanges[i].RangeLength =
+                             (*PortConfig->AccessRanges)[i].RangeLength =
                                -(RangeLength & PCI_ADDRESS_IO_ADDRESS_MASK);
-                             PortConfig->AccessRanges[i].RangeInMemory =
+                             (*PortConfig->AccessRanges)[i].RangeInMemory =
                                !(PciConfig.u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_SPACE);
 
                              DPRINT("RangeStart 0x%lX  RangeLength 0x%lX  RangeInMemory %s\n",
@@ -1296,7 +1501,11 @@ SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
                }
 
              NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
-             NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
+             NextSlotNumber->u.bits.FunctionNumber = FunctionNumber;
+
+              PortConfig->SlotNumber = NextSlotNumber->u.AsULONG;
+
+             NextSlotNumber->u.bits.FunctionNumber += 1;
 
              return TRUE;
            }
@@ -1425,34 +1634,10 @@ 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)
-         {
-           IoMarkIrpPending(Irp);
-           IoStartPacket (DeviceObject, Irp, NULL, NULL);
-         }
-       else
-         {
-           KIRQL oldIrql;
-
-           KeRaiseIrql (DISPATCH_LEVEL,
-                        &oldIrql);
-
-           if (!KeInsertByKeyDeviceQueue (&LunExtension->DeviceQueue,
-                                          &Irp->Tail.Overlay.DeviceQueueEntry,
-                                          Srb->QueueSortKey))
-             {
-               Srb->SrbStatus = SRB_STATUS_SUCCESS;
-               IoMarkIrpPending(Irp);
-               IoStartPacket (DeviceObject, Irp, NULL, NULL);
-             }
-
-           KeLowerIrql (oldIrql);
-         }
-#else
         IoMarkIrpPending(Irp);
-        IoStartPacket (DeviceObject, Irp, NULL, NULL);
-#endif
+       Srb->OriginalRequest = LunExtension;
+        Irp->Tail.Overlay.DriverContext[3] = Srb;
+       SpiProcessRequests(DeviceExtension, Irp);
        return(STATUS_PENDING);
 
       case SRB_FUNCTION_SHUTDOWN:
@@ -1460,7 +1645,9 @@ ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
        if (DeviceExtension->PortConfig->CachesData == TRUE)
          {
             IoMarkIrpPending(Irp);
-           IoStartPacket(DeviceObject, Irp, NULL, NULL);
+           Srb->OriginalRequest = LunExtension;
+            Irp->Tail.Overlay.DriverContext[3] = Srb;
+           SpiProcessRequests(DeviceExtension, Irp);
            return(STATUS_PENDING);
          }
        break;
@@ -1524,10 +1711,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;
 
 
@@ -1542,7 +1729,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;
@@ -1569,142 +1756,77 @@ 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);
+        Status = STATUS_INVALID_DEVICE_REQUEST;
+        break;
 
       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 VOID
+SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                       PSCSI_REQUEST_BLOCK Srb)
 {
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  PIO_STACK_LOCATION IrpStack;
-  PSCSI_REQUEST_BLOCK Srb;
-  KIRQL oldIrql;
-
-  DPRINT("ScsiPortStartIo() called!\n");
-
-  DeviceExtension = DeviceObject->DeviceExtension;
-  IrpStack = IoGetCurrentIrpStackLocation(Irp);
-
-  DPRINT("DeviceExtension %p\n", DeviceExtension);
-
-  oldIrql = KeGetCurrentIrql();
-
-  if (IrpStack->MajorFunction != IRP_MJ_SCSI)
-    {
-      DPRINT("No IRP_MJ_SCSI!\n");
-      Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
-      Irp->IoStatus.Information = 0;
-      IoCompleteRequest (Irp,
-                        IO_NO_INCREMENT);
-      if (oldIrql < DISPATCH_LEVEL)
-       {
-         KeRaiseIrql (DISPATCH_LEVEL,
-                      &oldIrql);
-         IoStartNextPacket (DeviceObject,
-                            FALSE);
-         KeLowerIrql (oldIrql);
-       }
-      else
-       {
-         IoStartNextPacket (DeviceObject,
-                            FALSE);
-       }
-      return;
-    }
+  ULONG index;
 
-  Srb = IrpStack->Parameters.Scsi.Srb;
+  DPRINT("SpiAllocateSrbExtension\n");
 
-  LunExtension = SpiGetLunExtension(DeviceExtension,
-                                   Srb->PathId,
-                                   Srb->TargetId,
-                                   Srb->Lun);
-  if (LunExtension == NULL)
-    {
-      DPRINT("Can't get LunExtension!\n");
-      Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
-      Irp->IoStatus.Information = 0;
-      IoCompleteRequest (Irp,
-                        IO_NO_INCREMENT);
-      if (oldIrql < DISPATCH_LEVEL)
-       {
-         KeRaiseIrql (DISPATCH_LEVEL,
-                      &oldIrql);
-         IoStartNextPacket (DeviceObject,
-                            FALSE);
-         KeLowerIrql (oldIrql);
-       }
-      else
-       {
-         IoStartNextPacket (DeviceObject,
-                            FALSE);
-       }
-      return;
-    }
-
-  Irp->IoStatus.Status = STATUS_SUCCESS;
-  Irp->IoStatus.Information = Srb->DataTransferLength;
-
-  DeviceExtension->CurrentIrp = Irp;
+  DPRINT("DeviceExtension->VirtualAddress %x, DeviceExtension->SrbExtensionSize %x\n",
+         DeviceExtension->VirtualAddress, DeviceExtension->SrbExtensionSize);
 
-  if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
-                             ScsiPortStartPacket,
-                             DeviceExtension))
+  Srb->SrbExtension = NULL;
+  if (DeviceExtension->VirtualAddress != NULL &&
+      DeviceExtension->SrbExtensionSize > 0)
     {
-      DPRINT("Synchronization failed!\n");
-
-      Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
-      Irp->IoStatus.Information = 0;
-      IoCompleteRequest(Irp,
-                       IO_NO_INCREMENT);
-      if (oldIrql < DISPATCH_LEVEL)
-       {
-         KeRaiseIrql (DISPATCH_LEVEL,
-                      &oldIrql);
-         IoStartNextPacket (DeviceObject,
-                            FALSE);
-         KeLowerIrql (oldIrql);
-       }
-      else
-       {
-         IoStartNextPacket (DeviceObject,
-                            FALSE);
+      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);
+}
 
-  KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
-  if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
-    {
-      DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
-      IoCompleteRequest(Irp,
-                       IO_NO_INCREMENT);
-    }
+static VOID
+SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                   PSCSI_REQUEST_BLOCK Srb)
+{
+  ULONG index;
 
-  if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
-    {
-      DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
-      KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
-      IoStartNextPacket(DeviceObject,
-                       FALSE);
-      KeLowerIrql(oldIrql);
-    }
-  else
+  if (DeviceExtension->VirtualAddress != NULL &&
+      DeviceExtension->SrbExtensionSize > 0 &&
+      Srb->SrbExtension != NULL)
     {
-      KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
+      index = ((ULONG_PTR)Srb->SrbExtension - (ULONG_PTR)DeviceExtension->VirtualAddress) / DeviceExtension->SrbExtensionSize;
+      RtlClearBits(&DeviceExtension->SrbExtensionAllocMap, index, 1);
+      DeviceExtension->CurrentSrbExtensions--;
     }
-
-  DPRINT("ScsiPortStartIo() done\n");
+  Srb->SrbExtension = NULL;
 }
 
 
@@ -1712,21 +1834,16 @@ static BOOLEAN STDCALL
 ScsiPortStartPacket(IN OUT PVOID Context)
 {
   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  PIO_STACK_LOCATION IrpStack;
   PSCSI_REQUEST_BLOCK Srb;
+  PIRP Irp;
+  PIO_STACK_LOCATION IrpStack;
 
-  DPRINT("ScsiPortStartPacket() called\n");
-
-  DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context;
-
-  IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
-  Srb = IrpStack->Parameters.Scsi.Srb;
+  DPRINT("ScsiPortStartPacket(Context %x) called\n", Context);
 
-  /* Allocte SRB extension */
-  if (DeviceExtension->SrbExtensionSize != 0)
-    {
-      Srb->SrbExtension = DeviceExtension->VirtualAddress;
-    }
+  Srb = (PSCSI_REQUEST_BLOCK)Context;
+  Irp = (PIRP)Srb->OriginalRequest;
+  IrpStack = IoGetCurrentIrpStackLocation(Irp);
+  DeviceExtension = IrpStack->DeviceObject->DeviceExtension;
 
   return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
                                    Srb));
@@ -1766,7 +1883,10 @@ 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;
 }
@@ -1830,20 +1950,16 @@ SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
 
 static NTSTATUS
 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
-               IN OUT PSCSI_REQUEST_BLOCK Srb)
+               IN OUT PSCSI_REQUEST_BLOCK Srb,
+               IN OUT PIO_STATUS_BLOCK IoStatusBlock,
+               IN OUT PKEVENT Event)
 {
-  IO_STATUS_BLOCK IoStatusBlock;
   PIO_STACK_LOCATION IrpStack;
-  PKEVENT Event;
   PIRP Irp;
   NTSTATUS Status;
 
   DPRINT ("SpiSendInquiry() called\n");
 
-  Event = ExAllocatePool (NonPagedPool,
-                         sizeof(KEVENT));
-  if (Event == NULL)
-    return STATUS_INSUFFICIENT_RESOURCES;
 
   KeInitializeEvent (Event,
                     NotificationEvent,
@@ -1857,11 +1973,10 @@ SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
                                       Srb->DataTransferLength,
                                       TRUE,
                                       Event,
-                                      &IoStatusBlock);
+                                      IoStatusBlock);
   if (Irp == NULL)
     {
       DPRINT("IoBuildDeviceIoControlRequest() failed\n");
-      ExFreePool (Event);
       return STATUS_INSUFFICIENT_RESOURCES;
     }
 
@@ -1873,97 +1988,160 @@ SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
   /* Call the driver */
   Status = IoCallDriver (DeviceObject,
                         Irp);
-  if (Status == STATUS_PENDING)
-    {
-      KeWaitForSingleObject (Event,
-                            Suspended,
-                            KernelMode,
-                            FALSE,
-                            NULL);
-      Status = IoStatusBlock.Status;
-    }
-
-  ExFreePool (Event);
 
   return Status;
 }
 
-
 static VOID
 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
 {
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  SCSI_REQUEST_BLOCK Srb;
+  PSCSI_REQUEST_BLOCK Srb;
   PCDB Cdb;
   ULONG Bus;
   ULONG Target;
-  ULONG Lun;
-  NTSTATUS Status;
+  PSCSI_PORT_SCAN_ADAPTER ScanDataArray;
+  PSCSI_PORT_SCAN_ADAPTER ScanData;
+  ULONG i;
+  ULONG MaxCount;
+  ULONG WaitCount;
+  ULONG ActiveCount;
+  PVOID* EventArray;
+  PKWAIT_BLOCK WaitBlockArray;
 
   DPRINT ("SpiScanAdapter() called\n");
 
-  RtlZeroMemory(&Srb,
-               sizeof(SCSI_REQUEST_BLOCK));
-  Srb.SrbFlags = SRB_FLAGS_DATA_IN;
-  Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
-  Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
-  Srb.DataTransferLength = 255; //256;
-  Srb.CdbLength = 6;
-
-  Cdb = (PCDB) &Srb.Cdb;
+  MaxCount = DeviceExtension->PortConfig->NumberOfBuses *
+               DeviceExtension->PortConfig->MaximumNumberOfTargets;
 
-  Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
-  Cdb->CDB6INQUIRY.AllocationLength = 255;
+  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++)
     {
-      Srb.PathId = Bus;
-
       for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
        {
-         Srb.TargetId = Target;
-
-         for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
-           {
-             Srb.Lun = Lun;
-             Srb.SrbStatus = SRB_STATUS_SUCCESS;
-
-             Cdb->CDB6INQUIRY.LogicalUnitNumber = Lun;
-
-             LunExtension = SpiAllocateLunExtension (DeviceExtension,
-                                                     Bus,
-                                                     Target,
-                                                     Lun);
-             if (LunExtension == NULL)
-               {
-                 DPRINT("Failed to allocate the LUN extension!\n");
-                 ExFreePool(Srb.DataBuffer);
-                 return;
+         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;
                }
-
-             Status = SpiSendInquiry (DeviceExtension->DeviceObject,
-                                      &Srb);
-             DPRINT ("Status %lx  Srb.SrbStatus %x\n", Status, Srb.SrbStatus);
-
-             if (NT_SUCCESS(Status) &&
-                 (Srb.SrbStatus == SRB_STATUS_SUCCESS ||
-                  Srb.SrbStatus == SRB_STATUS_DATA_OVERRUN) &&
-                 ((PINQUIRYDATA)Srb.DataBuffer)->DeviceTypeQualifier == 0)
+             else
+               {
+                  ScanData->Status = ScanData->IoStatusBlock.Status;
+               }
+             ScanData->Active = FALSE;
+             DPRINT ("Target %lu  Lun %lu\n", ScanData->Target, ScanData->Lun);
+             DPRINT ("Status %lx  Srb.SrbStatus %x\n", ScanData->Status, Srb->SrbStatus);
+             DPRINT ("DeviceTypeQualifier %x\n", ((PINQUIRYDATA)Srb->DataBuffer)->DeviceTypeQualifier);
+
+             if (NT_SUCCESS(ScanData->Status) &&
+                 (Srb->SrbStatus == SRB_STATUS_SUCCESS ||
+                  (Srb->SrbStatus == SRB_STATUS_DATA_OVERRUN &&
+                  /*
+                   * FIXME:
+                   *   The NT 4.0 driver from an inic950 based scsi controller
+                   *   returns only 4 byte of inquiry data, but the device name
+                   *   is visible on NT 4.0. We must implement an other way
+                   *   to get the complete inquiry data.
+                   */
+                   Srb->DataTransferLength >= /*INQUIRYDATABUFFERSIZE*/4)) &&
+                 ((PINQUIRYDATA)Srb->DataBuffer)->DeviceTypeQualifier == 0)
                {
                  /* Copy inquiry data */
-                 RtlCopyMemory (&LunExtension->InquiryData,
-                                Srb.DataBuffer,
-                                sizeof(INQUIRYDATA));
+                 RtlCopyMemory (&ScanData->LunExtension->InquiryData,
+                                Srb->DataBuffer,
+                                min(sizeof(INQUIRYDATA), Srb->DataTransferLength));
+                 ScanData->Lun++;
                }
              else
                {
-                 SpiRemoveLunExtension (LunExtension);
+                 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);
+  ExFreePool(ScanDataArray);
 
   DPRINT ("SpiScanAdapter() done\n");
 }
@@ -2011,7 +2189,7 @@ 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;
@@ -2049,30 +2227,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:
@@ -2084,104 +2248,21 @@ ScsiPortIsr(IN PKINTERRUPT Interrupt,
 //    IN PVOID          DpcContext
 //
 static VOID STDCALL
-ScsiPortDpcForIsr(IN PKDPC Dpc,
-                 IN PDEVICE_OBJECT DpcDeviceObject,
-                 IN PIRP DpcIrp,
-                 IN PVOID DpcContext)
+ScsiPortDpc(IN PKDPC Dpc,
+           IN PDEVICE_OBJECT DpcDeviceObject,
+           IN PIRP DpcIrp,
+           IN PVOID DpcContext)
 {
   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  PIO_STACK_LOCATION IrpStack;
-  PSCSI_REQUEST_BLOCK Srb;
 
-  DPRINT("ScsiPortDpcForIsr(Dpc %p  DpcDeviceObject %p  DpcIrp %p  DpcContext %p)\n",
+  DPRINT("ScsiPortDpc(Dpc %p  DpcDeviceObject %p  DpcIrp %p  DpcContext %p)\n",
         Dpc, DpcDeviceObject, DpcIrp, DpcContext);
 
   DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
 
-  KeAcquireSpinLockAtDpcLevel(&DeviceExtension->IrpLock);
-  if (DeviceExtension->IrpFlags)
-    {
-      IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
-      Srb = IrpStack->Parameters.Scsi.Srb;
-
-      if (DeviceExtension->OriginalSrb != NULL)
-       {
-         DPRINT("Got sense data!\n");
-
-         DPRINT("Valid: %x\n", DeviceExtension->InternalSenseData.Valid);
-         DPRINT("ErrorCode: %x\n", DeviceExtension->InternalSenseData.ErrorCode);
-         DPRINT("SenseKey: %x\n", DeviceExtension->InternalSenseData.SenseKey);
-         DPRINT("SenseCode: %x\n", DeviceExtension->InternalSenseData.AdditionalSenseCode);
-
-         /* Copy sense data */
-         if (DeviceExtension->OriginalSrb->SenseInfoBufferLength != 0)
-           {
-             RtlCopyMemory(DeviceExtension->OriginalSrb->SenseInfoBuffer,
-                           &DeviceExtension->InternalSenseData,
-                           sizeof(SENSE_DATA));
-             DeviceExtension->OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
-           }
-
-         /* Clear current sense data */
-         RtlZeroMemory(&DeviceExtension->InternalSenseData, sizeof(SENSE_DATA));
-
-         IrpStack->Parameters.Scsi.Srb = DeviceExtension->OriginalSrb;
-         ScsiPortFreeSenseRequestSrb (DeviceExtension);
-       }
-      else if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) &&
-              (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION))
-       {
-         DPRINT("SCSIOP_REQUEST_SENSE required!\n");
-
-         DeviceExtension->OriginalSrb = Srb;
-         IrpStack->Parameters.Scsi.Srb = ScsiPortInitSenseRequestSrb(DeviceExtension,
-                                                                     Srb);
-         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
-         if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
-                                     ScsiPortStartPacket,
-                                     DeviceExtension))
-           {
-             DPRINT1("Synchronization failed!\n");
-
-             DpcIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
-             DpcIrp->IoStatus.Information = 0;
-             IoCompleteRequest(DpcIrp,
-                               IO_NO_INCREMENT);
-             IoStartNextPacket(DpcDeviceObject,
-                               FALSE);
-           }
-
-         return;
-       }
-
-      DeviceExtension->CurrentIrp = NULL;
-
-//      DpcIrp->IoStatus.Information = 0;
-//      DpcIrp->IoStatus.Status = STATUS_SUCCESS;
-
-      if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
-       {
-         DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
-         IoCompleteRequest(DpcIrp, IO_NO_INCREMENT);
-       }
-
-      if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
-       {
-         DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
-         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
-         IoStartNextPacket(DpcDeviceObject, FALSE);
-       }
-      else
-       {
-         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
-       }
-    }
-  else
-    {
-      KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
-    }
+  SpiProcessRequests(DeviceExtension, NULL);
 
-  DPRINT("ScsiPortDpcForIsr() done\n");
+  DPRINT("ScsiPortDpc() done\n");
 }
 
 
@@ -2205,27 +2286,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;
@@ -2235,14 +2328,6 @@ ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
   return(Srb);
 }
 
-
-static VOID
-ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
-{
-  DeviceExtension->OriginalSrb = NULL;
-}
-
-
 /**********************************************************************
  * NAME                                                        INTERNAL
  *     SpiBuildDeviceMap
@@ -2272,7 +2357,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;
@@ -2300,8 +2386,6 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
     }
 
   /* Open or create the 'Scsi' subkey */
-  RtlRosInitUnicodeStringFromLiteral(&KeyName,
-                                 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
   InitializeObjectAttributes(&ObjectAttributes,
                             &KeyName,
                             OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
@@ -2406,7 +2490,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");
@@ -2666,4 +2750,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 */