Sync to trunk head(r38096)
[reactos.git] / reactos / drivers / storage / scsiport / scsiport.c
index a830581..7485c13 100644 (file)
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id$
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
- * FILE:            services/storage/scsiport/scsiport.c
+ * PROJECT:         ReactOS Storage Stack
+ * FILE:            drivers/storage/scsiport/scsiport.c
  * PURPOSE:         SCSI port driver
  * PROGRAMMER:      Eric Kohl (ekohl@rz-online.de)
- *                  Hartmut Birr
+ *                  Aleksey Bragin (aleksey reactos org)
  */
 
 /* INCLUDES *****************************************************************/
 #include <ntddstor.h>
 #include <ntdddisk.h>
 #include <stdio.h>
+#include <stdarg.h>
 
+#ifndef NDEBUG
 #define NDEBUG
+#endif
 #include <debug.h>
 
 #include "scsiport_int.h"
 
-/* TYPES *********************************************************************/
+ULONG InternalDebugLevel = 0x00;
 
-#define IRP_FLAG_COMPLETE      0x00000001
-#define IRP_FLAG_NEXT          0x00000002
-#define IRP_FLAG_NEXT_LU       0x00000004
+/* TYPES *********************************************************************/
 
 /* 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 PPCI_SLOT_NUMBER NextSlotNumber);
-
-static NTSTATUS STDCALL
+SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
+                    IN PDEVICE_OBJECT DeviceObject,
+                    IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
+                    IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
+                    IN PUNICODE_STRING RegistryPath,
+                    IN ULONG BusNumber,
+                    IN OUT PPCI_SLOT_NUMBER NextSlotNumber);
+
+static NTSTATUS NTAPI
 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
                    IN PIRP Irp);
 
-static NTSTATUS STDCALL
+static DRIVER_DISPATCH ScsiPortDispatchScsi;
+static NTSTATUS NTAPI
 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
                     IN PIRP Irp);
 
-static NTSTATUS STDCALL
+static NTSTATUS NTAPI
 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
                      IN PIRP Irp);
 
-static BOOLEAN STDCALL
+static DRIVER_STARTIO ScsiPortStartIo;
+static VOID NTAPI
+ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
+               IN PIRP Irp);
+
+static BOOLEAN NTAPI
 ScsiPortStartPacket(IN OUT PVOID Context);
 
+IO_ALLOCATION_ACTION
+NTAPI
+SpiAdapterControl(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+                  PVOID MapRegisterBase, PVOID Context);
 
 static PSCSI_PORT_LUN_EXTENSION
-SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                        IN UCHAR PathId,
-                        IN UCHAR TargetId,
-                        IN UCHAR Lun);
-
-static VOID
-SpiRemoveLunExtension (IN PSCSI_PORT_LUN_EXTENSION LunExtension);
+SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
 
 static PSCSI_PORT_LUN_EXTENSION
 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
@@ -96,52 +93,130 @@ SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
                    IN UCHAR TargetId,
                    IN UCHAR Lun);
 
+static PSCSI_REQUEST_BLOCK_INFO
+SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                         PSCSI_PORT_LUN_EXTENSION LunExtension,
+                         PSCSI_REQUEST_BLOCK Srb);
+
 static NTSTATUS
 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
-               IN OUT PSCSI_REQUEST_BLOCK Srb,
-               IN OUT PIO_STATUS_BLOCK IoStatusBlock,
-               IN OUT PKEVENT Event);
+               IN PSCSI_LUN_INFO LunInfo);
 
 static VOID
 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
 
-static ULONG
+static NTSTATUS
 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                  OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo);
+                  IN PIRP Irp);
 
-static BOOLEAN STDCALL
+static PSCSI_REQUEST_BLOCK_INFO
+SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+              IN UCHAR PathId,
+              IN UCHAR TargetId,
+              IN UCHAR Lun,
+              IN UCHAR QueueTag);
+
+static BOOLEAN NTAPI
 ScsiPortIsr(IN PKINTERRUPT Interrupt,
            IN PVOID ServiceContext);
 
-static VOID STDCALL
-ScsiPortDpc(IN PKDPC Dpc,
-           IN PDEVICE_OBJECT DpcDeviceObject,
-           IN PIRP DpcIrp,
-           IN PVOID DpcContext);
+static VOID NTAPI
+ScsiPortDpcForIsr(IN PKDPC Dpc,
+                 IN PDEVICE_OBJECT DpcDeviceObject,
+                 IN PIRP DpcIrp,
+                 IN PVOID DpcContext);
 
-static VOID STDCALL
+static VOID NTAPI
 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
                PVOID Context);
 
-static PSCSI_REQUEST_BLOCK
-ScsiPortInitSenseRequestSrb(PSCSI_REQUEST_BLOCK OriginalSrb);
+IO_ALLOCATION_ACTION
+NTAPI
+ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
+                               IN PIRP Irp,
+                               IN PVOID MapRegisterBase,
+                               IN PVOID Context);
 
 static NTSTATUS
 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
                   PUNICODE_STRING RegistryPath);
 
+static NTSTATUS
+SpiStatusSrbToNt(UCHAR SrbStatus);
+
+static VOID
+SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                    IN PSCSI_REQUEST_BLOCK Srb);
+
+static IO_COMPLETION_ROUTINE SpiCompletionRoutine;
+NTSTATUS NTAPI
+SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
+                     PIRP Irp,
+                     PVOID Context);
+
+static VOID
+NTAPI
+SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                           IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
+                           OUT PBOOLEAN NeedToCallStartIo);
+
+VOID NTAPI
+SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                         IN PSCSI_PORT_LUN_EXTENSION LunExtension);
+
+VOID NTAPI
+SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
+                    IN PVOID DeviceObject,
+                    IN PVOID SystemArgument1,
+                    IN PVOID SystemArgument2);
+
+static NTSTATUS
+SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                    PHW_INITIALIZATION_DATA HwInitData,
+                    PCONFIGURATION_INFO InternalConfigInfo,
+                    PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+                    BOOLEAN FirstCall);
+
+NTSTATUS NTAPI
+SpQueryDeviceCallout(IN PVOID  Context,
+                     IN PUNICODE_STRING  PathName,
+                     IN INTERFACE_TYPE  BusType,
+                     IN ULONG  BusNumber,
+                     IN PKEY_VALUE_FULL_INFORMATION  *BusInformation,
+                     IN CONFIGURATION_TYPE  ControllerType,
+                     IN ULONG  ControllerNumber,
+                     IN PKEY_VALUE_FULL_INFORMATION  *ControllerInformation,
+                     IN CONFIGURATION_TYPE  PeripheralType,
+                     IN ULONG  PeripheralNumber,
+                     IN PKEY_VALUE_FULL_INFORMATION  *PeripheralInformation);
+
 static VOID
-SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                       PSCSI_REQUEST_BLOCK Srb);
+SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                   IN HANDLE Key,
+                   IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+                   IN PCONFIGURATION_INFO InternalConfigInfo,
+                   IN PUCHAR Buffer);
 
 static VOID
-SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                   PSCSI_REQUEST_BLOCK Srb);
+SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
+                    IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
+                    IN PPORT_CONFIGURATION_INFORMATION PortConfig);
 
+static PCM_RESOURCE_LIST
+SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                    PPORT_CONFIGURATION_INFORMATION PortConfig);
+
+static VOID
+SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
+
+static NTSTATUS
+SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                       PIRP Irp);
 
 static NTSTATUS
-SpiScsiMiniport(IN PDEVICE_OBJECT DeviceObject,
-               IN PIRP Irp);
+SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize);
+
+
 
 /* FUNCTIONS *****************************************************************/
 
@@ -166,12 +241,12 @@ SpiScsiMiniport(IN PDEVICE_OBJECT DeviceObject,
  *     Status.
  */
 
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 DriverEntry(IN PDRIVER_OBJECT DriverObject,
            IN PUNICODE_STRING RegistryPath)
 {
-  DPRINT("ScsiPort Driver %s\n", VERSION);
-  return(STATUS_SUCCESS);
+    DPRINT("ScsiPort Driver %s\n", VERSION);
+    return(STATUS_SUCCESS);
 }
 
 
@@ -206,92 +281,133 @@ ScsiDebugPrint(IN ULONG DebugPrintLevel,
               IN PCHAR DebugMessage,
               ...)
 {
-  char Buffer[256];
-  va_list ap;
+    char Buffer[256];
+    va_list ap;
 
-  if (DebugPrintLevel >= InternalDebugLevel)
-    return;
+    if (DebugPrintLevel > InternalDebugLevel)
+        return;
 
-  va_start(ap, DebugMessage);
-  vsprintf(Buffer, DebugMessage, ap);
-  va_end(ap);
+    va_start(ap, DebugMessage);
+    vsprintf(Buffer, DebugMessage, ap);
+    va_end(ap);
 
-  DbgPrint(Buffer);
+    DbgPrint(Buffer);
 }
 
+/* An internal helper function for ScsiPortCompleteRequest */
+VOID
+NTAPI
+SpiCompleteRequest(IN PVOID HwDeviceExtension,
+                   IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
+                   IN UCHAR SrbStatus)
+{
+    PSCSI_REQUEST_BLOCK Srb;
+
+    /* Get current SRB */
+    Srb = SrbInfo->Srb;
+
+    /* Return if there is no SRB or it is not active */
+    if (!Srb || !(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) return;
+
+    /* Set status */
+    Srb->SrbStatus = SrbStatus;
+
+    /* Set data transfered to 0 */
+    Srb->DataTransferLength = 0;
+
+    /* Notify */
+    ScsiPortNotification(RequestComplete,
+                         HwDeviceExtension,
+                         Srb);
+}
 
 /*
  * @unimplemented
  */
-VOID STDCALL
+VOID NTAPI
 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
-                       IN UCHAR PathId,
-                       IN UCHAR TargetId,
-                       IN UCHAR Lun,
-                       IN UCHAR SrbStatus)
+                        IN UCHAR PathId,
+                        IN UCHAR TargetId,
+                        IN UCHAR Lun,
+                        IN UCHAR SrbStatus)
 {
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  PLIST_ENTRY Entry;
-  PIRP Irp;
-  PSCSI_REQUEST_BLOCK Srb;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+    PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+    PLIST_ENTRY ListEntry;
+    ULONG BusNumber;
+    ULONG Target;
 
-  DPRINT("ScsiPortCompleteRequest(HwDeviceExtension %x, PathId %d, TargetId %d, Lun %d, SrbStatus %x)\n",
-         HwDeviceExtension, PathId, TargetId, Lun, SrbStatus);
+    DPRINT("ScsiPortCompleteRequest() called\n");
 
-  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
-                                     SCSI_PORT_DEVICE_EXTENSION,
-                                     MiniPortDeviceExtension);
+    DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+                                        SCSI_PORT_DEVICE_EXTENSION,
+                                        MiniPortDeviceExtension);
 
-  Entry = DeviceExtension->LunExtensionListHead.Flink;
-  while (Entry != &DeviceExtension->LunExtensionListHead)
+    /* Go through all buses */
+    for (BusNumber = 0; BusNumber < 8; BusNumber++)
     {
-      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))
+        /* Go through all targets */
+        for (Target = 0; Target < DeviceExtension->MaxTargedIds; Target++)
         {
-         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;
-    }
-}
-
+            /* Get logical unit list head */
+            LunExtension = DeviceExtension->LunExtensionList[Target % 8];
 
-/*
- * @implemented
- */
-#undef ScsiPortConvertPhysicalAddressToUlong
-ULONG STDCALL
-ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
-{
-  DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
-  return(Address.u.LowPart);
+            /* Go through all logical units */
+            while (LunExtension)
+            {
+                /* Now match what caller asked with what we are at now */
+                if ((PathId == SP_UNTAGGED || PathId == LunExtension->PathId) &&
+                    (TargetId == SP_UNTAGGED || TargetId == LunExtension->TargetId) &&
+                    (Lun == SP_UNTAGGED || Lun == LunExtension->Lun))
+                {
+                    /* Yes, that's what caller asked for. Complete abort requests */
+                    if (LunExtension->CompletedAbortRequests)
+                    {
+                        /* TODO: Save SrbStatus in this request */
+                        DPRINT1("Completing abort request without setting SrbStatus!\n");
+
+                        /* Issue a notification request */
+                        ScsiPortNotification(RequestComplete,
+                                             HwDeviceExtension,
+                                             LunExtension->CompletedAbortRequests);
+                    }
+
+                    /* Complete the request using our helper */
+                    SpiCompleteRequest(HwDeviceExtension,
+                                       &LunExtension->SrbInfo,
+                                       SrbStatus);
+
+                    /* Go through the queue and complete everything there too */
+                    ListEntry = LunExtension->SrbInfo.Requests.Flink;
+                    while (ListEntry != &LunExtension->SrbInfo.Requests)
+                    {
+                        /* Get the actual SRB info entry */
+                        SrbInfo = CONTAINING_RECORD(ListEntry,
+                                                    SCSI_REQUEST_BLOCK_INFO,
+                                                    Requests);
+
+                        /* Complete it */
+                        SpiCompleteRequest(HwDeviceExtension,
+                                           SrbInfo,
+                                           SrbStatus);
+
+                        /* Advance to the next request in queue */
+                        ListEntry = SrbInfo->Requests.Flink;
+                    }
+                }
+
+                /* Advance to the next one */
+                LunExtension = LunExtension->Next;
+            }
+        }
+    }
 }
 
-
 /*
  * @unimplemented
  */
-VOID STDCALL
+VOID NTAPI
 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
 {
   DPRINT("ScsiPortFlushDma()\n");
@@ -302,39 +418,51 @@ ScsiPortFlushDma(IN PVOID HwDeviceExtension)
 /*
  * @implemented
  */
-VOID STDCALL
+VOID NTAPI
 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
                       IN PVOID MappedAddress)
 {
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  PSCSI_PORT_DEVICE_BASE DeviceBase;
-  PLIST_ENTRY Entry;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    PMAPPED_ADDRESS NextMa, LastMa;
 
-  DPRINT("ScsiPortFreeDeviceBase() called\n");
+    //DPRINT("ScsiPortFreeDeviceBase() called\n");
 
-  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
-                                     SCSI_PORT_DEVICE_EXTENSION,
-                                     MiniPortDeviceExtension);
-  if (IsListEmpty(&DeviceExtension->DeviceBaseListHead))
-    return;
+    DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+                                        SCSI_PORT_DEVICE_EXTENSION,
+                                        MiniPortDeviceExtension);
+
+    /* Initialize our pointers */
+    NextMa = DeviceExtension->MappedAddressList;
+    LastMa = NextMa;
 
-  Entry = DeviceExtension->DeviceBaseListHead.Flink;
-  while (Entry != &DeviceExtension->DeviceBaseListHead)
+    while (NextMa)
     {
-      DeviceBase = CONTAINING_RECORD(Entry,
-                                    SCSI_PORT_DEVICE_BASE,
-                                    List);
-      if (DeviceBase->MappedAddress == MappedAddress)
-       {
-         MmUnmapIoSpace(DeviceBase->MappedAddress,
-                        DeviceBase->NumberOfBytes);
-         RemoveEntryList(Entry);
-         ExFreePool(DeviceBase);
+        if (NextMa->MappedAddress == MappedAddress)
+        {
+            /* Unmap it first */
+            MmUnmapIoSpace(MappedAddress, NextMa->NumberOfBytes);
 
-         return;
-       }
+            /* Remove it from the list */
+            if (NextMa == DeviceExtension->MappedAddressList)
+            {
+                /* Remove the first entry */
+                DeviceExtension->MappedAddressList = NextMa->NextMappedAddress;
+            }
+            else
+            {
+                LastMa->NextMappedAddress = NextMa->NextMappedAddress;
+            }
 
-      Entry = Entry->Flink;
+            /* Free the resources and quit */
+            ExFreePool(NextMa);
+
+            return;
+        }
+        else
+        {
+            LastMa = NextMa;
+            NextMa = NextMa->NextMappedAddress;
+        }
     }
 }
 
@@ -342,7 +470,7 @@ ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
 /*
  * @implemented
  */
-ULONG STDCALL
+ULONG NTAPI
 ScsiPortGetBusData(IN PVOID DeviceExtension,
                   IN ULONG BusDataType,
                   IN ULONG SystemIoBusNumber,
@@ -350,18 +478,49 @@ ScsiPortGetBusData(IN PVOID DeviceExtension,
                   IN PVOID Buffer,
                   IN ULONG Length)
 {
-  return(HalGetBusData(BusDataType,
-                      SystemIoBusNumber,
-                      SlotNumber,
-                      Buffer,
-                      Length));
+    DPRINT("ScsiPortGetBusData()\n");
+
+    if (Length)
+    {
+        /* If Length is non-zero, just forward the call to
+        HalGetBusData() function */
+        return HalGetBusData(BusDataType,
+                             SystemIoBusNumber,
+                             SlotNumber,
+                             Buffer,
+                             Length);
+    }
+
+    /* We have a more complex case here */
+    UNIMPLEMENTED;
+    return 0;
 }
 
+/*
+ * @implemented
+ */
+ULONG NTAPI
+ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
+                           IN ULONG BusDataType,
+                           IN ULONG SystemIoBusNumber,
+                           IN ULONG SlotNumber,
+                           IN PVOID Buffer,
+                           IN ULONG Offset,
+                           IN ULONG Length)
+{
+    DPRINT("ScsiPortSetBusDataByOffset()\n");
+    return HalSetBusDataByOffset(BusDataType,
+                                 SystemIoBusNumber,
+                                 SlotNumber,
+                                 Buffer,
+                                 Offset,
+                                 Length);
+}
 
 /*
  * @implemented
  */
-PVOID STDCALL
+PVOID NTAPI
 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
                      IN INTERFACE_TYPE BusType,
                      IN ULONG SystemIoBusNumber,
@@ -369,60 +528,65 @@ ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
                      IN ULONG NumberOfBytes,
                      IN BOOLEAN InIoSpace)
 {
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  PHYSICAL_ADDRESS TranslatedAddress;
-  PSCSI_PORT_DEVICE_BASE DeviceBase;
-  ULONG AddressSpace;
-  PVOID MappedAddress;
-
-  DPRINT ("ScsiPortGetDeviceBase() called\n");
-
-  AddressSpace = (ULONG)InIoSpace;
-  if (HalTranslateBusAddress(BusType,
-                            SystemIoBusNumber,
-                            IoAddress,
-                            &AddressSpace,
-                            &TranslatedAddress) == FALSE)
-    return NULL;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    PHYSICAL_ADDRESS TranslatedAddress;
+    PMAPPED_ADDRESS DeviceBase;
+    ULONG AddressSpace;
+    PVOID MappedAddress;
+
+    //DPRINT ("ScsiPortGetDeviceBase() called\n");
+
+    DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+                                        SCSI_PORT_DEVICE_EXTENSION,
+                                        MiniPortDeviceExtension);
+
+    AddressSpace = (ULONG)InIoSpace;
+    if (HalTranslateBusAddress(BusType,
+                               SystemIoBusNumber,
+                               IoAddress,
+                               &AddressSpace,
+                               &TranslatedAddress) == FALSE)
+    {
+        return NULL;
+    }
 
-  /* i/o space */
-  if (AddressSpace != 0)
-    return((PVOID)TranslatedAddress.u.LowPart);
+    /* i/o space */
+    if (AddressSpace != 0)
+        return((PVOID)(ULONG_PTR)TranslatedAddress.QuadPart);
 
-  MappedAddress = MmMapIoSpace(TranslatedAddress,
-                              NumberOfBytes,
-                              MmNonCached);
+    MappedAddress = MmMapIoSpace(TranslatedAddress,
+                                 NumberOfBytes,
+                                 FALSE);
 
-  DeviceBase = ExAllocatePool(NonPagedPool,
-                             sizeof(SCSI_PORT_DEVICE_BASE));
-  if (DeviceBase == NULL)
-    return(MappedAddress);
+    DeviceBase = ExAllocatePoolWithTag(NonPagedPool,
+                                sizeof(MAPPED_ADDRESS), TAG_SCSIPORT);
 
-  DeviceBase->MappedAddress = MappedAddress;
-  DeviceBase->NumberOfBytes = NumberOfBytes;
-  DeviceBase->IoAddress = IoAddress;
-  DeviceBase->SystemIoBusNumber = SystemIoBusNumber;
+    if (DeviceBase == NULL)
+        return MappedAddress;
 
-  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
-                                     SCSI_PORT_DEVICE_EXTENSION,
-                                     MiniPortDeviceExtension);
+    DeviceBase->MappedAddress = MappedAddress;
+    DeviceBase->NumberOfBytes = NumberOfBytes;
+    DeviceBase->IoAddress = IoAddress;
+    DeviceBase->BusNumber = SystemIoBusNumber;
 
-  InsertHeadList(&DeviceExtension->DeviceBaseListHead,
-                &DeviceBase->List);
+    /* Link it to the Device Extension list */
+    DeviceBase->NextMappedAddress = DeviceExtension->MappedAddressList;
+    DeviceExtension->MappedAddressList = DeviceBase;
 
-  return(MappedAddress);
+    return MappedAddress;
 }
 
-
 /*
- * @implemented
+ * @unimplemented
  */
-PVOID STDCALL
+PVOID NTAPI
 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
                       IN UCHAR PathId,
                       IN UCHAR TargetId,
                       IN UCHAR Lun)
 {
+    UNIMPLEMENTED;
+#if 0
   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
   PSCSI_PORT_LUN_EXTENSION LunExtension;
   PLIST_ENTRY Entry;
@@ -450,120 +614,82 @@ ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
 
       Entry = Entry->Flink;
     }
-
+#endif
   return NULL;
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
-SCSI_PHYSICAL_ADDRESS STDCALL
+SCSI_PHYSICAL_ADDRESS NTAPI
 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
-                          IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
-                          IN PVOID VirtualAddress,
-                          OUT ULONG *Length)
+                           IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
+                           IN PVOID VirtualAddress,
+                           OUT ULONG *Length)
 {
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  SCSI_PHYSICAL_ADDRESS PhysicalAddress;
-  SCSI_PHYSICAL_ADDRESS NextPhysicalAddress;
-  ULONG BufferLength = 0;
-  ULONG Offset;
-  PVOID EndAddress;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    SCSI_PHYSICAL_ADDRESS PhysicalAddress;
+    ULONG BufferLength = 0;
+    ULONG Offset;
+    PSCSI_SG_ADDRESS SGList;
+    PSCSI_REQUEST_BLOCK_INFO SrbInfo;
 
-  DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
-        HwDeviceExtension, Srb, VirtualAddress, Length);
+    DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
+        HwDeviceExtension, Srb, VirtualAddress, Length);
 
-  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
-                                     SCSI_PORT_DEVICE_EXTENSION,
-                                     MiniPortDeviceExtension);
+    DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+                                        SCSI_PORT_DEVICE_EXTENSION,
+                                        MiniPortDeviceExtension);
 
-  if (Length != NULL)
+    if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress)
     {
-      *Length = 0;
+        /* Simply look it up in the allocated common buffer */
+        Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer;
+
+        BufferLength = DeviceExtension->CommonBufferLength - Offset;
+        PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset;
     }
-  if (Srb == NULL)
+    else if (DeviceExtension->MapRegisters)
     {
-      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
+        /* Scatter-gather list must be used */
+        SrbInfo = SpiGetSrbData(DeviceExtension,
+                               Srb->PathId,
+                               Srb->TargetId,
+                               Srb->Lun,
+                               Srb->QueueTag);
+
+        SGList = SrbInfo->ScatterGather;
+
+        /* Find needed item in the SG list */
+        Offset = (PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer;
+        while (Offset >= SGList->Length)
         {
-         /*
-          * The given virtual address is not within the range
-          * of the drivers uncached extension or srb extension.
-          */
-         /*
-          * FIXME:
-          *   Check if the address is a sense info buffer of an active srb.
-          */
-         PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
-         if (PhysicalAddress.QuadPart == 0LL)
-           {
-             CHECKPOINT;
-             return PhysicalAddress;
-           }
-         BufferLength = PAGE_SIZE - PhysicalAddress.u.LowPart % PAGE_SIZE;
-       }
-    }
-  else
-    {
-      EndAddress = (PVOID)((ULONG_PTR)Srb->DataBuffer + Srb->DataTransferLength);
-      if (VirtualAddress == NULL)
-       {
-         VirtualAddress = Srb->DataBuffer;
-       }
-      else if (VirtualAddress < Srb->DataBuffer || VirtualAddress >= EndAddress)
-       {
-         EndAddress = (PVOID)((ULONG_PTR)Srb->SenseInfoBuffer + Srb->SenseInfoBufferLength);
-         if (VirtualAddress < Srb->SenseInfoBuffer || VirtualAddress >= EndAddress)
-           {
-             PhysicalAddress.QuadPart = 0LL;
-             CHECKPOINT;
-             return PhysicalAddress;
-           }
-       }
-
-      PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
-      if (PhysicalAddress.QuadPart == 0LL)
-       {
-         CHECKPOINT;
-         return PhysicalAddress;
-       }
+            Offset -= SGList->Length;
+            SGList++;
+        }
 
-      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);
-       }
+        /* We're done, store length and physical address */
+        BufferLength = SGList->Length - Offset;
+        PhysicalAddress.QuadPart = SGList->PhysicalAddress.QuadPart + Offset;
     }
-  if (Length != NULL)
+    else
     {
-      *Length = BufferLength;
+        /* Nothing */
+        *Length = 0;
+        PhysicalAddress.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE);
     }
-  DPRINT("Address %I64x, Length %d\n", PhysicalAddress.QuadPart, BufferLength);
-  return PhysicalAddress;
+
+    *Length = BufferLength;
+    return PhysicalAddress;
 }
 
 
 /*
  * @unimplemented
  */
-PSCSI_REQUEST_BLOCK STDCALL
-ScsiPortGetSrb(IN PVOID HwDeviceExtension,
+PSCSI_REQUEST_BLOCK NTAPI
+ScsiPortGetSrb(IN PVOID DeviceExtension,
               IN UCHAR PathId,
               IN UCHAR TargetId,
               IN UCHAR Lun,
@@ -578,123 +704,277 @@ ScsiPortGetSrb(IN PVOID HwDeviceExtension,
 /*
  * @implemented
  */
-PVOID STDCALL
+PVOID NTAPI
 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
                             IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
                             IN ULONG NumberOfBytes)
 {
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  DEVICE_DESCRIPTION DeviceDescription;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    DEVICE_DESCRIPTION DeviceDescription;
+    ULONG MapRegistersCount;
+    NTSTATUS Status;
 
-  DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
-        HwDeviceExtension, ConfigInfo, NumberOfBytes);
+    DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
+        HwDeviceExtension, ConfigInfo, NumberOfBytes);
 
-  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
-                                     SCSI_PORT_DEVICE_EXTENSION,
-                                     MiniPortDeviceExtension);
+    DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+                                        SCSI_PORT_DEVICE_EXTENSION,
+                                        MiniPortDeviceExtension);
 
-  /* Check for allocated common DMA buffer */
-  if (DeviceExtension->VirtualAddress != NULL)
-    {
-      DPRINT1("The HBA has already got a common DMA buffer!\n");
-      return NULL;
-    }
-
-  /* Check for DMA adapter object */
-  if (DeviceExtension->AdapterObject == NULL)
-    {
-      /* Initialize DMA adapter description */
-      RtlZeroMemory(&DeviceDescription,
-                   sizeof(DEVICE_DESCRIPTION));
-      DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
-      DeviceDescription.Master = ConfigInfo->Master;
-      DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
-      DeviceDescription.DemandMode = ConfigInfo->DemandMode;
-      DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
-      DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
-      DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
-      DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
-      DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
-      DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
-      DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
-      DeviceDescription.DmaPort = ConfigInfo->DmaPort;
-
-      /* Get a DMA adapter object */
-      DeviceExtension->AdapterObject = HalGetAdapter(&DeviceDescription,
-                                                    &DeviceExtension->MapRegisterCount);
-      if (DeviceExtension->AdapterObject == NULL)
-       {
-         DPRINT1("HalGetAdapter() failed\n");
-         return NULL;
-       }
+    /* Check for allocated common DMA buffer */
+    if (DeviceExtension->SrbExtensionBuffer != NULL)
+    {
+        DPRINT1("The HBA has already got a common DMA buffer!\n");
+        return NULL;
     }
-  if (DeviceExtension->SrbExtensionSize > 0)
+
+    /* Check for DMA adapter object */
+    if (DeviceExtension->AdapterObject == NULL)
     {
-      PVOID Buffer;
-      DeviceExtension->CurrentSrbExtensions = 0;
-      if (DeviceExtension->PortConfig->MultipleRequestPerLu)
+        /* Initialize DMA adapter description */
+        RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+        DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+        DeviceDescription.Master = ConfigInfo->Master;
+        DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
+        DeviceDescription.DemandMode = ConfigInfo->DemandMode;
+        DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
+        DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
+        DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
+        DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
+        DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
+        DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
+        DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
+        DeviceDescription.DmaPort = ConfigInfo->DmaPort;
+
+        /* Get a DMA adapter object */
+        DeviceExtension->AdapterObject =
+            HalGetAdapter(&DeviceDescription, &MapRegistersCount);
+
+        /* Fail in case of error */
+        if (DeviceExtension->AdapterObject == NULL)
         {
-          DeviceExtension->MaxSrbExtensions = 1024;
-       }
-      else
+            DPRINT1("HalGetAdapter() failed\n");
+            return NULL;
+        }
+
+        /* Set number of physical breaks */
+        if (ConfigInfo->NumberOfPhysicalBreaks != 0 &&
+            MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks)
         {
-         DeviceExtension->MaxSrbExtensions = 32;
-       }
-      Buffer = ExAllocatePool(NonPagedPool, ROUND_UP(DeviceExtension->MaxSrbExtensions / 8, sizeof(ULONG)));
-      if (Buffer == NULL)
+            DeviceExtension->PortCapabilities.MaximumPhysicalPages =
+                ConfigInfo->NumberOfPhysicalBreaks;
+        }
+        else
         {
-          KEBUGCHECK(0);
-          return NULL;
+            DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount;
         }
-      RtlInitializeBitMap(&DeviceExtension->SrbExtensionAllocMap, Buffer, DeviceExtension->MaxSrbExtensions);
-      RtlClearAllBits(&DeviceExtension->SrbExtensionAllocMap);
     }
 
-  /* Allocate a common DMA buffer */
-  DeviceExtension->CommonBufferLength =
-    NumberOfBytes + PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * DeviceExtension->MaxSrbExtensions);
-  DeviceExtension->VirtualAddress =
-    HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
-                           DeviceExtension->CommonBufferLength,
-                           &DeviceExtension->PhysicalAddress,
-                           FALSE);
-  if (DeviceExtension->VirtualAddress == NULL)
+    /* Update auto request sense feature */
+    DeviceExtension->SupportsAutoSense = ConfigInfo->AutoRequestSense;
+
+    /* Update Srb extension size */
+    if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize)
+        DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize;
+
+    /* Update Srb extension alloc flag */
+    if (ConfigInfo->AutoRequestSense || DeviceExtension->SrbExtensionSize)
+        DeviceExtension->NeedSrbExtensionAlloc = TRUE;
+
+    /* Allocate a common DMA buffer */
+    Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status);
+        return NULL;
+    }
+
+    return DeviceExtension->NonCachedExtension;
+}
+
+static NTSTATUS
+SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize)
+{
+    PVOID *SrbExtension, CommonBuffer;
+    ULONG CommonBufferLength, BufSize;
+
+    /* If size is 0, set it to 16 */
+    if (!DeviceExtension->SrbExtensionSize)
+        DeviceExtension->SrbExtensionSize = 16;
+
+    /* Calculate size */
+    BufSize = DeviceExtension->SrbExtensionSize;
+
+    /* Add autosense data size if needed */
+    if (DeviceExtension->SupportsAutoSense)
+        BufSize += sizeof(SENSE_DATA);
+
+
+    /* Round it */
+    BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
+
+    /* Sum up into the total common buffer length, and round it to page size */
+    CommonBufferLength =
+        ROUND_TO_PAGES(NonCachedSize + BufSize * DeviceExtension->RequestsNumber);
+
+    /* Allocate it */
+    if (!DeviceExtension->AdapterObject)
+    {
+        /* From nonpaged pool if there is no DMA */
+        CommonBuffer = ExAllocatePoolWithTag(NonPagedPool, CommonBufferLength, TAG_SCSIPORT);
+    }
+    else
+    {
+        /* Perform a full request since we have a DMA adapter*/
+        CommonBuffer = HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
+            CommonBufferLength,
+            &DeviceExtension->PhysicalAddress,
+            FALSE );
+    }
+
+    /* Fail in case of error */
+    if (!CommonBuffer)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* Zero it */
+    RtlZeroMemory(CommonBuffer, CommonBufferLength);
+
+    /* Store its size in Device Extension */
+    DeviceExtension->CommonBufferLength = CommonBufferLength;
+
+    /* SrbExtension buffer is located at the beginning of the buffer */
+    DeviceExtension->SrbExtensionBuffer = CommonBuffer;
+
+    /* Non-cached extension buffer is located at the end of
+       the common buffer */
+    if (NonCachedSize)
+    {
+        CommonBufferLength -=  NonCachedSize;
+        DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength;
+    }
+    else
+    {
+        DeviceExtension->NonCachedExtension = NULL;
+    }
+
+    if (DeviceExtension->NeedSrbExtensionAlloc)
     {
-      DPRINT1("HalAllocateCommonBuffer() failed!\n");
-      DeviceExtension->CommonBufferLength = 0;
-      return NULL;
+        /* Look up how many SRB data structures we need */
+        DeviceExtension->SrbDataCount = CommonBufferLength / BufSize;
+
+        /* Initialize the free SRB extensions list */
+        SrbExtension = (PVOID *)CommonBuffer;
+        DeviceExtension->FreeSrbExtensions = SrbExtension;
+
+        /* Fill the remainding pointers (if we have more than 1 SRB) */
+        while (CommonBufferLength >= 2 * BufSize)
+        {
+            *SrbExtension = (PVOID*)((PCHAR)SrbExtension + BufSize);
+            SrbExtension = *SrbExtension;
+
+            CommonBufferLength -= BufSize;
+        }
     }
 
-  return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress +
-                 PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * DeviceExtension->MaxSrbExtensions));
+    return STATUS_SUCCESS;
 }
 
 
+
 /*
  * @implemented
  */
-PVOID STDCALL
+PVOID NTAPI
 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
-                         IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
+                          IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
 {
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  ULONG Offset;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    ULONG Offset;
 
-  DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
-        HwDeviceExtension, PhysicalAddress.QuadPart);
+    DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
+        HwDeviceExtension, PhysicalAddress.QuadPart);
 
-  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
-                                     SCSI_PORT_DEVICE_EXTENSION,
-                                     MiniPortDeviceExtension);
+    DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+                                        SCSI_PORT_DEVICE_EXTENSION,
+                                        MiniPortDeviceExtension);
 
-  if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
-    return NULL;
+    if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
+        return NULL;
 
-  Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
-  if (Offset >= DeviceExtension->CommonBufferLength)
-    return NULL;
+    Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
+
+    if (Offset >= DeviceExtension->CommonBufferLength)
+        return NULL;
+
+    return (PVOID)((ULONG_PTR)DeviceExtension->SrbExtensionBuffer + Offset);
+}
+
+static VOID
+SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo, PUNICODE_STRING RegistryPath)
+{
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING KeyName;
+    NTSTATUS Status;
+
+    /* Open the service key */
+    InitializeObjectAttributes(&ObjectAttributes,
+                               RegistryPath,
+                               OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+
+    Status = ZwOpenKey(&ConfigInfo->ServiceKey,
+                       KEY_READ,
+                       &ObjectAttributes);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath, Status);
+        ConfigInfo->ServiceKey = NULL;
+    }
+
+    /* If we could open driver's service key, then proceed to the Parameters key */
+    if (ConfigInfo->ServiceKey != NULL)
+    {
+        RtlInitUnicodeString(&KeyName, L"Parameters");
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &KeyName,
+                                   OBJ_CASE_INSENSITIVE,
+                                   ConfigInfo->ServiceKey,
+                                   (PSECURITY_DESCRIPTOR) NULL);
+
+        /* Try to open it */
+        Status = ZwOpenKey(&ConfigInfo->DeviceKey,
+                           KEY_READ,
+                           &ObjectAttributes);
+
+        if (NT_SUCCESS(Status))
+        {
+            /* Yes, Parameters key exist, and it must be used instead of
+               the Service key */
+            ZwClose(ConfigInfo->ServiceKey);
+            ConfigInfo->ServiceKey = ConfigInfo->DeviceKey;
+            ConfigInfo->DeviceKey = NULL;
+        }
+    }
 
-  return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + Offset);
+    if (ConfigInfo->ServiceKey != NULL)
+    {
+        /* Open the Device key */
+        RtlInitUnicodeString(&KeyName, L"Device");
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &KeyName,
+                                   OBJ_CASE_INSENSITIVE,
+                                   ConfigInfo->ServiceKey,
+                                   NULL);
+
+        /* We don't check for failure here - not needed */
+        ZwOpenKey(&ConfigInfo->DeviceKey,
+                  KEY_READ,
+                  &ObjectAttributes);
+    }
 }
 
 
@@ -727,498 +1007,818 @@ ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
  * @implemented
  */
 
-ULONG STDCALL
+ULONG NTAPI
 ScsiPortInitialize(IN PVOID Argument1,
                   IN PVOID Argument2,
                   IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
                   IN PVOID HwContext)
 {
-  PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
-//  PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  PCONFIGURATION_INFORMATION SystemConfig;
-  PPORT_CONFIGURATION_INFORMATION PortConfig;
-  ULONG DeviceExtensionSize;
-  ULONG PortConfigSize;
-  BOOLEAN Again;
-  BOOLEAN DeviceFound = FALSE;
-  ULONG i;
-  ULONG Result;
-  NTSTATUS Status;
-  ULONG MaxBus;
-  ULONG BusNumber;
-  PCI_SLOT_NUMBER SlotNumber;
+    PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
+    PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL;
+    PCONFIGURATION_INFORMATION SystemConfig;
+    PPORT_CONFIGURATION_INFORMATION PortConfig;
+    PORT_CONFIGURATION_INFORMATION InitialPortConfig;
+    CONFIGURATION_INFO ConfigInfo;
+    ULONG DeviceExtensionSize;
+    ULONG PortConfigSize;
+    BOOLEAN Again;
+    BOOLEAN DeviceFound = FALSE;
+    BOOLEAN FirstConfigCall = TRUE;
+    ULONG Result;
+    NTSTATUS Status;
+    ULONG MaxBus;
+    ULONG BusNumber = 0;
+    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;
+
+    PCM_RESOURCE_LIST ResourceList;
+    BOOLEAN Conflict;
+
+
+    DPRINT ("ScsiPortInitialize() called!\n");
+
+    /* Check params for validity */
+    if ((HwInitializationData->HwInitialize == NULL) ||
+        (HwInitializationData->HwStartIo == NULL) ||
+        (HwInitializationData->HwInterrupt == NULL) ||
+        (HwInitializationData->HwFindAdapter == NULL) ||
+        (HwInitializationData->HwResetBus == NULL))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
 
-  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;
+    /* Set handlers */
+    DriverObject->DriverStartIo = ScsiPortStartIo;
+    DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
+    DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
+    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
+    DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ScsiPortDeviceControl;
+    DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
 
+    /* Obtain configuration information */
+    SystemConfig = IoGetConfigurationInformation();
 
-  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) ||
-      (HwInitializationData->HwFindAdapter == NULL) ||
-      (HwInitializationData->HwResetBus == NULL))
-    return(STATUS_INVALID_PARAMETER);
-
-  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();
-
-  DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
-    HwInitializationData->DeviceExtensionSize;
-  PortConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION) +
-    HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE);
-
-
-  MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
-  DPRINT("MaxBus: %lu\n", MaxBus);
-
-  PortDeviceObject = NULL;
-  BusNumber = 0;
-  SlotNumber.u.AsULONG = 0;
-  while (TRUE)
-    {
-      /* Create a unicode device name */
-      swprintf (NameBuffer,
-               L"\\Device\\ScsiPort%lu",
-               SystemConfig->ScsiPortCount);
-      RtlInitUnicodeString (&DeviceName,
-                           NameBuffer);
-
-      DPRINT("Creating device: %wZ\n", &DeviceName);
-
-      /* Create the port device */
-      Status = IoCreateDevice (DriverObject,
-                              DeviceExtensionSize,
-                              &DeviceName,
-                              FILE_DEVICE_CONTROLLER,
-                              0,
-                              FALSE,
-                              &PortDeviceObject);
-      if (!NT_SUCCESS(Status))
-       {
-         DbgPrint ("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
-         PortDeviceObject = NULL;
-         goto ByeBye;
-       }
+    /* Zero the internal configuration info structure */
+    RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO));
 
-      DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
-
-      /* Increase the stacksize. We reenter our device on IOCTL_SCSI_MINIPORT */
-      PortDeviceObject->StackSize++;
-
-      /* Set the buffering strategy here... */
-      PortDeviceObject->Flags |= DO_DIRECT_IO;
-      PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
-
-      DeviceExtension = PortDeviceObject->DeviceExtension;
-      RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
-      DeviceExtension->Length = DeviceExtensionSize;
-      DeviceExtension->DeviceObject = PortDeviceObject;
-      DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
-
-      DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
-      DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
-      DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
-      DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
-      DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
-
-      DeviceExtension->AdapterObject = NULL;
-      DeviceExtension->MapRegisterCount = 0;
-      DeviceExtension->PhysicalAddress.QuadPart = 0ULL;
-      DeviceExtension->VirtualAddress = NULL;
-      DeviceExtension->CommonBufferLength = 0;
-
-      /* Initialize the device base list */
-      InitializeListHead (&DeviceExtension->DeviceBaseListHead);
-
-      /* Initialize the irp lists */
-      InitializeListHead (&DeviceExtension->PendingIrpListHead);
-      DeviceExtension->NextIrp = NULL;
-      DeviceExtension->PendingIrpCount = 0;
-      DeviceExtension->ActiveIrpCount = 0;
-
-      /* Initialize LUN-Extension list */
-      InitializeListHead (&DeviceExtension->LunExtensionListHead);
-
-      /* Initialize the spin lock in the controller extension */
-      KeInitializeSpinLock (&DeviceExtension->Lock);
-
-      /* Initialize the DPC object */
-      IoInitializeDpcRequest (PortDeviceObject,
-                             ScsiPortDpc);
-
-      /* Initialize the device timer */
-      DeviceExtension->TimerState = IDETimerIdle;
-      DeviceExtension->TimerCount = 0;
-      IoInitializeTimer (PortDeviceObject,
-                        ScsiPortIoTimer,
-                        DeviceExtension);
-
-      /* Allocate and initialize port configuration info */
-      DeviceExtension->PortConfig = ExAllocatePool (NonPagedPool,
-                                                   PortConfigSize);
-      if (DeviceExtension->PortConfig == NULL)
-       {
-         Status = STATUS_INSUFFICIENT_RESOURCES;
-         goto ByeBye;
-       }
-      RtlZeroMemory (DeviceExtension->PortConfig,
-                    PortConfigSize);
-
-      PortConfig = DeviceExtension->PortConfig;
-      PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
-      PortConfig->SystemIoBusNumber = BusNumber;
-      PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
-      PortConfig->InterruptMode =
-       (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
-      PortConfig->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
-      PortConfig->NumberOfPhysicalBreaks = SP_UNINITIALIZED_VALUE;
-      PortConfig->DmaChannel = SP_UNINITIALIZED_VALUE;
-      PortConfig->DmaPort = SP_UNINITIALIZED_VALUE;
-      PortConfig->DmaWidth = 0;
-      PortConfig->DmaSpeed = Compatible;
-      PortConfig->AlignmentMask = 0;
-      PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
-      PortConfig->NumberOfBuses = 0;
-
-      for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
-       PortConfig->InitiatorBusId[i] = 255;
-
-      PortConfig->ScatterGather = FALSE;
-      PortConfig->Master = FALSE;
-      PortConfig->CachesData = FALSE;
-      PortConfig->AdapterScansDown = FALSE;
-      PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
-      PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
-      PortConfig->Dma32BitAddresses = FALSE;
-      PortConfig->DemandMode = FALSE;
-      PortConfig->MapBuffers = HwInitializationData->MapBuffers;
-      PortConfig->NeedPhysicalAddresses = HwInitializationData->NeedPhysicalAddresses;
-      PortConfig->TaggedQueuing = HwInitializationData->TaggedQueuing;
-      PortConfig->AutoRequestSense = HwInitializationData->AutoRequestSense;
-      PortConfig->MultipleRequestPerLu = HwInitializationData->MultipleRequestPerLu;
-      PortConfig->ReceiveEvent = HwInitializationData->ReceiveEvent;
-      PortConfig->RealModeInitialized = FALSE;
-      PortConfig->BufferAccessScsiPortControlled = FALSE;
-      PortConfig->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS;
-//      PortConfig->MaximumNumberOfLogicalUnits = SCSI_MAXIMUM_LOGICAL_UNITS;
-
-      PortConfig->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
-      PortConfig->SpecificLuExtensionSize = HwInitializationData->SpecificLuExtensionSize;
-
-      PortConfig->AccessRanges = (ACCESS_RANGE(*)[])(PortConfig + 1);
+    /* Zero starting slot number */
+    SlotNumber.u.AsULONG = 0;
 
-      /* Search for matching PCI device */
-      if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
-         (HwInitializationData->VendorIdLength > 0) &&
-         (HwInitializationData->VendorId != NULL) &&
-         (HwInitializationData->DeviceIdLength > 0) &&
-         (HwInitializationData->DeviceId != NULL))
-       {
-         /* Get PCI device data */
-         DPRINT("VendorId '%.*s'  DeviceId '%.*s'\n",
-                HwInitializationData->VendorIdLength,
-                HwInitializationData->VendorId,
-                HwInitializationData->DeviceIdLength,
-                HwInitializationData->DeviceId);
-
-         if (!SpiGetPciConfigData (HwInitializationData,
-                                   PortConfig,
-                                   BusNumber,
-                                   &SlotNumber))
-           {
-             Status = STATUS_UNSUCCESSFUL;
-             goto ByeBye;
-           }
-       }
+    /* Allocate space for access ranges */
+    if (HwInitializationData->NumberOfAccessRanges)
+    {
+        ConfigInfo.AccessRanges =
+            ExAllocatePoolWithTag(PagedPool,
+            HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT);
 
-      /* Note: HwFindAdapter is called once for each bus */
-      Again = FALSE;
-      DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
-      Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension,
-                                                    HwContext,
-                                                    0,  /* BusInformation */
-                                                    "", /* ArgumentString */
-                                                    PortConfig,
-                                                    &Again);
-      DPRINT("HwFindAdapter() Result: %lu  Again: %s\n",
-            Result, (Again) ? "True" : "False");
+        /* Fail if failed */
+        if (ConfigInfo.AccessRanges == NULL)
+            return STATUS_INSUFFICIENT_RESOURCES;
+    }
 
-      if (Result == SP_RETURN_FOUND)
-       {
-         DPRINT("ScsiPortInitialize(): Found HBA! (%x)\n", PortConfig->BusInterruptVector);
+    /* Open registry keys */
+    SpiInitOpenKeys(&ConfigInfo, (PUNICODE_STRING)Argument2);
 
-#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);
+    /* Last adapter number = not known */
+    ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE;
 
-#endif
+    /* Calculate sizes of DeviceExtension and PortConfig */
+    DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
+        HwInitializationData->DeviceExtensionSize;
 
-          if (DeviceExtension->VirtualAddress == NULL && DeviceExtension->SrbExtensionSize)
-           {
-             ScsiPortGetUncachedExtension(&DeviceExtension->MiniPortDeviceExtension,
-                                          PortConfig,
-                                          0);
-           }
+    MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
+    DPRINT("MaxBus: %lu\n", MaxBus);
 
-         /* Register an interrupt handler for this device */
-         MappedIrq = HalGetInterruptVector(PortConfig->AdapterInterfaceType,
-                                           PortConfig->SystemIoBusNumber,
-                                           PortConfig->BusInterruptLevel,
-#if 1
-/*
- * FIXME:
- *   Something is wrong in our interrupt conecting code.
- *   The promise Ultra100TX driver returns 0 for BusInterruptVector
- *   and a nonzero value for BusInterruptLevel. The driver does only
- *   work with this fix.
- */
-                                           PortConfig->BusInterruptLevel,
-#else
-                                           PortConfig->BusInterruptVector,
-#endif
-                                           &Dirql,
-                                           &Affinity);
-         DPRINT("AdapterInterfaceType %x, SystemIoBusNumber %x, BusInterruptLevel %x, BusInterruptVector %x\n",
-                 PortConfig->AdapterInterfaceType, PortConfig->SystemIoBusNumber,
-                 PortConfig->BusInterruptLevel, PortConfig->BusInterruptVector);
-         Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
-                                     ScsiPortIsr,
-                                     DeviceExtension,
-                                     NULL,
-                                     MappedIrq,
-                                     Dirql,
-                                     Dirql,
-                                     PortConfig->InterruptMode,
-                                     TRUE,
-                                     Affinity,
-                                     FALSE);
-         if (!NT_SUCCESS(Status))
-           {
-             DbgPrint("Could not connect interrupt %d\n",
-                      PortConfig->BusInterruptVector);
-             goto ByeBye;
-           }
+    while (TRUE)
+    {
+        /* Create a unicode device name */
+        swprintf(NameBuffer,
+                 L"\\Device\\ScsiPort%lu",
+                 SystemConfig->ScsiPortCount);
+        RtlInitUnicodeString(&DeviceName, NameBuffer);
+
+        DPRINT("Creating device: %wZ\n", &DeviceName);
+
+        /* Create the port device */
+        Status = IoCreateDevice(DriverObject,
+                                DeviceExtensionSize,
+                                &DeviceName,
+                                FILE_DEVICE_CONTROLLER,
+                                0,
+                                FALSE,
+                                &PortDeviceObject);
+
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
+            PortDeviceObject = NULL;
+            break;
+        }
 
-         if (!(HwInitializationData->HwInitialize)(&DeviceExtension->MiniPortDeviceExtension))
-           {
-             DbgPrint("HwInitialize() failed!");
-             Status = STATUS_UNSUCCESSFUL;
-             goto ByeBye;
-           }
+        DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
+
+        /* Set the buffering strategy here... */
+        PortDeviceObject->Flags |= DO_DIRECT_IO;
+        PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */
+
+        /* Fill Device Extension */
+        DeviceExtension = PortDeviceObject->DeviceExtension;
+        DeviceExtension->Length = DeviceExtensionSize;
+        DeviceExtension->DeviceObject = PortDeviceObject;
+        DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
+
+        /* Driver's routines... */
+        DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
+        DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
+        DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
+        DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
+        DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
+
+        /* Extensions sizes */
+        DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
+        DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
+        DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
+
+        /* Round Srb extension size to the quadword */
+        DeviceExtension->SrbExtensionSize =
+            ~(sizeof(LONGLONG) - 1) & (DeviceExtension->SrbExtensionSize +
+            sizeof(LONGLONG) - 1);
+
+        /* Fill some numbers (bus count, lun count, etc) */
+        DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
+        DeviceExtension->RequestsNumber = 16;
+
+        /* Initialize the spin lock in the controller extension */
+        KeInitializeSpinLock(&DeviceExtension->IrqLock);
+        KeInitializeSpinLock(&DeviceExtension->SpinLock);
+
+        /* Initialize the DPC object */
+        IoInitializeDpcRequest(PortDeviceObject,
+                               ScsiPortDpcForIsr);
+
+        /* Initialize the device timer */
+        DeviceExtension->TimerCount = -1;
+        IoInitializeTimer(PortDeviceObject,
+                          ScsiPortIoTimer,
+                          DeviceExtension);
+
+        /* Initialize miniport timer */
+        KeInitializeTimer(&DeviceExtension->MiniportTimer);
+        KeInitializeDpc(&DeviceExtension->MiniportTimerDpc,
+                        SpiMiniportTimerDpc,
+                        PortDeviceObject);
+
+CreatePortConfig:
+
+        Status = SpiCreatePortConfig(DeviceExtension,
+                                     HwInitializationData,
+                                     &ConfigInfo,
+                                     &InitialPortConfig,
+                                     FirstConfigCall);
+
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status);
+            break;
+        }
 
-         /* 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;
-           }
+        /* Allocate and initialize port configuration info */
+        PortConfigSize = (sizeof(PORT_CONFIGURATION_INFORMATION) +
+                          HwInitializationData->NumberOfAccessRanges *
+                          sizeof(ACCESS_RANGE) + 7) & ~7;
+        DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT);
 
-         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;
-           }
+        /* Fail if failed */
+        if (DeviceExtension->PortConfig == NULL)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            break;
+        }
 
-         PortCapabilities->MaximumPhysicalPages =
-           PortCapabilities->MaximumTransferLength / PAGE_SIZE;
-         PortCapabilities->SupportedAsynchronousEvents = 0; /* FIXME */
-         PortCapabilities->AlignmentMask =
-           PortConfig->AlignmentMask;
-         PortCapabilities->TaggedQueuing =
-           PortConfig->TaggedQueuing;
-         PortCapabilities->AdapterScansDown =
-           PortConfig->AdapterScansDown;
-         PortCapabilities->AdapterUsesPio = TRUE; /* FIXME */
-
-         /* Scan the adapter for devices */
-         SpiScanAdapter (DeviceExtension);
-
-         /* Build the registry device map */
-         SpiBuildDeviceMap (DeviceExtension,
-                            (PUNICODE_STRING)Argument2);
-
-         /* Create the dos device link */
-         swprintf(DosNameBuffer,
-                  L"\\??\\Scsi%lu:",
-                  SystemConfig->ScsiPortCount);
-         RtlInitUnicodeString(&DosDeviceName,
-                              DosNameBuffer);
-         IoCreateSymbolicLink(&DosDeviceName,
-                              &DeviceName);
-
-         /* Update the system configuration info */
-         if (PortConfig->AtdiskPrimaryClaimed == TRUE)
-           SystemConfig->AtDiskPrimaryAddressClaimed = TRUE;
-         if (PortConfig->AtdiskSecondaryClaimed == TRUE)
-           SystemConfig->AtDiskSecondaryAddressClaimed = TRUE;
-
-         SystemConfig->ScsiPortCount++;
-         PortDeviceObject = NULL;
-         DeviceFound = TRUE;
-       }
+        PortConfig = DeviceExtension->PortConfig;
+
+        /* Copy information here */
+        RtlCopyMemory(PortConfig,
+                      &InitialPortConfig,
+                      sizeof(PORT_CONFIGURATION_INFORMATION));
+
+
+        /* Copy extension sizes into the PortConfig */
+        PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize;
+        PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize;
+
+        /* Initialize Access ranges */
+        if (HwInitializationData->NumberOfAccessRanges != 0)
+        {
+            PortConfig->AccessRanges = (PVOID)(PortConfig+1);
+
+            /* Align to LONGLONG */
+            PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) + 7);
+            PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) & ~7);
+
+            /* Copy the data */
+            RtlCopyMemory(PortConfig->AccessRanges,
+                          ConfigInfo.AccessRanges,
+                          HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
+        }
+
+      /* Search for matching PCI device */
+      if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
+          (HwInitializationData->VendorIdLength > 0) &&
+          (HwInitializationData->VendorId != NULL) &&
+          (HwInitializationData->DeviceIdLength > 0) &&
+          (HwInitializationData->DeviceId != NULL))
+      {
+          PortConfig->BusInterruptLevel = 0;
+
+          /* Get PCI device data */
+          DPRINT("VendorId '%.*s'  DeviceId '%.*s'\n",
+                 HwInitializationData->VendorIdLength,
+                 HwInitializationData->VendorId,
+                 HwInitializationData->DeviceIdLength,
+                 HwInitializationData->DeviceId);
+
+          if (!SpiGetPciConfigData(DriverObject,
+                                   PortDeviceObject,
+                                   HwInitializationData,
+                                   PortConfig,
+                                   RegistryPath,
+                                   ConfigInfo.BusNumber,
+                                   &SlotNumber))
+          {
+              /* Continue to the next bus, nothing here */
+              ConfigInfo.BusNumber++;
+              DeviceExtension->PortConfig = NULL;
+              ExFreePool(PortConfig);
+              Again = FALSE;
+              goto CreatePortConfig;
+          }
+
+          if (!PortConfig->BusInterruptLevel)
+          {
+              /* Bypass this slot, because no interrupt was assigned */
+              DeviceExtension->PortConfig = NULL;
+              ExFreePool(PortConfig);
+              goto CreatePortConfig;
+          }
+      }
       else
-       {
-         DPRINT("HwFindAdapter() Result: %lu\n", Result);
+      {
+          DPRINT("Non-pci bus\n");
+      }
 
-         ExFreePool (PortConfig);
-         IoDeleteDevice (PortDeviceObject);
-         PortDeviceObject = NULL;
-       }
+      /* Note: HwFindAdapter is called once for each bus */
+      Again = FALSE;
+      DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
+      Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension,
+                                                     HwContext,
+                                                     0,  /* BusInformation */
+                                                     ConfigInfo.Parameter, /* ArgumentString */
+                                                     PortConfig,
+                                                     &Again);
+
+      DPRINT("HwFindAdapter() Result: %lu  Again: %s\n",
+             Result, (Again) ? "True" : "False");
+
+      /* Free MapRegisterBase, it's not needed anymore */
+      if (DeviceExtension->MapRegisterBase != NULL)
+      {
+          ExFreePool(DeviceExtension->MapRegisterBase);
+          DeviceExtension->MapRegisterBase = NULL;
+      }
+
+      /* If result is nothing good... */
+      if (Result != SP_RETURN_FOUND)
+      {
+          DPRINT("HwFindAdapter() Result: %lu\n", Result);
+
+          if (Result == SP_RETURN_NOT_FOUND)
+          {
+              /* We can continue on the next bus */
+              ConfigInfo.BusNumber++;
+              Again = FALSE;
+
+              DeviceExtension->PortConfig = NULL;
+              ExFreePool(PortConfig);
+              goto CreatePortConfig;
+          }
+
+          /* Otherwise, break */
+          Status = STATUS_INTERNAL_ERROR;
+          break;
+      }
+
+      DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
+          PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]);
+
+      /* If the SRB extension size was updated */
+      if (!DeviceExtension->NonCachedExtension &&
+          (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize))
+      {
+          /* Set it (rounding to LONGLONG again) */
+          DeviceExtension->SrbExtensionSize =
+              (PortConfig->SrbExtensionSize +
+               sizeof(LONGLONG)) & ~(sizeof(LONGLONG) - 1);
+      }
+
+      /* The same with LUN extension size */
+      if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize)
+          DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize;
+
+
+      if (!((HwInitializationData->AdapterInterfaceType == PCIBus) &&
+          (HwInitializationData->VendorIdLength > 0) &&
+          (HwInitializationData->VendorId != NULL) &&
+          (HwInitializationData->DeviceIdLength > 0) &&
+          (HwInitializationData->DeviceId != NULL)))
+      {
+          /* Construct a resource list */
+          ResourceList = SpiConfigToResource(DeviceExtension,
+                                             PortConfig);
+
+          if (ResourceList)
+          {
+              UNICODE_STRING UnicodeString;
+              RtlInitUnicodeString(&UnicodeString, L"ScsiAdapter");
+              DPRINT("Reporting resources\n");
+              Status = IoReportResourceUsage(&UnicodeString,
+                                             DriverObject,
+                                             NULL,
+                                             0,
+                                             PortDeviceObject,
+                                             ResourceList,
+                                             FIELD_OFFSET(CM_RESOURCE_LIST,
+                                                 List[0].PartialResourceList.PartialDescriptors) +
+                                                 ResourceList->List[0].PartialResourceList.Count
+                                                 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+                                             FALSE,
+                                             &Conflict);
+              ExFreePool(ResourceList);
+
+              /* In case of a failure or a conflict, break */
+              if (Conflict || (!NT_SUCCESS(Status)))
+              {
+                  if (Conflict)
+                      Status = STATUS_CONFLICTING_ADDRESSES;
+                  break;
+              }
+            }
+      }
+
+      /* Reset the Conflict var */
+      Conflict = FALSE;
+
+      /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
+      if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
+          DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
+      else
+          DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets;
+
+      DeviceExtension->BusNum = PortConfig->NumberOfBuses;
+      DeviceExtension->CachesData = PortConfig->CachesData;
+      DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent;
+      DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing;
+      DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu;
+
+      /* If something was disabled via registry - apply it */
+      if (ConfigInfo.DisableMultipleLun)
+          DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE;
+
+      if (ConfigInfo.DisableTaggedQueueing)
+          DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE;
+
+      /* Check if we need to alloc SRB data */
+      if (DeviceExtension->SupportsTaggedQueuing ||
+          DeviceExtension->MultipleReqsPerLun)
+      {
+          DeviceExtension->NeedSrbDataAlloc = TRUE;
+      }
+      else
+      {
+          DeviceExtension->NeedSrbDataAlloc = FALSE;
+      }
+
+      /* Get a pointer to the port capabilities */
+      PortCapabilities = &DeviceExtension->PortCapabilities;
+
+      /* Copy one field there */
+      DeviceExtension->MapBuffers = PortConfig->MapBuffers;
+      PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers;
+
+      if (DeviceExtension->AdapterObject == NULL &&
+          (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master))
+      {
+          DPRINT1("DMA is not supported yet\n");
+          ASSERT(FALSE);
+      }
+
+      if (DeviceExtension->SrbExtensionBuffer == NULL &&
+          (DeviceExtension->SrbExtensionSize != 0  ||
+          PortConfig->AutoRequestSense))
+      {
+          DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense;
+          DeviceExtension->NeedSrbExtensionAlloc = TRUE;
+
+          /* Allocate common buffer */
+          Status = SpiAllocateCommonBuffer(DeviceExtension, 0);
+
+          /* Check for failure */
+          if (!NT_SUCCESS(Status))
+              break;
+      }
+
+      /* Allocate SrbData, if needed */
+      if (DeviceExtension->NeedSrbDataAlloc)
+      {
+          ULONG Count;
+          PSCSI_REQUEST_BLOCK_INFO SrbData;
+
+          if (DeviceExtension->SrbDataCount != 0)
+              Count = DeviceExtension->SrbDataCount;
+          else
+              Count = DeviceExtension->RequestsNumber * 2;
+
+          /* Allocate the data */
+          SrbData = ExAllocatePoolWithTag(NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT);
+          if (SrbData == NULL)
+              return STATUS_INSUFFICIENT_RESOURCES;
+
+          RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO));
+
+          DeviceExtension->SrbInfo = SrbData;
+          DeviceExtension->FreeSrbInfo = SrbData;
+          DeviceExtension->SrbDataCount = Count;
+
+          /* Link it to the list */
+          while (Count > 0)
+          {
+              SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1);
+              SrbData++;
+              Count--;
+          }
+
+          /* Mark the last entry of the list */
+          SrbData--;
+          SrbData->Requests.Flink = NULL;
+      }
+
+      /* Initialize port capabilities */
+      PortCapabilities = &DeviceExtension->PortCapabilities;
+      PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
+      PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength;
+
+      if (PortConfig->ReceiveEvent)
+          PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION;
+
+      PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing;
+      PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown;
+
+      if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement)
+          PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask;
+
+      PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement;
+
+      if (PortCapabilities->MaximumPhysicalPages == 0)
+      {
+          PortCapabilities->MaximumPhysicalPages =
+              BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength);
+
+          /* Apply miniport's limits */
+          if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages)
+          {
+              PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks;
+          }
+      }
+
+      /* Deal with interrupts */
+      if (DeviceExtension->HwInterrupt == NULL ||
+          (PortConfig->BusInterruptLevel == 0 && PortConfig->BusInterruptVector == 0))
+      {
+          /* No interrupts */
+          KeInitializeSpinLock(&DeviceExtension->IrqLock);
+
+          /* FIXME: Use synchronization routine */
+          ASSERT("No interrupts branch requires changes in synchronization\n");
+
+          DeviceExtension->Interrupt = (PVOID)DeviceExtension;
+          DPRINT("No interrupts\n");
+
+      }
+      else
+      {
+          /* Are 2 interrupts needed? */
+          if (DeviceExtension->HwInterrupt != NULL &&
+              (PortConfig->BusInterruptLevel != 0 || PortConfig->BusInterruptVector != 0) &&
+              (PortConfig->BusInterruptLevel2 != 0 || PortConfig->BusInterruptVector2 != 0))
+          {
+              DPRINT1("2 interrupts requested! Not yet supported\n");
+              ASSERT(FALSE);
+          }
+          else
+          {
+              BOOLEAN InterruptShareable;
+
+              /* No, only 1 interrupt */
+              DPRINT("1 interrupt, IRQ is %d\n", PortConfig->BusInterruptLevel);
+
+              DeviceExtension->InterruptLevel = PortConfig->BusInterruptLevel;
+
+              /* Register an interrupt handler for this device */
+              MappedIrq = HalGetInterruptVector(PortConfig->AdapterInterfaceType,
+                                                PortConfig->SystemIoBusNumber,
+                                                PortConfig->BusInterruptLevel,
+                                                PortConfig->BusInterruptVector,
+                                                &Dirql,
+                                                &Affinity);
+
+              /* Determing IRQ sharability as usual */
+              if (PortConfig->AdapterInterfaceType == MicroChannel ||
+                  PortConfig->InterruptMode == LevelSensitive)
+              {
+                  InterruptShareable = TRUE;
+              }
+              else
+              {
+                  InterruptShareable = FALSE;
+              }
+
+              Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
+                                          (PKSERVICE_ROUTINE)ScsiPortIsr,
+                                          DeviceExtension,
+                                          NULL,
+                                          MappedIrq,
+                                          Dirql,
+                                          Dirql,
+                                          PortConfig->InterruptMode,
+                                          InterruptShareable,
+                                          Affinity,
+                                          FALSE);
+
+              if (!(NT_SUCCESS(Status)))
+              {
+                  DPRINT1("Could not connect interrupt %d\n",
+                      PortConfig->BusInterruptVector);
+                  DeviceExtension->Interrupt = NULL;
+                  break;
+              }
+
+          }
+      }
+
+      /* Save IoAddress (from access ranges) */
+      if (HwInitializationData->NumberOfAccessRanges != 0)
+      {
+          DeviceExtension->IoAddress =
+              ((*(PortConfig->AccessRanges))[0]).RangeStart.LowPart;
+
+          DPRINT("Io Address %x\n", DeviceExtension->IoAddress);
+      }
+
+      /* Set flag that it's allowed to disconnect during this command */
+      DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
+
+      /* Initialize counter of active requests (-1 means there are none) */
+      DeviceExtension->ActiveRequestCounter = -1;
+
+      /* Analyze what we have about DMA */
+      if (DeviceExtension->AdapterObject != NULL &&
+          PortConfig->Master &&
+          PortConfig->NeedPhysicalAddresses)
+      {
+          DeviceExtension->MapRegisters = TRUE;
+      }
+      else
+      {
+          DeviceExtension->MapRegisters = FALSE;
+      }
+
+      /* Call HwInitialize at DISPATCH_LEVEL */
+      KeRaiseIrql(DISPATCH_LEVEL, &Dirql);
+
+      if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
+                                  DeviceExtension->HwInitialize,
+                                  DeviceExtension->MiniPortDeviceExtension))
+      {
+          DPRINT1("HwInitialize() failed!\n");
+          KeLowerIrql(Dirql);
+          Status = STATUS_ADAPTER_HARDWARE_ERROR;
+          break;
+      }
+
+      /* Check if a notification is needed */
+      if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
+      {
+          /* Call DPC right away, because we're already at DISPATCH_LEVEL */
+          ScsiPortDpcForIsr(NULL,
+                            DeviceExtension->DeviceObject,
+                            NULL,
+                            NULL);
+      }
+
+      /* Lower irql back to what it was */
+      KeLowerIrql(Dirql);
+
+      /* Start our timer */
+      IoStartTimer(PortDeviceObject);
+
+      /* Initialize bus scanning information */
+      DeviceExtension->BusesConfig = ExAllocatePoolWithTag(PagedPool,
+          sizeof(PSCSI_BUS_SCAN_INFO) * DeviceExtension->PortConfig->NumberOfBuses
+          + sizeof(ULONG), TAG_SCSIPORT);
+
+      if (!DeviceExtension->BusesConfig)
+      {
+          DPRINT1("Out of resources!\n");
+          Status = STATUS_INSUFFICIENT_RESOURCES;
+          break;
+      }
+
+      /* Zero it */
+      RtlZeroMemory(DeviceExtension->BusesConfig,
+          sizeof(PSCSI_BUS_SCAN_INFO) * DeviceExtension->PortConfig->NumberOfBuses
+          + sizeof(ULONG));
+
+      /* Store number of buses there */
+      DeviceExtension->BusesConfig->NumberOfBuses = (UCHAR)DeviceExtension->BusNum;
+
+      /* Scan the adapter for devices */
+      SpiScanAdapter(DeviceExtension);
+
+      /* Build the registry device map */
+      SpiBuildDeviceMap(DeviceExtension,
+                       (PUNICODE_STRING)Argument2);
+
+      /* Create the dos device link */
+      swprintf(DosNameBuffer,
+               L"\\??\\Scsi%lu:",
+              SystemConfig->ScsiPortCount);
+      RtlInitUnicodeString(&DosDeviceName, DosNameBuffer);
+      IoCreateSymbolicLink(&DosDeviceName, &DeviceName);
+
+      /* Increase the port count */
+      SystemConfig->ScsiPortCount++;
+      FirstConfigCall = FALSE;
+
+      /* Increase adapter number and bus number respectively */
+      ConfigInfo.AdapterNumber++;
+
+      if (!Again)
+          ConfigInfo.BusNumber++;
 
       DPRINT("Bus: %lu  MaxBus: %lu\n", BusNumber, MaxBus);
-      if (BusNumber >= MaxBus)
-       {
-         DPRINT("Scanned all buses!\n");
-         Status = STATUS_SUCCESS;
-         goto ByeBye;
-       }
 
-      if (Again == FALSE)
-       {
-         BusNumber++;
-         SlotNumber.u.AsULONG = 0;
-       }
+      DeviceFound = TRUE;
     }
 
-ByeBye:
-  /* Clean up the mess */
-  if (PortDeviceObject != NULL)
+    /* Clean up the mess */
+    SpiCleanupAfterInit(DeviceExtension);
+
+    /* Close registry keys */
+    if (ConfigInfo.ServiceKey != NULL)
+        ZwClose(ConfigInfo.ServiceKey);
+
+    if (ConfigInfo.DeviceKey != NULL)
+        ZwClose(ConfigInfo.DeviceKey);
+
+    if (ConfigInfo.BusKey != NULL)
+        ZwClose(ConfigInfo.BusKey);
+
+    if (ConfigInfo.AccessRanges != NULL)
+        ExFreePool(ConfigInfo.AccessRanges);
+
+    if (ConfigInfo.Parameter != NULL)
+        ExFreePool(ConfigInfo.Parameter);
+
+    DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
+        Status, DeviceFound);
+
+    return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
+}
+
+static VOID
+SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+    PSCSI_LUN_INFO LunInfo;
+    PVOID Ptr;
+    ULONG Bus, Lun;
+
+    /* Check if we have something to clean up */
+    if (DeviceExtension == NULL)
+        return;
+
+    /* Stop the timer and disconnect the interrupt */
+    if (DeviceExtension->Interrupt)
     {
-      DPRINT("Delete device: %p\n", PortDeviceObject);
+        IoStopTimer(DeviceExtension->DeviceObject);
+        IoDisconnectInterrupt(DeviceExtension->Interrupt);
+    }
 
-      DeviceExtension = PortDeviceObject->DeviceExtension;
+    /* Delete ConfigInfo */
+    if (DeviceExtension->BusesConfig)
+    {
+        for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
+        {
+            if (!DeviceExtension->BusesConfig->BusScanInfo[Bus])
+                continue;
 
-      if (DeviceExtension->PortCapabilities != NULL)
-       {
-         IoDisconnectInterrupt (DeviceExtension->Interrupt);
-         ExFreePool (DeviceExtension->PortCapabilities);
-       }
+            LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
 
-      if (DeviceExtension->PortConfig != NULL)
-       {
-         ExFreePool (DeviceExtension->PortConfig);
-       }
+            while (LunInfo)
+            {
+                /* Free current, but save pointer to the next one */
+                Ptr = LunInfo->Next;
+                ExFreePool(LunInfo);
+                LunInfo = Ptr;
+            }
 
-      IoDeleteDevice (PortDeviceObject);
+            ExFreePool(DeviceExtension->BusesConfig->BusScanInfo[Bus]);
+        }
+
+        ExFreePool(DeviceExtension->BusesConfig);
     }
 
-  DPRINT("ScsiPortInitialize() done!\n");
+    /* Free PortConfig */
+    if (DeviceExtension->PortConfig)
+        ExFreePool(DeviceExtension->PortConfig);
 
-  return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
-}
+    /* Free LUNs*/
+    for(Lun = 0; Lun < LUS_NUMBER; Lun++)
+    {
+        while (DeviceExtension->LunExtensionList[Lun])
+        {
+            Ptr = DeviceExtension->LunExtensionList[Lun];
+            DeviceExtension->LunExtensionList[Lun] = DeviceExtension->LunExtensionList[Lun]->Next;
+
+            ExFreePool(Ptr);
+        }
+    }
+
+    /* Free common buffer (if it exists) */
+    if (DeviceExtension->SrbExtensionBuffer != NULL &&
+        DeviceExtension->CommonBufferLength != 0)
+    {
+            if (!DeviceExtension->AdapterObject)
+            {
+                ExFreePool(DeviceExtension->SrbExtensionBuffer);
+            }
+            else
+            {
+                HalFreeCommonBuffer(DeviceExtension->AdapterObject,
+                                    DeviceExtension->CommonBufferLength,
+                                    DeviceExtension->PhysicalAddress,
+                                    DeviceExtension->SrbExtensionBuffer,
+                                    FALSE);
+            }
+    }
+
+    /* Free SRB info */
+    if (DeviceExtension->SrbInfo != NULL)
+        ExFreePool(DeviceExtension->SrbInfo);
+
+    /* Unmap mapped addresses */
+    while (DeviceExtension->MappedAddressList != NULL)
+    {
+        MmUnmapIoSpace(DeviceExtension->MappedAddressList->MappedAddress,
+                       DeviceExtension->MappedAddressList->NumberOfBytes);
+
+        Ptr = DeviceExtension->MappedAddressList;
+        DeviceExtension->MappedAddressList = DeviceExtension->MappedAddressList->NextMappedAddress;
+
+        ExFreePool(Ptr);
+    }
 
+    /* Finally delete the device object */
+    DPRINT("Deleting device %p\n", DeviceExtension->DeviceObject);
+    IoDeleteDevice(DeviceExtension->DeviceObject);
+}
 
 /*
  * @unimplemented
  */
-VOID STDCALL
+VOID NTAPI
 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
                      IN PSCSI_REQUEST_BLOCK Srb,
-                     IN ULONG LogicalAddress,
+                     IN PVOID LogicalAddress,
                      IN ULONG Length)
 {
   DPRINT1("ScsiPortIoMapTransfer()\n");
   UNIMPLEMENTED;
 }
 
-
 /*
  * @unimplemented
  */
-VOID STDCALL
+VOID NTAPI
 ScsiPortLogError(IN PVOID HwDeviceExtension,
                 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
                 IN UCHAR PathId,
@@ -1230,8 +1830,6 @@ 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,
@@ -1241,11 +1839,10 @@ ScsiPortLogError(IN PVOID HwDeviceExtension,
   DPRINT("ScsiPortLogError() done\n");
 }
 
-
 /*
  * @implemented
  */
-VOID STDCALL
+VOID NTAPI
 ScsiPortMoveMemory(OUT PVOID Destination,
                   IN PVOID Source,
                   IN ULONG Length)
@@ -1264,114 +1861,141 @@ ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
                     IN PVOID HwDeviceExtension,
                     ...)
 {
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  va_list ap;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    va_list ap;
 
-  DPRINT("ScsiPortNotification() called\n");
+    DPRINT("ScsiPortNotification() called\n");
 
-  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
-                                     SCSI_PORT_DEVICE_EXTENSION,
-                                     MiniPortDeviceExtension);
+    DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
+        SCSI_PORT_DEVICE_EXTENSION,
+        MiniPortDeviceExtension);
 
-  DPRINT("DeviceExtension %p\n", DeviceExtension);
+    DPRINT("DeviceExtension %p\n", DeviceExtension);
 
-  va_start(ap, HwDeviceExtension);
+    va_start(ap, HwDeviceExtension);
 
-  switch (NotificationType)
+    switch (NotificationType)
     {
-      case RequestComplete:
-       {
-         PSCSI_REQUEST_BLOCK Srb;
+    case RequestComplete:
+        {
+            PSCSI_REQUEST_BLOCK Srb;
+            PSCSI_REQUEST_BLOCK_INFO SrbData;
 
-         Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
+            Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
 
-         DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
-         DeviceExtension->Flags |= IRP_FLAG_COMPLETE;
-         Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
-       }
-       break;
+            DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
 
-      case NextRequest:
-       DPRINT("Notify: NextRequest\n");
-       DeviceExtension->Flags |= IRP_FLAG_NEXT;
-       break;
+            /* Make sure Srb is allright */
+            ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING);
+            ASSERT(Srb->Function != SRB_FUNCTION_EXECUTE_SCSI || Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD);
 
-      case NextLuRequest:
-       {
-         UCHAR PathId;
-         UCHAR TargetId;
-         UCHAR Lun;
-          PSCSI_PORT_LUN_EXTENSION LunExtension;
-
-         PathId = (UCHAR) va_arg (ap, int);
-         TargetId = (UCHAR) va_arg (ap, int);
-         Lun = (UCHAR) va_arg (ap, int);
-
-         DPRINT ("Notify: NextLuRequest(PathId %u  TargetId %u  Lun %u)\n",
-                  PathId, TargetId, Lun);
-
-          LunExtension = SpiGetLunExtension(DeviceExtension,
-                                           PathId,
-                                           TargetId,
-                                           Lun);
-         if (LunExtension)
-           {
-             DeviceExtension->Flags |= IRP_FLAG_NEXT_LU;
-             LunExtension->Flags |= IRP_FLAG_NEXT_LU;
-           }
-       }
-       break;
+            if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
+            {
+                /* It's been already completed */
+                va_end(ap);
+                return;
+            }
+
+            /* It's not active anymore */
+            Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
+
+            if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
+            {
+                /* TODO: Treat it specially */
+                ASSERT(FALSE);
+            }
+            else
+            {
+                /* Get the SRB data */
+                SrbData = SpiGetSrbData(DeviceExtension,
+                                        Srb->PathId,
+                                        Srb->TargetId,
+                                        Srb->Lun,
+                                        Srb->QueueTag);
+
+                /* Make sure there are no CompletedRequests and there is a Srb */
+                ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL);
+
+                /* If it's a read/write request, make sure it has data inside it */
+                if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) &&
+                    ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE)))
+                {
+                        ASSERT(Srb->DataTransferLength);
+                }
+
+                SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests;
+                DeviceExtension->InterruptData.CompletedRequests = SrbData;
+            }
+        }
+        break;
+
+    case NextRequest:
+        DPRINT("Notify: NextRequest\n");
+        DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
+        break;
+
+    case NextLuRequest:
+        {
+            UCHAR PathId;
+            UCHAR TargetId;
+            UCHAR Lun;
+            PSCSI_PORT_LUN_EXTENSION LunExtension;
+
+            PathId = (UCHAR) va_arg (ap, int);
+            TargetId = (UCHAR) va_arg (ap, int);
+            Lun = (UCHAR) va_arg (ap, int);
+
+            DPRINT("Notify: NextLuRequest(PathId %u  TargetId %u  Lun %u)\n",
+                PathId, TargetId, Lun);
+
+            /* Mark it in the flags field */
+            DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
+
+            /* Get the LUN extension */
+            LunExtension = SpiGetLunExtension(DeviceExtension,
+                                              PathId,
+                                              TargetId,
+                                              Lun);
+
+            /* If returned LunExtension is NULL, break out */
+            if (!LunExtension) break;
+
+            /* This request should not be processed if */
+            if ((LunExtension->ReadyLun) ||
+                (LunExtension->SrbInfo.Srb))
+            {
+                /* Nothing to do here */
+                break;
+            }
+
+            /* Add this LUN to the list */
+            LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun;
+            DeviceExtension->InterruptData.ReadyLun = LunExtension;
+          }
+          break;
 
       case ResetDetected:
-       DPRINT1("Notify: ResetDetected\n");
-       /* FIXME: ??? */
-       break;
+          DPRINT("Notify: ResetDetected\n");
+          /* Add RESET flags */
+          DeviceExtension->InterruptData.Flags |=
+                SCSI_PORT_RESET | SCSI_PORT_RESET_REPORTED;
+          break;
 
       default:
        DPRINT1 ("Unsupported notification %lu\n", NotificationType);
        break;
     }
-  if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
-    {
-      IoRequestDpc(DeviceExtension->DeviceObject,
-                   NULL,
-                  DeviceExtension);
-    }
-  else
-    {
-      SpiProcessRequests(DeviceExtension, NULL);
-    }
-
-  va_end(ap);
-}
 
+    va_end(ap);
 
-/*
- * @implemented
- */
-ULONG STDCALL
-ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
-                          IN ULONG BusDataType,
-                          IN ULONG SystemIoBusNumber,
-                          IN ULONG SlotNumber,
-                          IN PVOID Buffer,
-                          IN ULONG Offset,
-                          IN ULONG Length)
-{
-  DPRINT("ScsiPortSetBusDataByOffset()\n");
-  return(HalSetBusDataByOffset(BusDataType,
-                              SystemIoBusNumber,
-                              SlotNumber,
-                              Buffer,
-                              Offset,
-                              Length));
+    /* Request a DPC after we're done with the interrupt */
+    DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED;
 }
 
-
 /*
  * @implemented
  */
-BOOLEAN STDCALL
+BOOLEAN NTAPI
 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
                      IN INTERFACE_TYPE BusType,
                      IN ULONG SystemIoBusNumber,
@@ -1386,1026 +2010,3026 @@ ScsiPortValidateRange(IN PVOID HwDeviceExtension,
 
 /* INTERNAL FUNCTIONS ********************************************************/
 
-
-static BOOLEAN
-SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
-                    IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
-                    IN ULONG BusNumber,
-                    IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
+static VOID
+SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
+                    IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
+                    IN PPORT_CONFIGURATION_INFORMATION PortConfig)
 {
-  PCI_COMMON_CONFIG PciConfig;
-  PCI_SLOT_NUMBER SlotNumber;
-  ULONG DataSize;
-  ULONG DeviceNumber;
-  ULONG FunctionNumber;
-  CHAR VendorIdString[8];
-  CHAR DeviceIdString[8];
-  ULONG i;
-  ULONG RangeLength;
-
-  DPRINT ("SpiGetPciConfiguration() called\n");
+    PACCESS_RANGE AccessRange;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
+    ULONG RangeNumber;
+    ULONG Index;
 
-  if (NextSlotNumber->u.bits.FunctionNumber >= PCI_MAX_FUNCTION)
-    {
-      NextSlotNumber->u.bits.FunctionNumber = 0;
-      NextSlotNumber->u.bits.DeviceNumber++;
-    }
+    RangeNumber = 0;
 
-  if (NextSlotNumber->u.bits.DeviceNumber >= PCI_MAX_DEVICES)
+    /* Loop through all entries */
+    for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
     {
-      NextSlotNumber->u.bits.DeviceNumber = 0;
-      return FALSE;
-    }
+        PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
 
-  for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
-    {
-      SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+        switch (PartialData->Type)
+        {
+        case CmResourceTypePort:
+            /* Copy access ranges */
+            if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
+            {
+                AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
 
-      for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
-       {
-         SlotNumber.u.bits.FunctionNumber = FunctionNumber;
-
-         DataSize = HalGetBusData (PCIConfiguration,
-                                   BusNumber,
-                                   SlotNumber.u.AsULONG,
-                                   &PciConfig,
-                                   PCI_COMMON_HDR_LENGTH);
-         if (DataSize != PCI_COMMON_HDR_LENGTH)
-           {
-             if (FunctionNumber == 0)
-               {
-                 break;
-               }
-             else
-               {
-                 continue;
-               }
-           }
+                AccessRange->RangeStart = PartialData->u.Port.Start;
+                AccessRange->RangeLength = PartialData->u.Port.Length;
 
-         sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
-         sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
+                AccessRange->RangeInMemory = FALSE;
+                RangeNumber++;
+            }
+            break;
 
-         if (!_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) &&
-             !_strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
-           {
-             DPRINT ("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
-                     PciConfig.VendorID,
-                     PciConfig.DeviceID,
-                     BusNumber,
-                     SlotNumber.u.bits.DeviceNumber,
-                     SlotNumber.u.bits.FunctionNumber);
-
-             PortConfig->BusInterruptLevel =
-             PortConfig->BusInterruptVector = PciConfig.u.type0.InterruptLine;
-             PortConfig->SlotNumber = SlotNumber.u.AsULONG;
-
-             /* Initialize access ranges */
-             if (PortConfig->NumberOfAccessRanges > 0)
-               {
-                 if (PortConfig->NumberOfAccessRanges > PCI_TYPE0_ADDRESSES)
-                   PortConfig->NumberOfAccessRanges = PCI_TYPE0_ADDRESSES;
+        case CmResourceTypeMemory:
+            /* Copy access ranges */
+            if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
+            {
+                AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
 
-                 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");
-                           }
-                       }
-                   }
-               }
+                AccessRange->RangeStart = PartialData->u.Memory.Start;
+                AccessRange->RangeLength = PartialData->u.Memory.Length;
 
-             NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
-             NextSlotNumber->u.bits.FunctionNumber = FunctionNumber;
+                AccessRange->RangeInMemory = TRUE;
+                RangeNumber++;
+            }
+            break;
 
-              PortConfig->SlotNumber = NextSlotNumber->u.AsULONG;
+        case CmResourceTypeInterrupt:
+            /* Copy interrupt data */
+            PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
+            PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
 
-             NextSlotNumber->u.bits.FunctionNumber += 1;
+            /* Set interrupt mode accordingly to the resource */
+            if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
+            {
+                PortConfig->InterruptMode = Latched;
+            }
+            else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
+            {
+                PortConfig->InterruptMode = LevelSensitive;
+            }
+            break;
 
-             return TRUE;
-           }
+        case CmResourceTypeDma:
+            PortConfig->DmaChannel = PartialData->u.Dma.Channel;
+            PortConfig->DmaPort = PartialData->u.Dma.Port;
+            break;
+        }
+    }
+}
 
+static PCM_RESOURCE_LIST
+SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                    PPORT_CONFIGURATION_INFORMATION PortConfig)
+{
+    PCONFIGURATION_INFORMATION ConfigInfo;
+    PCM_RESOURCE_LIST ResourceList;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
+    PACCESS_RANGE AccessRange;
+    BOOLEAN Dma;
+    ULONG ListLength = 0, i, FullSize;
+    ULONG Interrupt;
+
+    /* Get current Atdisk usage from the system */
+    ConfigInfo = IoGetConfigurationInformation();
+
+    if (PortConfig->AtdiskPrimaryClaimed)
+        ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
+
+    if (PortConfig->AtdiskSecondaryClaimed)
+        ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
+
+    /* Do we use DMA? */
+    if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE ||
+        PortConfig->DmaPort != SP_UNINITIALIZED_VALUE)
+    {
+        Dma = TRUE;
+        ListLength++;
+    }
+    else
+    {
+        Dma = FALSE;
+    }
 
-         if (FunctionNumber == 0 && !(PciConfig.HeaderType & PCI_MULTIFUNCTION))
-           {
-             break;
-           }
-       }
-       NextSlotNumber->u.bits.FunctionNumber = 0;
+    /* How many interrupts to we have? */
+    if (DeviceExtension->HwInterrupt == NULL ||
+        (PortConfig->BusInterruptLevel == 0 &&
+        PortConfig->BusInterruptVector == 0))
+    {
+        Interrupt = 0;
+    }
+    else
+    {
+        Interrupt = 1;
+        ListLength++;
     }
 
-  DPRINT ("No device found\n");
+    if (DeviceExtension->HwInterrupt != NULL &&
+        (PortConfig->BusInterruptLevel2 != 0 ||
+        PortConfig->BusInterruptVector2 != 0))
+    {
+        Interrupt++;
+        ListLength++;
+    }
 
-  return FALSE;
-}
+    /* How many access ranges do we use? */
+    AccessRange = &((*(PortConfig->AccessRanges))[0]);
+    for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
+    {
+        if (AccessRange->RangeLength != 0)
+            ListLength++;
 
+        AccessRange++;
+    }
 
+    /* Allocate the resource list, since we know its size now */
+    FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) *
+        sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
 
-/**********************************************************************
- * NAME                                                        INTERNAL
- *     ScsiPortCreateClose
- *
- * DESCRIPTION
- *     Answer requests for Create/Close calls: a null operation.
- *
- * RUN LEVEL
- *     PASSIVE_LEVEL
- *
- * ARGUMENTS
- *     DeviceObject
- *             Pointer to a device object.
- *
- *     Irp
- *             Pointer to an IRP.
- *
- * RETURN VALUE
- *     Status.
- */
+    ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT);
 
-static NTSTATUS STDCALL
-ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
-                   IN PIRP Irp)
-{
-  DPRINT("ScsiPortCreateClose()\n");
+    if (!ResourceList)
+        return NULL;
 
-  Irp->IoStatus.Status = STATUS_SUCCESS;
-  Irp->IoStatus.Information = FILE_OPENED;
+    /* Zero it */
+    RtlZeroMemory(ResourceList, FullSize);
 
-  IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    /* Initialize it */
+    ResourceList->Count = 1;
+    ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType;
+    ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber;
+    ResourceList->List[0].PartialResourceList.Count = ListLength;
+    ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
 
-  return(STATUS_SUCCESS);
-}
+    /* Copy access ranges array over */
+    for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
+    {
+        AccessRange = &((*(PortConfig->AccessRanges))[i]);
 
+        /* If the range is empty - skip it */
+        if (AccessRange->RangeLength == 0)
+            continue;
 
-/**********************************************************************
- * NAME                                                        INTERNAL
- *     ScsiPortDispatchScsi
- *
- * DESCRIPTION
- *     Answer requests for SCSI calls
- *
- * RUN LEVEL
- *     PASSIVE_LEVEL
- *
- * ARGUMENTS
- *     Standard dispatch arguments
- *
- * RETURNS
- *     NTSTATUS
- */
+        if (AccessRange->RangeInMemory)
+        {
+            ResourceDescriptor->Type = CmResourceTypeMemory;
+            ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
+        }
+        else
+        {
+            ResourceDescriptor->Type = CmResourceTypePort;
+            ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
+        }
 
-static NTSTATUS STDCALL
-ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
-                    IN PIRP Irp)
-{
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  PIO_STACK_LOCATION Stack;
-  PSCSI_REQUEST_BLOCK Srb;
-  NTSTATUS Status = STATUS_SUCCESS;
-  ULONG DataSize = 0;
+        ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
 
-  DPRINT("ScsiPortDispatchScsi(DeviceObject %p  Irp %p)\n",
-        DeviceObject, Irp);
+        ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart;
+        ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength;
 
-  DeviceExtension = DeviceObject->DeviceExtension;
-  Stack = IoGetCurrentIrpStackLocation(Irp);
+        ResourceDescriptor++;
+    }
 
-  Srb = Stack->Parameters.Scsi.Srb;
-  if (Srb == NULL)
+    /* If we use interrupt(s), copy them */
+    if (Interrupt)
     {
-      Status = STATUS_UNSUCCESSFUL;
-
-      Irp->IoStatus.Status = Status;
-      Irp->IoStatus.Information = 0;
-
-      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        ResourceDescriptor->Type = CmResourceTypeInterrupt;
 
-      return(Status);
+        if (PortConfig->AdapterInterfaceType == MicroChannel ||
+            PortConfig->InterruptMode == LevelSensitive)
+        {
+            ResourceDescriptor->ShareDisposition = CmResourceShareShared;
+            ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+        }
+        else
+        {
+            ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+            ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+        }
+
+        ResourceDescriptor->u.Interrupt.Level = PortConfig->BusInterruptLevel;
+        ResourceDescriptor->u.Interrupt.Vector = PortConfig->BusInterruptVector;
+        ResourceDescriptor->u.Interrupt.Affinity = 0;
+
+        ResourceDescriptor++;
+        Interrupt--;
+    }
+
+    /* Copy 2nd interrupt
+       FIXME: Stupid code duplication, remove */
+    if (Interrupt)
+    {
+        ResourceDescriptor->Type = CmResourceTypeInterrupt;
+
+        if (PortConfig->AdapterInterfaceType == MicroChannel ||
+            PortConfig->InterruptMode == LevelSensitive)
+        {
+            ResourceDescriptor->ShareDisposition = CmResourceShareShared;
+            ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+        }
+        else
+        {
+            ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+            ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+        }
+
+        ResourceDescriptor->u.Interrupt.Level = PortConfig->BusInterruptLevel;
+        ResourceDescriptor->u.Interrupt.Vector = PortConfig->BusInterruptVector;
+        ResourceDescriptor->u.Interrupt.Affinity = 0;
+
+        ResourceDescriptor++;
+    }
+
+    /* Copy DMA data */
+    if (Dma)
+    {
+        ResourceDescriptor->Type = CmResourceTypeDma;
+        ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        ResourceDescriptor->u.Dma.Channel = PortConfig->DmaChannel;
+        ResourceDescriptor->u.Dma.Port = PortConfig->DmaPort;
+        ResourceDescriptor->Flags = 0;
+
+        if (PortConfig->DmaChannel == SP_UNINITIALIZED_VALUE)
+            ResourceDescriptor->u.Dma.Channel = 0;
+
+        if (PortConfig->DmaPort == SP_UNINITIALIZED_VALUE)
+            ResourceDescriptor->u.Dma.Port = 0;
+    }
+
+    return ResourceList;
+}
+
+
+static BOOLEAN
+SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
+                    IN PDEVICE_OBJECT DeviceObject,
+                    IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
+                    IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
+                    IN PUNICODE_STRING RegistryPath,
+                    IN ULONG BusNumber,
+                    IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
+{
+    PCI_COMMON_CONFIG PciConfig;
+    PCI_SLOT_NUMBER SlotNumber;
+    ULONG DataSize;
+    ULONG DeviceNumber;
+    ULONG FunctionNumber;
+    CHAR VendorIdString[8];
+    CHAR DeviceIdString[8];
+    UNICODE_STRING UnicodeStr;
+    PCM_RESOURCE_LIST ResourceList;
+    NTSTATUS Status;
+
+    DPRINT ("SpiGetPciConfiguration() called\n");
+
+       RtlZeroMemory(&ResourceList, sizeof(PCM_RESOURCE_LIST));
+    SlotNumber.u.AsULONG = 0;
+
+    /* Loop through all devices */
+    for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
+    {
+        SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+
+        /* Loop through all functions */
+        for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
+        {
+            SlotNumber.u.bits.FunctionNumber = FunctionNumber;
+
+            /* Get PCI config bytes */
+            DataSize = HalGetBusData(PCIConfiguration,
+                                     BusNumber,
+                                     SlotNumber.u.AsULONG,
+                                     &PciConfig,
+                                     sizeof(ULONG));
+
+            /* If result of HalGetBusData is 0, then the bus is wrong */
+            if (DataSize == 0)
+                return FALSE;
+
+            /* If result is PCI_INVALID_VENDORID, then this device has no more
+               "Functions" */
+            if (PciConfig.VendorID == PCI_INVALID_VENDORID)
+                break;
+
+            sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
+            sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
+
+            if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
+                _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
+            {
+                /* It is not our device */
+                continue;
+            }
+
+            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);
+
+
+            RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter");
+            Status = HalAssignSlotResources(RegistryPath,
+                                            &UnicodeStr,
+                                            DriverObject,
+                                            DeviceObject,
+                                            PCIBus,
+                                            BusNumber,
+                                            SlotNumber.u.AsULONG,
+                                            &ResourceList);
+
+            if (!NT_SUCCESS(Status))
+                break;
+
+            /* Create configuration information */
+            SpiResourceToConfig(HwInitializationData,
+                                ResourceList->List,
+                                PortConfig);
+
+            /* Free the resource list */
+            ExFreePool(ResourceList);
+
+            /* Set dev & fn numbers */
+            NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
+            NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
+
+            /* Save the slot number */
+            PortConfig->SlotNumber = SlotNumber.u.AsULONG;
+
+            return TRUE;
+        }
+       NextSlotNumber->u.bits.FunctionNumber = 0;
+    }
+
+    NextSlotNumber->u.bits.DeviceNumber = 0;
+    DPRINT ("No device found\n");
+
+    return FALSE;
+}
+
+
+
+/**********************************************************************
+ * NAME                                                        INTERNAL
+ *     ScsiPortCreateClose
+ *
+ * DESCRIPTION
+ *     Answer requests for Create/Close calls: a null operation.
+ *
+ * RUN LEVEL
+ *     PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ *     DeviceObject
+ *             Pointer to a device object.
+ *
+ *     Irp
+ *             Pointer to an IRP.
+ *
+ * RETURN VALUE
+ *     Status.
+ */
+
+static NTSTATUS NTAPI
+ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
+                   IN PIRP Irp)
+{
+    DPRINT("ScsiPortCreateClose()\n");
+
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                       PIRP Irp)
+{
+    PSCSI_LUN_INFO LunInfo;
+    PIO_STACK_LOCATION IrpStack;
+    PDEVICE_OBJECT DeviceObject;
+    PSCSI_REQUEST_BLOCK Srb;
+    KIRQL Irql;
+
+    /* Get pointer to the SRB */
+    IrpStack = IoGetCurrentIrpStackLocation(Irp);
+    Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
+
+    /* Check if PathId matches number of buses */
+    if (DeviceExtension->BusesConfig == NULL ||
+        DeviceExtension->BusesConfig->NumberOfBuses <= Srb->PathId)
+    {
+        Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+        return STATUS_DEVICE_DOES_NOT_EXIST;
+    }
+
+    /* Get pointer to LunInfo */
+    LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Srb->PathId]->LunInfo;
+
+    /* Find matching LunInfo */
+    while (LunInfo)
+    {
+        if (LunInfo->PathId == Srb->PathId &&
+            LunInfo->TargetId == Srb->TargetId &&
+            LunInfo->Lun == Srb->Lun)
+        {
+            break;
+        }
+
+        LunInfo = LunInfo->Next;
+    }
+
+    /* If we couldn't find it - exit */
+    if (LunInfo == NULL)
+        return STATUS_DEVICE_DOES_NOT_EXIST;
+
+
+    /* Get spinlock */
+    KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
+
+    /* Release, if asked */
+    if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE)
+    {
+        LunInfo->DeviceClaimed = FALSE;
+        KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+        Srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+        return STATUS_SUCCESS;
+    }
+
+    /* Attach, if not already claimed */
+    if (LunInfo->DeviceClaimed)
+    {
+        KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+        Srb->SrbStatus = SRB_STATUS_BUSY;
+
+        return STATUS_DEVICE_BUSY;
+    }
+
+    /* Save the device object */
+    DeviceObject = LunInfo->DeviceObject;
+
+    if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE)
+        LunInfo->DeviceClaimed = TRUE;
+
+    if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE)
+        LunInfo->DeviceObject = Srb->DataBuffer;
+
+    Srb->DataBuffer = DeviceObject;
+
+    KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+    Srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+    return STATUS_SUCCESS;
+}
+
+
+/**********************************************************************
+ * NAME                                                        INTERNAL
+ *     ScsiPortDispatchScsi
+ *
+ * DESCRIPTION
+ *     Answer requests for SCSI calls
+ *
+ * RUN LEVEL
+ *     PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ *     Standard dispatch arguments
+ *
+ * RETURNS
+ *     NTSTATUS
+ */
+
+static NTSTATUS NTAPI
+ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
+                    IN PIRP Irp)
+{
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+    PIO_STACK_LOCATION Stack;
+    PSCSI_REQUEST_BLOCK Srb;
+    KIRQL Irql;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PIRP NextIrp, IrpList;
+    PKDEVICE_QUEUE_ENTRY Entry;
+
+    DPRINT("ScsiPortDispatchScsi(DeviceObject %p  Irp %p)\n",
+        DeviceObject, Irp);
+
+    DeviceExtension = DeviceObject->DeviceExtension;
+    Stack = IoGetCurrentIrpStackLocation(Irp);
+
+    Srb = Stack->Parameters.Scsi.Srb;
+    if (Srb == NULL)
+    {
+        DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
+        Status = STATUS_UNSUCCESSFUL;
+
+        Irp->IoStatus.Status = Status;
+        Irp->IoStatus.Information = 0;
+
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+        return(Status);
+    }
+
+    DPRINT("Srb: %p\n", Srb);
+    DPRINT("Srb->Function: %lu\n", Srb->Function);
+    DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
+
+    LunExtension = SpiGetLunExtension(DeviceExtension,
+                                      Srb->PathId,
+                                      Srb->TargetId,
+                                      Srb->Lun);
+    if (LunExtension == NULL)
+    {
+        DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
+        Status = STATUS_NO_SUCH_DEVICE;
+
+        Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+        Irp->IoStatus.Status = Status;
+        Irp->IoStatus.Information = 0;
+
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+        return(Status);
+    }
+
+    switch (Srb->Function)
+    {
+    case SRB_FUNCTION_SHUTDOWN:
+    case SRB_FUNCTION_FLUSH:
+        DPRINT ("  SRB_FUNCTION_SHUTDOWN or FLUSH\n");
+        if (DeviceExtension->CachesData == FALSE)
+        {
+            /* All success here */
+            Srb->SrbStatus = SRB_STATUS_SUCCESS;
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+            return STATUS_SUCCESS;
+        }
+        /* Fall through to a usual execute operation */
+
+    case SRB_FUNCTION_EXECUTE_SCSI:
+    case SRB_FUNCTION_IO_CONTROL:
+        /* Mark IRP as pending in all cases */
+        IoMarkIrpPending(Irp);
+
+        if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
+        {
+            /* Start IO directly */
+            IoStartPacket(DeviceObject, Irp, NULL, NULL);
+        }
+        else
+        {
+            KIRQL oldIrql;
+
+            /* We need to be at DISPATCH_LEVEL */
+            KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
+
+            /* Insert IRP into the queue */
+            if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
+                &Irp->Tail.Overlay.DeviceQueueEntry,
+                Srb->QueueSortKey))
+            {
+                /* It means the queue is empty, and we just start this request */
+                IoStartPacket(DeviceObject, Irp, NULL, NULL);
+            }
+
+            /* Back to the old IRQL */
+            KeLowerIrql (oldIrql);
+        }
+        return STATUS_PENDING;
+
+    case SRB_FUNCTION_CLAIM_DEVICE:
+    case SRB_FUNCTION_ATTACH_DEVICE:
+        DPRINT ("  SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
+
+        /* Reference device object and keep the device object */
+        Status = SpiHandleAttachRelease(DeviceExtension, Irp);
+        break;
+
+    case SRB_FUNCTION_RELEASE_DEVICE:
+        DPRINT ("  SRB_FUNCTION_RELEASE_DEVICE\n");
+
+        /* Dereference device object and clear the device object */
+        Status = SpiHandleAttachRelease(DeviceExtension, Irp);
+        break;
+
+    case SRB_FUNCTION_RELEASE_QUEUE:
+        DPRINT("  SRB_FUNCTION_RELEASE_QUEUE\n");
+
+        /* Guard with the spinlock */
+        KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
+
+        if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
+        {
+            DPRINT("Queue is not frozen really\n");
+
+            KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+            Srb->SrbStatus = SRB_STATUS_SUCCESS;
+            Status = STATUS_SUCCESS;
+            break;
+
+        }
+
+        /* Unfreeze the queue */
+        LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
+
+        if (LunExtension->SrbInfo.Srb == NULL)
+        {
+            /* Get next logical unit request */
+            SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
+
+            /* SpiGetNextRequestFromLun() releases the spinlock */
+            KeLowerIrql(Irql);
+        }
+        else
+        {
+            DPRINT("The queue has active request\n");
+            KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+        }
+
+
+        Srb->SrbStatus = SRB_STATUS_SUCCESS;
+        Status = STATUS_SUCCESS;
+        break;
+
+    case SRB_FUNCTION_FLUSH_QUEUE:
+        DPRINT("  SRB_FUNCTION_FLUSH_QUEUE\n");
+
+        /* Guard with the spinlock */
+        KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
+
+        if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
+        {
+            DPRINT("Queue is not frozen really\n");
+
+            KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+            Status = STATUS_INVALID_DEVICE_REQUEST;
+            break;
+        }
+
+        /* Make sure there is no active request */
+        ASSERT(LunExtension->SrbInfo.Srb == NULL);
+
+        /* Compile a list from the device queue */
+        IrpList = NULL;
+        while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) != NULL)
+        {
+                NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
+
+                /* Get the Srb */
+                Stack = IoGetCurrentIrpStackLocation(NextIrp);
+                Srb = Stack->Parameters.Scsi.Srb;
+
+                /* Set statuse */
+                Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
+                NextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+                /* Add then to the list */
+                NextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)IrpList;
+                IrpList = NextIrp;
+        }
+
+        /* Unfreeze the queue */
+        LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
+
+        /* Release the spinlock */
+        KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+
+        /* Complete those requests */
+        while (IrpList)
+        {
+            NextIrp = IrpList;
+            IrpList = (PIRP)NextIrp->Tail.Overlay.ListEntry.Flink;
+
+            IoCompleteRequest(NextIrp, 0);
+        }
+
+        Status = STATUS_SUCCESS;
+        break;
+
+    default:
+        DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
+        Status = STATUS_NOT_IMPLEMENTED;
+        break;
+    }
+
+    Irp->IoStatus.Status = Status;
+
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return(Status);
+}
+
+
+/**********************************************************************
+ * NAME                                                        INTERNAL
+ *     ScsiPortDeviceControl
+ *
+ * DESCRIPTION
+ *     Answer requests for device control calls
+ *
+ * RUN LEVEL
+ *     PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ *     Standard dispatch arguments
+ *
+ * RETURNS
+ *     NTSTATUS
+ */
+
+static NTSTATUS NTAPI
+ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
+                     IN PIRP Irp)
+{
+    PIO_STACK_LOCATION Stack;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    NTSTATUS Status = STATUS_SUCCESS;;
+
+    DPRINT("ScsiPortDeviceControl()\n");
+
+    Irp->IoStatus.Information = 0;
+
+    Stack = IoGetCurrentIrpStackLocation(Irp);
+    DeviceExtension = DeviceObject->DeviceExtension;
+
+    switch (Stack->Parameters.DeviceIoControl.IoControlCode)
+    {
+      case IOCTL_SCSI_GET_DUMP_POINTERS:
+       {
+         PDUMP_POINTERS DumpPointers;
+         DPRINT("  IOCTL_SCSI_GET_DUMP_POINTERS\n");
+         DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
+         DumpPointers->DeviceObject = DeviceObject;
+
+         Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
+       }
+       break;
+
+      case IOCTL_SCSI_GET_CAPABILITIES:
+        DPRINT("  IOCTL_SCSI_GET_CAPABILITIES\n");
+        if (Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
+        {
+            *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = &DeviceExtension->PortCapabilities;
+
+            Irp->IoStatus.Information = sizeof(PVOID);
+            Status = STATUS_SUCCESS;
+            break;
+        }
+
+        if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IO_SCSI_CAPABILITIES))
+        {
+            Status = STATUS_BUFFER_TOO_SMALL;
+            break;
+        }
+
+        RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
+                      &DeviceExtension->PortCapabilities,
+                      sizeof(IO_SCSI_CAPABILITIES));
+
+        Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
+        Status = STATUS_SUCCESS;
+        break;
+
+      case IOCTL_SCSI_GET_INQUIRY_DATA:
+          DPRINT("  IOCTL_SCSI_GET_INQUIRY_DATA\n");
+
+          /* Copy inquiry data to the port device extension */
+          Status = SpiGetInquiryData(DeviceExtension, Irp);
+          break;
+
+      default:
+       DPRINT1("  unknown ioctl code: 0x%lX\n",
+              Stack->Parameters.DeviceIoControl.IoControlCode);
+       break;
+    }
+
+    /* Complete the request with the given status */
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return Status;
+}
+
+
+static VOID NTAPI
+ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
+               IN PIRP Irp)
+{
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+    PIO_STACK_LOCATION IrpStack;
+    PSCSI_REQUEST_BLOCK Srb;
+    PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+    LONG CounterResult;
+    NTSTATUS Status;
+
+    DPRINT("ScsiPortStartIo() called!\n");
+
+    DeviceExtension = DeviceObject->DeviceExtension;
+    IrpStack = IoGetCurrentIrpStackLocation(Irp);
+
+    DPRINT("DeviceExtension %p\n", DeviceExtension);
+
+    Srb = IrpStack->Parameters.Scsi.Srb;
+
+    /* Apply "default" flags */
+    Srb->SrbFlags |= DeviceExtension->SrbFlags;
+
+    /* Get LUN extension */
+    LunExtension = SpiGetLunExtension(DeviceExtension,
+                                      Srb->PathId,
+                                      Srb->TargetId,
+                                      Srb->Lun);
+
+    if (DeviceExtension->NeedSrbDataAlloc ||
+        DeviceExtension->NeedSrbExtensionAlloc)
+    {
+        /* Allocate them */
+        SrbInfo = SpiAllocateSrbStructures(DeviceExtension,
+                                           LunExtension,
+                                           Srb);
+
+        /* Couldn't alloc one or both data structures, return */
+        if (SrbInfo == NULL)
+        {
+            /* We have to call IoStartNextPacket, because this request
+               was not started */
+            if (LunExtension->Flags & LUNEX_REQUEST_PENDING)
+                IoStartNextPacket(DeviceObject, FALSE);
+
+            return;
+        }
+    }
+    else
+    {
+        /* No allocations are needed */
+        SrbInfo = &LunExtension->SrbInfo;
+        Srb->SrbExtension = NULL;
+        Srb->QueueTag = SP_UNTAGGED;
+    }
+
+    /* Increase sequence number of SRB */
+    if (!SrbInfo->SequenceNumber)
+    {
+        /* Increase global sequence number */
+        DeviceExtension->SequenceNumber++;
+
+        /* Assign it */
+        SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber;
+    }
+
+    /* Check some special SRBs */
+    if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
+    {
+        /* Some special handling */
+        DPRINT1("Abort command! Unimplemented now\n");
+    }
+    else
+    {
+        SrbInfo->Srb = Srb;
+    }
+
+    if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
+    {
+        // Store the MDL virtual address in SrbInfo structure
+        SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
+
+        if (DeviceExtension->MapBuffers)
+        {
+            /* Calculate offset within DataBuffer */
+            SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress);
+            Srb->DataBuffer = SrbInfo->DataOffset +
+                (ULONG)((PUCHAR)Srb->DataBuffer -
+                (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
+        }
+
+        if (DeviceExtension->AdapterObject)
+        {
+            /* Flush buffers */
+            KeFlushIoBuffers(Irp->MdlAddress,
+                             Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
+                             TRUE);
+        }
+
+        if (DeviceExtension->MapRegisters)
+        {
+            /* Calculate number of needed map registers */
+            SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
+                    Srb->DataBuffer,
+                    Srb->DataTransferLength);
+
+            /* Allocate adapter channel */
+            Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject,
+                                              DeviceExtension->DeviceObject,
+                                              SrbInfo->NumberOfMapRegisters,
+                                              SpiAdapterControl,
+                                              SrbInfo);
+
+            if (!NT_SUCCESS(Status))
+            {
+                DPRINT1("IoAllocateAdapterChannel() failed!\n");
+
+                Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+                ScsiPortNotification(RequestComplete,
+                                     DeviceExtension + 1,
+                                     Srb);
+
+                ScsiPortNotification(NextRequest,
+                                     DeviceExtension + 1);
+
+                /* Request DPC for that work */
+                IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
+            }
+
+            /* Control goes to SpiAdapterControl */
+            return;
+        }
+    }
+
+    /* Increase active request counter */
+    CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter);
+
+    if (CounterResult == 0 &&
+        DeviceExtension->AdapterObject != NULL &&
+        !DeviceExtension->MapRegisters)
+    {
+        IoAllocateAdapterChannel(
+            DeviceExtension->AdapterObject,
+            DeviceObject,
+            DeviceExtension->PortCapabilities.MaximumPhysicalPages,
+            ScsiPortAllocateAdapterChannel,
+            LunExtension
+            );
+
+        return;
+    }
+
+    KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+    if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
+                                ScsiPortStartPacket,
+                                DeviceObject))
+    {
+        DPRINT("Synchronization failed!\n");
+
+        Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+        Irp->IoStatus.Information = 0;
+        KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    }
+    else
+    {
+        /* Release the spinlock only */
+        KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+    }
+
+
+    DPRINT("ScsiPortStartIo() done\n");
+}
+
+
+static BOOLEAN NTAPI
+ScsiPortStartPacket(IN OUT PVOID Context)
+{
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    PIO_STACK_LOCATION IrpStack;
+    PSCSI_REQUEST_BLOCK Srb;
+    PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+    PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+    BOOLEAN Result;
+    BOOLEAN StartTimer;
+
+    DPRINT("ScsiPortStartPacket() called\n");
+
+    DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
+    Srb = IrpStack->Parameters.Scsi.Srb;
+
+    /* Get LUN extension */
+    LunExtension = SpiGetLunExtension(DeviceExtension,
+                                      Srb->PathId,
+                                      Srb->TargetId,
+                                      Srb->Lun);
+
+    /* Check if we are in a reset state */
+    if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
+    {
+        /* Mark the we've got requests while being in the reset state */
+        DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST;
+        return TRUE;
+    }
+
+    /* Set the time out value */
+    DeviceExtension->TimerCount = Srb->TimeOutValue;
+
+    /* We are busy */
+    DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY;
+
+    if (LunExtension->RequestTimeout != -1)
+    {
+        /* Timer already active */
+        StartTimer = FALSE;
+    }
+    else
+    {
+        /* It hasn't been initialized yet */
+        LunExtension->RequestTimeout = Srb->TimeOutValue;
+        StartTimer = TRUE;
+    }
+
+    if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
+    {
+        /* Handle bypass-requests */
+
+        /* Is this an abort request? */
+        if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
+        {
+            /* Get pointer to SRB info structure */
+            SrbInfo = SpiGetSrbData(DeviceExtension,
+                                    Srb->PathId,
+                                    Srb->TargetId,
+                                    Srb->Lun,
+                                    Srb->QueueTag);
+
+            /* Check if the request is still "active" */
+            if (SrbInfo == NULL ||
+                SrbInfo->Srb == NULL ||
+                !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
+            {
+                /* It's not, mark it as active then */
+                Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
+
+                if (StartTimer)
+                    LunExtension->RequestTimeout = -1;
+
+                DPRINT("Request has been already completed, but abort request came\n");
+                Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+                /* Notify about request complete */
+                ScsiPortNotification(RequestComplete,
+                                     DeviceExtension->MiniPortDeviceExtension,
+                                     Srb);
+
+                /* and about readiness for the next request */
+                ScsiPortNotification(NextRequest,
+                                     DeviceExtension->MiniPortDeviceExtension);
+
+                /* They might ask for some work, so queue the DPC for them */
+                IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
+
+                /* We're done in this branch */
+                return TRUE;
+            }
+        }
+        else
+        {
+            /* Add number of queued requests */
+            LunExtension->QueueCount++;
+        }
+
+        /* Bypass requests don't need request sense */
+        LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE;
+
+        /* Is disconnect disabled for this request? */
+        if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+        {
+            /* Set the corresponding flag */
+            DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
+        }
+
+        /* Transfer timeout value from Srb to Lun */
+        LunExtension->RequestTimeout = Srb->TimeOutValue;
+    }
+    else
+    {
+        if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+        {
+            /* It's a disconnect, so no more requests can go */
+            DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
+        }
+
+        LunExtension->Flags |= SCSI_PORT_LU_ACTIVE;
+
+        /* Increment queue count */
+        LunExtension->QueueCount++;
+
+        /* If it's tagged - special thing */
+        if (Srb->QueueTag != SP_UNTAGGED)
+        {
+            SrbInfo = &DeviceExtension->SrbInfo[Srb->QueueTag - 1];
+
+            /* Chek for consistency */
+            ASSERT(SrbInfo->Requests.Blink == NULL);
+
+            /* Insert it into the list of requests */
+            InsertTailList(&LunExtension->SrbInfo.Requests, &SrbInfo->Requests);
+        }
+    }
+
+    /* Mark this Srb active */
+    Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
+
+    /* Call HwStartIo routine */
+    Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
+                                        Srb);
+
+    /* If notification is needed, then request a DPC */
+    if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
+        IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
+
+    return Result;
+}
+
+IO_ALLOCATION_ACTION
+NTAPI
+SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
+                  PIRP Irp,
+                  PVOID MapRegisterBase,
+                  PVOID Context)
+{
+    PSCSI_REQUEST_BLOCK Srb;
+    PSCSI_SG_ADDRESS ScatterGatherList;
+    KIRQL CurrentIrql;
+    PIO_STACK_LOCATION IrpStack;
+    ULONG TotalLength = 0;
+    PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    PUCHAR DataVA;
+    BOOLEAN WriteToDevice;
+
+    /* Get pointers to SrbInfo and DeviceExtension */
+    SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
+    DeviceExtension = DeviceObject->DeviceExtension;
+
+    /* Get pointer to SRB */
+    IrpStack = IoGetCurrentIrpStackLocation(Irp);
+    Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
+
+    /* Depending on the map registers number, we allocate
+       either from NonPagedPool, or from our static list */
+    if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
+    {
+        SrbInfo->ScatterGather = ExAllocatePoolWithTag(
+            NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT);
+
+        if (SrbInfo->ScatterGather == NULL)
+            ASSERT(FALSE);
+
+        Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
+    }
+    else
+    {
+        SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
+    }
+
+    /* Use chosen SG list source */
+    ScatterGatherList = SrbInfo->ScatterGather;
+
+    /* Save map registers base */
+    SrbInfo->BaseOfMapRegister = MapRegisterBase;
+
+    /* Determine WriteToDevice flag */
+    WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
+
+    /* Get virtual address of the data buffer */
+    DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
+                ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
+
+    /* Build the actual SG list */
+    while (TotalLength < Srb->DataTransferLength)
+    {
+        if (!ScatterGatherList)
+            break;
+
+        ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
+        ScatterGatherList->PhysicalAddress = IoMapTransfer(NULL,
+                                                           Irp->MdlAddress,
+                                                           MapRegisterBase,
+                                                           DataVA + TotalLength,
+                                                           &ScatterGatherList->Length,
+                                                           WriteToDevice);
+
+        TotalLength += ScatterGatherList->Length;
+        ScatterGatherList++;
+    }
+
+    /* Schedule an active request */
+    InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
+    KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
+    KeSynchronizeExecution(DeviceExtension->Interrupt,
+                           ScsiPortStartPacket,
+                           DeviceObject);
+    KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
+
+    return DeallocateObjectKeepRegisters;
+}
+
+static PSCSI_PORT_LUN_EXTENSION
+SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+    ULONG LunExtensionSize;
+
+    DPRINT("SpiAllocateLunExtension (%p)\n",
+        DeviceExtension);
+
+    /* Round LunExtensionSize first to the sizeof LONGLONG */
+    LunExtensionSize = (DeviceExtension->LunExtensionSize +
+        sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
+
+    LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
+    DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
+
+    LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT);
+    if (LunExtension == NULL)
+    {
+        DPRINT1("Out of resources!\n");
+        return NULL;
+    }
+
+    /* Zero everything */
+    RtlZeroMemory(LunExtension, LunExtensionSize);
+
+    /* Initialize a list of requests */
+    InitializeListHead(&LunExtension->SrbInfo.Requests);
+
+    /* Initialize timeout counter */
+    LunExtension->RequestTimeout = -1;
+
+    /* Set maximum queue size */
+    LunExtension->MaxQueueCount = 256;
+
+    /* Initialize request queue */
+    KeInitializeDeviceQueue (&LunExtension->DeviceQueue);
+
+    return LunExtension;
+}
+
+static PSCSI_PORT_LUN_EXTENSION
+SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                   IN UCHAR PathId,
+                   IN UCHAR TargetId,
+                   IN UCHAR Lun)
+{
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+
+    DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
+        DeviceExtension, PathId, TargetId, Lun);
+
+    /* Get appropriate list */
+    LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER];
+
+    /* Iterate it until we find what we need */
+    while (LunExtension)
+    {
+        if (LunExtension->TargetId == TargetId &&
+            LunExtension->Lun == Lun &&
+            LunExtension->PathId == PathId)
+        {
+            /* All matches, return */
+            return LunExtension;
+        }
+
+        /* Advance to the next item */
+        LunExtension = LunExtension->Next;
+    }
+
+    /* We did not find anything */
+    DPRINT("Nothing found\n");
+    return NULL;
+}
+
+static PSCSI_REQUEST_BLOCK_INFO
+SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                         PSCSI_PORT_LUN_EXTENSION LunExtension,
+                         PSCSI_REQUEST_BLOCK Srb)
+{
+    PCHAR SrbExtension;
+    PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+
+    /* Spinlock must be held while this function executes */
+    KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+    /* Allocate SRB data structure */
+    if (DeviceExtension->NeedSrbDataAlloc)
+    {
+        /* Treat the abort request in a special way */
+        if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
+        {
+            SrbInfo = SpiGetSrbData(DeviceExtension,
+                                    Srb->PathId,
+                                    Srb->TargetId,
+                                    Srb->Lun,
+                                    Srb->QueueTag);
+        }
+        else if (Srb->SrbFlags &
+                 (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) &&
+                 !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+                 )
+        {
+            /* Do not process tagged commands if need request sense is set */
+            if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
+            {
+                ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
+
+                LunExtension->PendingRequest = Srb->OriginalRequest;
+                LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
+
+                /* Relese the spinlock and return */
+                KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+                return NULL;
+            }
+
+            ASSERT(LunExtension->SrbInfo.Srb == NULL);
+            SrbInfo = DeviceExtension->FreeSrbInfo;
+
+            if (SrbInfo == NULL)
+            {
+                /* No SRB structures left in the list. We have to leave
+                   and wait while we are called again */
+
+                DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
+                KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+                return NULL;
+            }
+
+            DeviceExtension->FreeSrbInfo = (PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink;
+
+            /* QueueTag must never be 0, so +1 to it */
+            Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1;
+        }
+        else
+        {
+            /* Usual untagged command */
+            if (
+                (!IsListEmpty(&LunExtension->SrbInfo.Requests) ||
+                LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) &&
+                !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
+                )
+            {
+                /* Mark it as pending and leave */
+                ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
+                LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
+                LunExtension->PendingRequest = Srb->OriginalRequest;
+
+                KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+                return(NULL);
+            }
+
+            Srb->QueueTag = SP_UNTAGGED;
+            SrbInfo = &LunExtension->SrbInfo;
+        }
+    }
+    else
+    {
+        Srb->QueueTag = SP_UNTAGGED;
+        SrbInfo = &LunExtension->SrbInfo;
     }
 
-  DPRINT("Srb: %p\n", Srb);
-  DPRINT("Srb->Function: %lu\n", Srb->Function);
-  DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
+    /* Allocate SRB extension structure */
+    if (DeviceExtension->NeedSrbExtensionAlloc)
+    {
+        /* Check the list of free extensions */
+        SrbExtension = DeviceExtension->FreeSrbExtensions;
+
+        /* If no free extensions... */
+        if (SrbExtension == NULL)
+        {
+            /* Free SRB data */
+            if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND &&
+                Srb->QueueTag != SP_UNTAGGED)
+            {
+                SrbInfo->Requests.Blink = NULL;
+                SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
+                DeviceExtension->FreeSrbInfo = SrbInfo;
+            }
+
+            /* Return, in order to be called again later */
+            DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
+            KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+            return NULL;
+        }
+
+        /* Remove that free SRB extension from the list (since
+           we're going to use it) */
+        DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension);
+
+        /* Spinlock can be released now */
+        KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+        Srb->SrbExtension = SrbExtension;
+
+        if (Srb->SenseInfoBuffer != NULL &&
+            DeviceExtension->SupportsAutoSense)
+        {
+            /* Store pointer to the SenseInfo buffer */
+            SrbInfo->SaveSenseRequest = Srb->SenseInfoBuffer;
 
-  LunExtension = SpiGetLunExtension(DeviceExtension,
-                                   Srb->PathId,
-                                   Srb->TargetId,
-                                   Srb->Lun);
-  if (LunExtension == NULL)
+            /* Does data fit the buffer? */
+            if (Srb->SenseInfoBufferLength > sizeof(SENSE_DATA))
+            {
+                /* No, disabling autosense at all */
+                Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
+            }
+            else
+            {
+                /* Yes, update the buffer pointer */
+                Srb->SenseInfoBuffer = SrbExtension + DeviceExtension->SrbExtensionSize;
+            }
+        }
+    }
+    else
     {
-      Status = STATUS_NO_SUCH_DEVICE;
+        /* Cleanup... */
+        Srb->SrbExtension = NULL;
+        KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+    }
 
-      Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
-      Irp->IoStatus.Status = Status;
-      Irp->IoStatus.Information = 0;
+    return SrbInfo;
+}
 
-      IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
-      return(Status);
+static NTSTATUS
+SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
+               IN PSCSI_LUN_INFO LunInfo)
+{
+    IO_STATUS_BLOCK IoStatusBlock;
+    PIO_STACK_LOCATION IrpStack;
+    KEVENT Event;
+    KIRQL Irql;
+    PIRP Irp;
+    NTSTATUS Status;
+    PINQUIRYDATA InquiryBuffer;
+    PSENSE_DATA SenseBuffer;
+    BOOLEAN KeepTrying = TRUE;
+    ULONG RetryCount = 0;
+    SCSI_REQUEST_BLOCK Srb;
+    PCDB Cdb;
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+
+    DPRINT ("SpiSendInquiry() called\n");
+
+    DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    InquiryBuffer = ExAllocatePoolWithTag (NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_SCSIPORT);
+    if (InquiryBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    SenseBuffer = ExAllocatePoolWithTag (NonPagedPool, SENSE_BUFFER_SIZE, TAG_SCSIPORT);
+    if (SenseBuffer == NULL)
+    {
+        ExFreePool(InquiryBuffer);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    while (KeepTrying)
+    {
+        /* Initialize event for waiting */
+        KeInitializeEvent(&Event,
+                          NotificationEvent,
+                          FALSE);
+
+        /* Create an IRP */
+        Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
+            DeviceObject,
+            NULL,
+            0,
+            InquiryBuffer,
+            INQUIRYDATABUFFERSIZE,
+            TRUE,
+            &Event,
+            &IoStatusBlock);
+        if (Irp == NULL)
+        {
+            DPRINT("IoBuildDeviceIoControlRequest() failed\n");
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        /* Prepare SRB */
+        RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
+
+        Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
+        Srb.OriginalRequest = Irp;
+        Srb.PathId = LunInfo->PathId;
+        Srb.TargetId = LunInfo->TargetId;
+        Srb.Lun = LunInfo->Lun;
+        Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
+        Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+        Srb.TimeOutValue = 4;
+        Srb.CdbLength = 6;
+
+        Srb.SenseInfoBuffer = SenseBuffer;
+        Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
+
+        Srb.DataBuffer = InquiryBuffer;
+        Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
+
+        /* Attach Srb to the Irp */
+        IrpStack = IoGetNextIrpStackLocation (Irp);
+        IrpStack->Parameters.Scsi.Srb = &Srb;
+
+        /* Fill in CDB */
+        Cdb = (PCDB)Srb.Cdb;
+        Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
+        Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
+        Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
+
+        /* Call the driver */
+        Status = IoCallDriver(DeviceObject, Irp);
+
+        /* Wait for it to complete */
+        if (Status == STATUS_PENDING)
+        {
+            DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
+            KeWaitForSingleObject(&Event,
+                Executive,
+                KernelMode,
+                FALSE,
+                NULL);
+            Status = IoStatusBlock.Status;
+        }
+
+        DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
+
+        if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS)
+        {
+            /* All fine, copy data over */
+            RtlCopyMemory(LunInfo->InquiryData,
+                          InquiryBuffer,
+                          INQUIRYDATABUFFERSIZE);
+
+            Status = STATUS_SUCCESS;
+            KeepTrying = FALSE;
+        }
+        else
+        {
+            DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus);
+            /* Check if the queue is frozen */
+            if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
+            {
+                /* Something weird happened, deal with it (unfreeze the queue) */
+                KeepTrying = FALSE;
+
+                DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId);
+
+                LunExtension = SpiGetLunExtension(DeviceExtension,
+                                                  LunInfo->PathId,
+                                                  LunInfo->TargetId,
+                                                  LunInfo->Lun);
+
+                /* Clear frozen flag */
+                LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
+
+                /* Acquire the spinlock */
+                KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
+
+                /* Process the request */
+                SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
+
+                /* SpiGetNextRequestFromLun() releases the spinlock,
+                   so we just lower irql back to what it was before */
+                KeLowerIrql(Irql);
+            }
+
+            /* Check if data overrun happened */
+            if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
+            {
+                DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId);
+                /* Nothing dramatic, just copy data, but limiting the size */
+                RtlCopyMemory(LunInfo->InquiryData,
+                              InquiryBuffer,
+                              (Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ?
+                              INQUIRYDATABUFFERSIZE : Srb.DataTransferLength);
+
+                Status = STATUS_SUCCESS;
+                KeepTrying = FALSE;
+            }
+            else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
+                SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
+            {
+                /* LUN is not valid, but some device responds there.
+                   Mark it as invalid anyway */
+
+                Status = STATUS_INVALID_DEVICE_REQUEST;
+                KeepTrying = FALSE;
+            }
+            else
+            {
+                /* Retry a couple of times if no timeout happened */
+                if ((RetryCount < 2) &&
+                    (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
+                    (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT))
+                {
+                    RetryCount++;
+                    KeepTrying = TRUE;
+                }
+                else
+                {
+                    /* That's all, go to exit */
+                    KeepTrying = FALSE;
+
+                    /* Set status according to SRB status */
+                    if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
+                        SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
+                    {
+                        Status = STATUS_INVALID_DEVICE_REQUEST;
+                    }
+                    else
+                    {
+                        Status = STATUS_IO_DEVICE_ERROR;
+                    }
+                }
+            }
+        }
+    }
+
+    /* Free buffers */
+    ExFreePool(InquiryBuffer);
+    ExFreePool(SenseBuffer);
+
+    DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status);
+
+    return Status;
+}
+
+
+/* Scans all SCSI buses */
+static VOID
+SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+    ULONG Bus;
+    ULONG Target;
+    ULONG Lun;
+    PSCSI_BUS_SCAN_INFO BusScanInfo;
+    PSCSI_LUN_INFO LastLunInfo, LunInfo, LunInfoExists;
+    BOOLEAN DeviceExists;
+    ULONG Hint;
+    NTSTATUS Status;
+    ULONG DevicesFound;
+
+    DPRINT("SpiScanAdapter() called\n");
+
+    /* Scan all buses */
+    for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
+    {
+        DPRINT("    Scanning bus %d\n", Bus);
+        DevicesFound = 0;
+
+        /* Get pointer to the scan information */
+        BusScanInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus];
+
+        if (BusScanInfo)
+        {
+            /* Find the last LUN info in the list */
+            LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
+            LastLunInfo = LunInfo;
+
+            while (LunInfo != NULL)
+            {
+                LastLunInfo = LunInfo;
+                LunInfo = LunInfo->Next;
+            }
+        }
+        else
+        {
+            /* We need to allocate this buffer */
+            BusScanInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_BUS_SCAN_INFO), TAG_SCSIPORT);
+
+            if (!BusScanInfo)
+            {
+                DPRINT1("Out of resources!\n");
+                return;
+            }
+
+            /* Store the pointer in the BusScanInfo array */
+            DeviceExtension->BusesConfig->BusScanInfo[Bus] = BusScanInfo;
+
+            /* Fill this struct (length and bus ids for now) */
+            BusScanInfo->Length = sizeof(SCSI_BUS_SCAN_INFO);
+            BusScanInfo->LogicalUnitsCount = 0;
+            BusScanInfo->BusIdentifier = DeviceExtension->PortConfig->InitiatorBusId[Bus];
+            BusScanInfo->LunInfo = NULL;
+
+            /* Set pointer to the last LUN info to NULL */
+            LastLunInfo = NULL;
+        }
+
+        /* Create LUN information structure */
+        LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
+
+        if (LunInfo == NULL)
+        {
+            DPRINT1("Out of resources!\n");
+            return;
+        }
+
+        RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
+
+        /* Create LunExtension */
+        LunExtension = SpiAllocateLunExtension (DeviceExtension);
+
+        /* And send INQUIRY to every target */
+        for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
+        {
+            /* TODO: Support scan bottom-up */
+
+            /* Skip if it's the same address */
+            if (Target == BusScanInfo->BusIdentifier)
+                continue;
+
+            /* Try to find an existing device here */
+            DeviceExists = FALSE;
+            LunInfoExists = BusScanInfo->LunInfo;
+
+            /* Find matching address on this bus */
+            while (LunInfoExists)
+            {
+                if (LunInfoExists->TargetId == Target)
+                {
+                    DeviceExists = TRUE;
+                    break;
+                }
+
+                /* Advance to the next one */
+                LunInfoExists = LunInfoExists->Next;
+            }
+
+            /* No need to bother rescanning, since we already did that before */
+            if (DeviceExists)
+                continue;
+
+            /* Scan all logical units */
+            for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
+            {
+                if ((!LunExtension) || (!LunInfo))
+                    break;
+
+                /* Add extension to the list */
+                Hint = (Target + Lun) % LUS_NUMBER;
+                LunExtension->Next = DeviceExtension->LunExtensionList[Hint];
+                DeviceExtension->LunExtensionList[Hint] = LunExtension;
+
+                /* Fill Path, Target, Lun fields */
+                LunExtension->PathId = LunInfo->PathId = (UCHAR)Bus;
+                LunExtension->TargetId = LunInfo->TargetId = (UCHAR) Target;
+                LunExtension->Lun = LunInfo->Lun = (UCHAR)Lun;
+
+                /* Set flag to prevent race conditions */
+                LunExtension->Flags |= SCSI_PORT_SCAN_IN_PROGRESS;
+
+                /* Zero LU extension contents */
+                if (DeviceExtension->LunExtensionSize)
+                {
+                    RtlZeroMemory(LunExtension + 1,
+                                  DeviceExtension->LunExtensionSize);
+                }
+
+                /* Finally send the inquiry command */
+                Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo);
+
+                if (NT_SUCCESS(Status))
+                {
+                    /* Let's see if we really found a device */
+                    PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
+
+                    /* Check if this device is unsupported */
+                    if (InquiryData->DeviceTypeQualifier == DEVICE_QUALIFIER_NOT_SUPPORTED)
+                    {
+                        DeviceExtension->LunExtensionList[Hint] =
+                            DeviceExtension->LunExtensionList[Hint]->Next;
+
+                        continue;
+                    }
+
+                    /* Clear the "in scan" flag */
+                    LunExtension->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS;
+
+                    DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
+                        InquiryData->DeviceType, Bus, Target, Lun);
+
+                    /* Add this info to the linked list */
+                    LunInfo->Next = NULL;
+                    if (LastLunInfo)
+                        LastLunInfo->Next = LunInfo;
+                    else
+                        BusScanInfo->LunInfo = LunInfo;
+
+                    /* Store the last LUN info */
+                    LastLunInfo = LunInfo;
+
+                    /* Store DeviceObject */
+                    LunInfo->DeviceObject = DeviceExtension->DeviceObject;
+
+                    /* Allocate another buffer */
+                    LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
+
+                    if (!LunInfo)
+                    {
+                        DPRINT1("Out of resources!\n");
+                        break;
+                    }
+
+                    RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
+
+                    /* Create a new LU extension */
+                    LunExtension = SpiAllocateLunExtension(DeviceExtension);
+
+                    DevicesFound++;
+                }
+                else
+                {
+                    /* Remove this LUN from the list */
+                    DeviceExtension->LunExtensionList[Hint] =
+                        DeviceExtension->LunExtensionList[Hint]->Next;
+
+                    /* Decide whether we are continuing or not */
+                    if (Status == STATUS_INVALID_DEVICE_REQUEST)
+                        continue;
+                    else
+                        break;
+                }
+            }
+        }
+
+        /* Free allocated buffers */
+        if (LunExtension)
+            ExFreePool(LunExtension);
+
+        if (LunInfo)
+            ExFreePool(LunInfo);
+
+        /* Sum what we found */
+        BusScanInfo->LogicalUnitsCount += (UCHAR) DevicesFound;
+        DPRINT("    Found %d devices on bus %d\n", DevicesFound, Bus);
+    }
+
+    DPRINT ("SpiScanAdapter() done\n");
+}
+
+
+static NTSTATUS
+SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                 PIRP Irp)
+{
+    ULONG InquiryDataSize;
+    PSCSI_LUN_INFO LunInfo;
+    ULONG BusCount, LunCount, Length;
+    PIO_STACK_LOCATION IrpStack;
+    PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
+    PSCSI_INQUIRY_DATA InquiryData;
+    PSCSI_BUS_DATA BusData;
+    ULONG Bus;
+    PUCHAR Buffer;
+
+    DPRINT("SpiGetInquiryData() called\n");
+
+    /* Get pointer to the buffer */
+    IrpStack = IoGetCurrentIrpStackLocation(Irp);
+    Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+    /* Initialize bus and LUN counters */
+    BusCount = DeviceExtension->BusesConfig->NumberOfBuses;
+    LunCount = 0;
+
+    /* Calculate total number of LUNs */
+    for (Bus = 0; Bus < BusCount; Bus++)
+        LunCount += DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
+
+    /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
+    InquiryDataSize =
+        ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
+        sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
+
+    /* Calculate data size */
+    Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) *
+        sizeof(SCSI_BUS_DATA);
+
+    Length += InquiryDataSize * LunCount;
+
+    /* Check, if all data is going to fit into provided buffer */
+    if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length)
+    {
+        Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+        return STATUS_BUFFER_TOO_SMALL;
+    }
+
+    /* Store data size in the IRP */
+    Irp->IoStatus.Information = Length;
+
+    DPRINT("Data size: %lu\n", Length);
+
+    AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
+
+    AdapterBusInfo->NumberOfBuses = (UCHAR)BusCount;
+
+    /* Point InquiryData to the corresponding place inside Buffer */
+    InquiryData = (PSCSI_INQUIRY_DATA)(Buffer + sizeof(SCSI_ADAPTER_BUS_INFO) +
+        (BusCount - 1) * sizeof(SCSI_BUS_DATA));
+
+    /* Loop each bus */
+    for (Bus = 0; Bus < BusCount; Bus++)
+    {
+        BusData = &AdapterBusInfo->BusData[Bus];
+
+        /* Calculate and save an offset of the inquiry data */
+        BusData->InquiryDataOffset = (PUCHAR)InquiryData - Buffer;
+
+        /* Get a pointer to the LUN information structure */
+        LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
+
+        /* Store Initiator Bus Id */
+        BusData->InitiatorBusId =
+            DeviceExtension->BusesConfig->BusScanInfo[Bus]->BusIdentifier;
+
+        /* Store LUN count */
+        BusData->NumberOfLogicalUnits =
+            DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
+
+        /* Loop all LUNs */
+        while (LunInfo != NULL)
+        {
+            DPRINT("(Bus %lu Target %lu Lun %lu)\n",
+                Bus, LunInfo->TargetId, LunInfo->Lun);
+
+            /* Fill InquiryData with values */
+            InquiryData->PathId = LunInfo->PathId;
+            InquiryData->TargetId = LunInfo->TargetId;
+            InquiryData->Lun = LunInfo->Lun;
+            InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
+            InquiryData->DeviceClaimed = LunInfo->DeviceClaimed;
+            InquiryData->NextInquiryDataOffset =
+                (PUCHAR)InquiryData + InquiryDataSize - Buffer;
+
+            /* Copy data in it */
+            RtlCopyMemory(InquiryData->InquiryData,
+                          LunInfo->InquiryData,
+                          INQUIRYDATABUFFERSIZE);
+
+            /* Move to the next LUN */
+            LunInfo = LunInfo->Next;
+            InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize);
+        }
+
+        /* Either mark the end, or set offset to 0 */
+        if (BusData->NumberOfLogicalUnits != 0)
+            ((PSCSI_INQUIRY_DATA) ((PCHAR) InquiryData - InquiryDataSize))->NextInquiryDataOffset = 0;
+        else
+            BusData->InquiryDataOffset = 0;
+    }
+
+    /* Finish with success */
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    return STATUS_SUCCESS;
+}
+
+static PSCSI_REQUEST_BLOCK_INFO
+SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+              IN UCHAR PathId,
+              IN UCHAR TargetId,
+              IN UCHAR Lun,
+              IN UCHAR QueueTag)
+{
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+
+    if (QueueTag == SP_UNTAGGED)
+    {
+        /* Untagged request, get LU and return pointer to SrbInfo */
+        LunExtension = SpiGetLunExtension(DeviceExtension,
+                                          PathId,
+                                          TargetId,
+                                          Lun);
+
+        /* Return NULL in case of error */
+        if (!LunExtension)
+            return(NULL);
+
+        /* Return the pointer to SrbInfo */
+        return &LunExtension->SrbInfo;
+    }
+    else
+    {
+        /* Make sure the tag is valid, if it is - return the data */
+        if (QueueTag > DeviceExtension->SrbDataCount || QueueTag < 1)
+            return NULL;
+        else
+            return &DeviceExtension->SrbInfo[QueueTag -1];
+    }
+}
+
+static VOID
+SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                    IN PSCSI_REQUEST_BLOCK InitialSrb)
+{
+    PSCSI_REQUEST_BLOCK Srb;
+    PCDB Cdb;
+    PIRP Irp;
+    PIO_STACK_LOCATION IrpStack;
+    LARGE_INTEGER LargeInt;
+    PVOID *Ptr;
+
+    DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb);
+
+    /* Allocate Srb */
+    Srb = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(PVOID), TAG_SCSIPORT);
+    RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
+
+    /* Allocate IRP */
+    LargeInt.QuadPart = (LONGLONG) 1;
+    Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
+                                        DeviceExtension->DeviceObject,
+                                        InitialSrb->SenseInfoBuffer,
+                                        InitialSrb->SenseInfoBufferLength,
+                                        &LargeInt,
+                                        NULL);
+
+    IoSetCompletionRoutine(Irp,
+                           (PIO_COMPLETION_ROUTINE)SpiCompletionRoutine,
+                           Srb,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+
+    if (!Srb)
+    {
+        DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb);
+        return;
+    }
+
+    IrpStack = IoGetNextIrpStackLocation(Irp);
+    IrpStack->MajorFunction = IRP_MJ_SCSI;
+
+    /* Put Srb address into Irp... */
+    IrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
+
+    /* ...and vice versa */
+    Srb->OriginalRequest = Irp;
+
+    /* Save Srb */
+    Ptr = (PVOID *)(Srb+1);
+    *Ptr = InitialSrb;
+
+    /* Build CDB for REQUEST SENSE */
+    Srb->CdbLength = 6;
+    Cdb = (PCDB)Srb->Cdb;
+
+    Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
+    Cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
+    Cdb->CDB6INQUIRY.Reserved1 = 0;
+    Cdb->CDB6INQUIRY.PageCode = 0;
+    Cdb->CDB6INQUIRY.IReserved = 0;
+    Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)InitialSrb->SenseInfoBufferLength;
+    Cdb->CDB6INQUIRY.Control = 0;
+
+    /* Set address */
+    Srb->TargetId = InitialSrb->TargetId;
+    Srb->Lun = InitialSrb->Lun;
+    Srb->PathId = InitialSrb->PathId;
+
+    Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+    Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+
+    /* Timeout will be 2 seconds */
+    Srb->TimeOutValue = 2;
+
+    /* No auto request sense */
+    Srb->SenseInfoBufferLength = 0;
+    Srb->SenseInfoBuffer = NULL;
+
+    /* Set necessary flags */
+    Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE |
+                    SRB_FLAGS_DISABLE_DISCONNECT;
+
+    /* Transfer disable synch transfer flag */
+    if (InitialSrb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER)
+        Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+
+    Srb->DataBuffer = InitialSrb->SenseInfoBuffer;
+
+    /* Fill the transfer length */
+    Srb->DataTransferLength = InitialSrb->SenseInfoBufferLength;
+
+    /* Clear statuses */
+    Srb->ScsiStatus = Srb->SrbStatus = 0;
+    Srb->NextSrb = 0;
+
+    /* Call the driver */
+    (VOID)IoCallDriver(DeviceExtension->DeviceObject, Irp);
+
+    DPRINT("SpiSendRequestSense() done\n");
+}
+
+
+static
+VOID
+NTAPI
+SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                           IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
+                           OUT PBOOLEAN NeedToCallStartIo)
+{
+    PSCSI_REQUEST_BLOCK Srb;
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+    LONG Result;
+    PIRP Irp;
+    ULONG SequenceNumber;
+
+    Srb = SrbInfo->Srb;
+    Irp = Srb->OriginalRequest;
+
+    /* Get Lun extension */
+    LunExtension = SpiGetLunExtension(DeviceExtension,
+                                     Srb->PathId,
+                                     Srb->TargetId,
+                                     Srb->Lun);
+
+    if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION &&
+        DeviceExtension->MapBuffers &&
+        Irp->MdlAddress)
+    {
+        /* MDL is shared if transfer is broken into smaller parts */
+        Srb->DataBuffer = (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
+            ((PCCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
+
+        /* In case of data going in, flush the buffers */
+        if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
+        {
+            KeFlushIoBuffers(Irp->MdlAddress,
+                             TRUE,
+                             FALSE);
+        }
+    }
+
+    /* Flush adapter if needed */
+    if (SrbInfo->BaseOfMapRegister)
+    {
+        /* TODO: Implement */
+        ASSERT(FALSE);
+    }
+
+    /* Clear the request */
+    SrbInfo->Srb = NULL;
+
+    /* If disconnect is disabled... */
+    if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+    {
+        /* Acquire the spinlock since we mess with flags */
+        KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+        /* Set corresponding flag */
+        DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
+
+        /* Clear the timer if needed */
+        if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET))
+            DeviceExtension->TimerCount = -1;
+
+        /* Spinlock is not needed anymore */
+        KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+        if (!(DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) &&
+            !(DeviceExtension->Flags & SCSI_PORT_DEVICE_BUSY) &&
+            !(*NeedToCallStartIo))
+        {
+            /* We're not busy, but we have a request pending */
+            IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
+        }
+    }
+
+    /* Scatter/gather */
+    if (Srb->SrbFlags & SRB_FLAGS_SGLIST_FROM_POOL)
+    {
+        /* TODO: Implement */
+        ASSERT(FALSE);
+    }
+
+    /* Acquire spinlock (we're freeing SrbExtension) */
+    KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+    /* Free it (if needed) */
+    if (Srb->SrbExtension)
+    {
+        if (Srb->SenseInfoBuffer != NULL && DeviceExtension->SupportsAutoSense)
+        {
+            ASSERT(Srb->SenseInfoBuffer == NULL || SrbInfo->SaveSenseRequest != NULL);
+
+            if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)
+            {
+                /* Copy sense data to the buffer */
+                RtlCopyMemory(SrbInfo->SaveSenseRequest,
+                              Srb->SenseInfoBuffer,
+                              Srb->SenseInfoBufferLength);
+            }
+
+            /* And restore the pointer */
+            Srb->SenseInfoBuffer = SrbInfo->SaveSenseRequest;
+        }
+
+        /* Put it into the free srb extensions list */
+        *((PVOID *)Srb->SrbExtension) = DeviceExtension->FreeSrbExtensions;
+        DeviceExtension->FreeSrbExtensions = Srb->SrbExtension;
+    }
+
+    /* Save transfer length in the IRP */
+    Irp->IoStatus.Information = Srb->DataTransferLength;
+
+    SequenceNumber = SrbInfo->SequenceNumber;
+    SrbInfo->SequenceNumber = 0;
+
+    /* Decrement the queue count */
+    LunExtension->QueueCount--;
+
+    /* Free Srb, if needed*/
+    if (Srb->QueueTag != SP_UNTAGGED)
+    {
+        /* Put it into the free list */
+        SrbInfo->Requests.Blink = NULL;
+        SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
+        DeviceExtension->FreeSrbInfo = SrbInfo;
+    }
+
+    /* SrbInfo is not used anymore */
+    SrbInfo = NULL;
+
+    if (DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING)
+    {
+        /* Clear the flag */
+        DeviceExtension->Flags &= ~SCSI_PORT_REQUEST_PENDING;
+
+        /* Note the caller about StartIo */
+        *NeedToCallStartIo = TRUE;
+    }
+
+    if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
+    {
+        /* Start the packet */
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+
+        if (!(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) &&
+            LunExtension->RequestTimeout == -1)
+        {
+            /* Start the next packet */
+            SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
+        }
+        else
+        {
+            /* Release the spinlock */
+            KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+        }
+
+        DPRINT("IoCompleting request IRP 0x%p\n", Irp);
+
+        IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+        /* Decrement number of active requests, and analyze the result */
+        Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
+
+        if (Result < 0 &&
+            !DeviceExtension->MapRegisters &&
+            DeviceExtension->AdapterObject != NULL)
+        {
+            /* Nullify map registers */
+            DeviceExtension->MapRegisterBase = NULL;
+            IoFreeAdapterChannel(DeviceExtension->AdapterObject);
+        }
+
+         /* Exit, we're done */
+        return;
     }
 
-  switch (Srb->Function)
+    /* Decrement number of active requests, and analyze the result */
+    Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
+
+    if (Result < 0 &&
+        !DeviceExtension->MapRegisters &&
+        DeviceExtension->AdapterObject != NULL)
     {
-      case SRB_FUNCTION_EXECUTE_SCSI:
-      case SRB_FUNCTION_IO_CONTROL:
-        IoMarkIrpPending(Irp);
-       Srb->OriginalRequest = LunExtension;
-        Irp->Tail.Overlay.DriverContext[3] = Srb;
-       SpiProcessRequests(DeviceExtension, Irp);
-       return(STATUS_PENDING);
-
-      case SRB_FUNCTION_SHUTDOWN:
-      case SRB_FUNCTION_FLUSH:
-       if (DeviceExtension->PortConfig->CachesData == TRUE)
-         {
-            IoMarkIrpPending(Irp);
-           Srb->OriginalRequest = LunExtension;
-            Irp->Tail.Overlay.DriverContext[3] = Srb;
-           SpiProcessRequests(DeviceExtension, Irp);
-           return(STATUS_PENDING);
-         }
-       break;
+        /* Result is negative, so this is a slave, free map registers */
+        DeviceExtension->MapRegisterBase = NULL;
+        IoFreeAdapterChannel(DeviceExtension->AdapterObject);
+    }
 
-      case SRB_FUNCTION_CLAIM_DEVICE:
-       DPRINT ("  SRB_FUNCTION_CLAIM_DEVICE\n");
+    /* Convert status */
+    Irp->IoStatus.Status = SpiStatusSrbToNt(Srb->SrbStatus);
 
-       /* Reference device object and keep the device object */
-       ObReferenceObject(DeviceObject);
-       LunExtension->DeviceObject = DeviceObject;
-       LunExtension->DeviceClaimed = TRUE;
-       Srb->DataBuffer = DeviceObject;
-       break;
+    /* It's not a bypass, it's busy or the queue is full? */
+    if ((Srb->ScsiStatus == SCSISTAT_BUSY ||
+         Srb->SrbStatus == SRB_STATUS_BUSY ||
+         Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) &&
+         !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE))
+    {
 
-      case SRB_FUNCTION_RELEASE_DEVICE:
-       DPRINT ("  SRB_FUNCTION_RELEASE_DEVICE\n");
-       DPRINT ("PathId: %lu  TargetId: %lu  Lun: %lu\n",
-               Srb->PathId, Srb->TargetId, Srb->Lun);
+        DPRINT("Busy SRB status %x\n", Srb->SrbStatus);
 
-       /* Dereference device object and clear the device object */
-       ObDereferenceObject(LunExtension->DeviceObject);
-       LunExtension->DeviceObject = NULL;
-       LunExtension->DeviceClaimed = FALSE;
-       break;
+        /* Requeu, if needed */
+        if (LunExtension->Flags & (LUNEX_FROZEN_QUEUE | LUNEX_BUSY))
+        {
+            DPRINT("it's being requeued\n");
 
-      default:
-       DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
-       Status = STATUS_NOT_IMPLEMENTED;
-       break;
-    }
+            Srb->SrbStatus = SRB_STATUS_PENDING;
+            Srb->ScsiStatus = 0;
 
-  Irp->IoStatus.Status = Status;
-  Irp->IoStatus.Information = DataSize;
+            if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
+                                          &Irp->Tail.Overlay.DeviceQueueEntry,
+                                          Srb->QueueSortKey))
+            {
+                /* It's a big f.ck up if we got here */
+                Srb->SrbStatus = SRB_STATUS_ERROR;
+                Srb->ScsiStatus = SCSISTAT_BUSY;
 
-  IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                ASSERT(FALSE);
+                goto Error;
+            }
 
-  return(Status);
-}
+            /* Release the spinlock */
+            KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
 
+        }
+        else if (LunExtension->AttemptCount++ < 20)
+        {
+            /* LUN is still busy */
+            Srb->ScsiStatus = 0;
+            Srb->SrbStatus = SRB_STATUS_PENDING;
 
-/**********************************************************************
- * NAME                                                        INTERNAL
- *     ScsiPortDeviceControl
- *
- * DESCRIPTION
- *     Answer requests for device control calls
- *
- * RUN LEVEL
- *     PASSIVE_LEVEL
- *
- * ARGUMENTS
- *     Standard dispatch arguments
- *
- * RETURNS
- *     NTSTATUS
- */
+            LunExtension->BusyRequest = Irp;
+            LunExtension->Flags |= LUNEX_BUSY;
 
-static NTSTATUS STDCALL
-ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
-                     IN PIRP Irp)
-{
-  PIO_STACK_LOCATION Stack;
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  NTSTATUS Status = STATUS_SUCCESS;
+            /* Release the spinlock */
+            KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+        }
+        else
+        {
+Error:
+            /* Freeze the queue*/
+            Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
+            LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
 
-  DPRINT("ScsiPortDeviceControl()\n");
+            /* "Unfull" the queue */
+            LunExtension->Flags &= ~LUNEX_FULL_QUEUE;
 
-  Irp->IoStatus.Information = 0;
+            /* Release the spinlock */
+            KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
 
+            /* Return status that the device is not ready */
+            Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
+            IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+        }
 
-  Stack = IoGetCurrentIrpStackLocation(Irp);
-  DeviceExtension = DeviceObject->DeviceExtension;
+        return;
+    }
 
-  switch (Stack->Parameters.DeviceIoControl.IoControlCode)
+    /* Start the next request, if LUN is idle, and this is sense request */
+    if (((Srb->ScsiStatus != SCSISTAT_CHECK_CONDITION) ||
+        (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) ||
+        !Srb->SenseInfoBuffer || !Srb->SenseInfoBufferLength)
+        && (Srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE))
     {
-      case IOCTL_SCSI_GET_DUMP_POINTERS:
-       {
-         PDUMP_POINTERS DumpPointers;
-         DPRINT("  IOCTL_SCSI_GET_DUMP_POINTERS\n");
-         DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
-         DumpPointers->DeviceObject = DeviceObject;
-
-         Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
-       }
-       break;
+        if (LunExtension->RequestTimeout == -1)
+            SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
+        else
+            KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+    }
+    else
+    {
+        /* Freeze the queue */
+        Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
+        LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
+
+        /* Do we need a request sense? */
+        if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
+            !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
+            Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength)
+        {
+            /* If LUN is busy, we have to requeue it in order to allow request sense */
+            if (LunExtension->Flags & LUNEX_BUSY)
+            {
+                DPRINT("Requeueing busy request to allow request sense\n");
 
-      case IOCTL_SCSI_GET_CAPABILITIES:
-       {
-         DPRINT("  IOCTL_SCSI_GET_CAPABILITIES\n");
+                if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
+                    &LunExtension->BusyRequest->Tail.Overlay.DeviceQueueEntry,
+                    Srb->QueueSortKey))
+                {
+                    /* We should never get here */
+                    ASSERT(FALSE);
 
-         *((PIO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer) =
-           DeviceExtension->PortCapabilities;
+                    KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+                    IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+                    return;
 
-         Irp->IoStatus.Information = sizeof(PIO_SCSI_CAPABILITIES);
-       }
-       break;
+                }
 
-      case IOCTL_SCSI_GET_INQUIRY_DATA:
-       {
-         DPRINT("  IOCTL_SCSI_GET_INQUIRY_DATA\n");
+                /* Clear busy flags */
+                LunExtension->Flags &= ~(LUNEX_FULL_QUEUE | LUNEX_BUSY);
+            }
 
-         /* Copy inquiry data to the port device extension */
-         Irp->IoStatus.Information =
-           SpiGetInquiryData(DeviceExtension,
-                             Irp->AssociatedIrp.SystemBuffer);
-         DPRINT("Inquiry data size: %lu\n", Irp->IoStatus.Information);
-       }
-       break;
-      
-      case IOCTL_SCSI_PASS_THROUGH:
-        DPRINT("  IOCTL_SCSI_PASS_THROUGH\n");
-        Status = STATUS_NOT_IMPLEMENTED;
-        break;
+            /* Release the spinlock */
+            KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
 
-      case IOCTL_SCSI_PASS_THROUGH_DIRECT:
-        DPRINT("  IOCTL_SCSI_PASS_THROUGH_DIRECT\n");
-        Status = STATUS_NOT_IMPLEMENTED;
-        break;
+            /* Send RequestSense */
+            SpiSendRequestSense(DeviceExtension, Srb);
 
-      case IOCTL_SCSI_MINIPORT:
-        DPRINT("  IOCTL_SCSI_MINIPORT\n");
-        DPRINT("  Signature: %.8s\n", ((PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer)->Signature);
-        DPRINT("  ControlCode: 0x%lX\n", ((PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer)->ControlCode);
-        return SpiScsiMiniport(DeviceObject, Irp);
+            /* Exit */
+            return;
+        }
 
-      default:
-       DPRINT1("  unknown ioctl code: 0x%lX\n",
-              Stack->Parameters.DeviceIoControl.IoControlCode);
-        Status = STATUS_INVALID_DEVICE_REQUEST;
-       break;
+        /* Release the spinlock */
+        KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
     }
 
-  Irp->IoStatus.Status = Status;
-  IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
-  return Status;
+    /* Complete the request */
+    IoCompleteRequest(Irp, IO_DISK_INCREMENT);
 }
 
-static NTSTATUS STDCALL
-SpiCompletion(IN PDEVICE_OBJECT DeviceObject,
-             IN PIRP Irp,
-             IN PVOID Context)
+NTSTATUS
+NTAPI
+SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
+                     PIRP Irp,
+                     PVOID Context)
 {
-  PSCSI_REQUEST_BLOCK Srb;
-  
-  DPRINT("SpiCompletion(DeviceObject %x, Irp %x, Context %x)\n",
-         DeviceObject, Irp, Context);
+    PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)Context;
+    PSCSI_REQUEST_BLOCK InitialSrb;
+    PIRP InitialIrp;
 
-  Srb = (PSCSI_REQUEST_BLOCK)Context;
-  Irp->IoStatus.Information = 0;
+    DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp);
 
-  switch (SRB_STATUS(Srb->SrbStatus))
+    if ((Srb->Function == SRB_FUNCTION_RESET_BUS) ||
+        (Srb->Function == SRB_FUNCTION_ABORT_COMMAND))
     {
-      case SRB_STATUS_SUCCESS:
-        Irp->IoStatus.Status = STATUS_SUCCESS;
-        Irp->IoStatus.Information = Srb->DataTransferLength;
-        break;
+        /* Deallocate SRB and IRP and exit */
+        ExFreePool(Srb);
+        IoFreeIrp(Irp);
 
-      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;
+        return STATUS_MORE_PROCESSING_REQUIRED;
+    }
 
-      case SRB_STATUS_NO_DEVICE:
-        Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
-        break;
+    /* Get a pointer to the SRB and IRP which were initially sent */
+    InitialSrb = *((PVOID *)(Srb+1));
+    InitialIrp = InitialSrb->OriginalRequest;
 
-      case SRB_STATUS_BUSY:
-       Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
-        break;
+    if ((SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
+        (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN))
+    {
+        /* Sense data is OK */
+        InitialSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
 
-      case SRB_STATUS_DATA_OVERRUN:
-       Irp->IoStatus.Status = STATUS_DATA_OVERRUN;
-        Irp->IoStatus.Information = Srb->DataTransferLength;
-        break;
+        /* Set length to be the same */
+        InitialSrb->SenseInfoBufferLength = (UCHAR)Srb->DataTransferLength;
+    }
 
-      case SRB_STATUS_INVALID_REQUEST:
-        Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
-        break;
+    /* Make sure initial SRB's queue is frozen */
+    ASSERT(InitialSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN);
 
-      default:
-       Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
-       break;
-    }
+    /* Complete this request */
+    IoCompleteRequest(InitialIrp, IO_DISK_INCREMENT);
 
-  ExFreePool(Srb);
+    /* Deallocate everything (internal) */
+    ExFreePool(Srb);
 
-  if (Irp->PendingReturned)
+    if (Irp->MdlAddress != NULL)
     {
-      IoMarkIrpPending (Irp);
+               MmUnlockPages(Irp->MdlAddress);
+        IoFreeMdl(Irp->MdlAddress);
+        Irp->MdlAddress = NULL;
     }
-  return Irp->IoStatus.Status;
+
+    IoFreeIrp(Irp);
+    return STATUS_MORE_PROCESSING_REQUIRED;
 }
 
-static NTSTATUS
-SpiScsiMiniport(IN PDEVICE_OBJECT DeviceObject,
-               IN PIRP Irp)
+static BOOLEAN NTAPI
+ScsiPortIsr(IN PKINTERRUPT Interrupt,
+            IN PVOID ServiceContext)
 {
-  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);
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    BOOLEAN Result;
 
-  DeviceExtension = DeviceObject->DeviceExtension;
-  SrbIoControl = (PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer;
+    DPRINT("ScsiPortIsr() called!\n");
 
-  IrpStack = IoGetCurrentIrpStackLocation(Irp);
-  if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SRB_IO_CONTROL))
-    {
-      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)
+    DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
+
+    /* If interrupts are disabled - we don't expect any */
+    if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS)
+        return FALSE;
+
+    /* Call miniport's HwInterrupt routine */
+    Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
+
+    /* If flag of notification is set - queue a DPC */
+    if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
     {
-      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;
+        IoRequestDpc(DeviceExtension->DeviceObject,
+                     DeviceExtension->CurrentIrp,
+                     DeviceExtension);
     }
-  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;
-    }
-
-  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);
+
+    return TRUE;
 }
 
-static VOID
-SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                       PSCSI_REQUEST_BLOCK Srb)
+BOOLEAN
+NTAPI
+SpiSaveInterruptData(IN PVOID Context)
 {
-  ULONG index;
+    PSCSI_PORT_SAVE_INTERRUPT InterruptContext = Context;
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+    PSCSI_REQUEST_BLOCK Srb;
+    PSCSI_REQUEST_BLOCK_INFO SrbInfo, NextSrbInfo;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    BOOLEAN IsTimed;
+
+    /* Get pointer to the device extension */
+    DeviceExtension = InterruptContext->DeviceExtension;
+
+    /* If we don't have anything pending - return */
+    if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED))
+        return FALSE;
+
+    /* Actually save the interrupt data */
+    *InterruptContext->InterruptData = DeviceExtension->InterruptData;
+
+    /* Clear the data stored in the device extension */
+    DeviceExtension->InterruptData.Flags &=
+        (SCSI_PORT_RESET | SCSI_PORT_RESET_REQUEST | SCSI_PORT_DISABLE_INTERRUPTS);
+    DeviceExtension->InterruptData.CompletedAbort = NULL;
+    DeviceExtension->InterruptData.ReadyLun = NULL;
+    DeviceExtension->InterruptData.CompletedRequests = NULL;
+
+    /* Loop through the list of completed requests */
+    SrbInfo = InterruptContext->InterruptData->CompletedRequests;
+
+    while (SrbInfo)
+    {
+        /* Make sure we have SRV */
+        ASSERT(SrbInfo->Srb);
 
-  DPRINT("SpiAllocateSrbExtension\n");
+        /* Get SRB and LunExtension */
+        Srb = SrbInfo->Srb;
 
-  DPRINT("DeviceExtension->VirtualAddress %x, DeviceExtension->SrbExtensionSize %x\n",
-         DeviceExtension->VirtualAddress, DeviceExtension->SrbExtensionSize);
+        LunExtension = SpiGetLunExtension(DeviceExtension,
+                                          Srb->PathId,
+                                          Srb->TargetId,
+                                          Srb->Lun);
 
-  Srb->SrbExtension = NULL;
-  if (DeviceExtension->VirtualAddress != NULL &&
-      DeviceExtension->SrbExtensionSize > 0)
-    {
-      index = RtlFindClearBitsAndSet(&DeviceExtension->SrbExtensionAllocMap, 1, 0);
-      if (index != 0xffffffff)
+        /* We have to check special cases if request is unsuccessfull*/
+        if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
         {
-         DeviceExtension->CurrentSrbExtensions++;
-          Srb->SrbExtension = (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + index * DeviceExtension->SrbExtensionSize);
-       }
-    }
-  DPRINT("%x\n", Srb->SrbExtension);
-}
+            /* Check if we need request sense by a few conditions */
+            if (Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength &&
+                Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
+                !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
+            {
+                if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
+                {
+                    /* It means: we tried to send REQUEST SENSE, but failed */
 
-static VOID
-SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                   PSCSI_REQUEST_BLOCK Srb)
-{
-  ULONG index;
+                    Srb->ScsiStatus = 0;
+                    Srb->SrbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
+                }
+                else
+                {
+                    /* Set the corresponding flag, so that REQUEST SENSE
+                       will be sent */
+                    LunExtension->Flags |= LUNEX_NEED_REQUEST_SENSE;
+                }
 
-  if (DeviceExtension->VirtualAddress != NULL &&
-      DeviceExtension->SrbExtensionSize > 0 &&
-      Srb->SrbExtension != NULL)
-    {
-      index = ((ULONG_PTR)Srb->SrbExtension - (ULONG_PTR)DeviceExtension->VirtualAddress) / DeviceExtension->SrbExtensionSize;
-      RtlClearBits(&DeviceExtension->SrbExtensionAllocMap, index, 1);
-      DeviceExtension->CurrentSrbExtensions--;
-    }
-  Srb->SrbExtension = NULL;
-}
+            }
 
+            /* Check for a full queue */
+            if (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL)
+            {
+                /* TODO: Implement when it's encountered */
+                ASSERT(FALSE);
+            }
+        }
 
-static BOOLEAN STDCALL
-ScsiPortStartPacket(IN OUT PVOID Context)
-{
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
-  PSCSI_REQUEST_BLOCK Srb;
-  PIRP Irp;
-  PIO_STACK_LOCATION IrpStack;
+        /* Let's decide if we need to watch timeout or not */
+        if (Srb->QueueTag == SP_UNTAGGED)
+        {
+            IsTimed = TRUE;
+        }
+        else
+        {
+            if (LunExtension->SrbInfo.Requests.Flink == &SrbInfo->Requests)
+                IsTimed = TRUE;
+            else
+                IsTimed = FALSE;
+
+            /* Remove it from the queue */
+            RemoveEntryList(&SrbInfo->Requests);
+        }
+
+        if (IsTimed)
+        {
+            /* We have to maintain timeout counter */
+            if (IsListEmpty(&LunExtension->SrbInfo.Requests))
+            {
+                LunExtension->RequestTimeout = -1;
+            }
+            else
+            {
+                NextSrbInfo = CONTAINING_RECORD(LunExtension->SrbInfo.Requests.Flink,
+                                                SCSI_REQUEST_BLOCK_INFO,
+                                                Requests);
 
-  DPRINT("ScsiPortStartPacket(Context %x) called\n", Context);
+                Srb = NextSrbInfo->Srb;
 
-  Srb = (PSCSI_REQUEST_BLOCK)Context;
-  Irp = (PIRP)Srb->OriginalRequest;
-  IrpStack = IoGetCurrentIrpStackLocation(Irp);
-  DeviceExtension = IrpStack->DeviceObject->DeviceExtension;
+                /* Update timeout counter */
+                LunExtension->RequestTimeout = Srb->TimeOutValue;
+            }
+        }
 
-  return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
-                                   Srb));
-}
+        SrbInfo = SrbInfo->CompletedRequests;
+    }
 
+    return TRUE;
+}
 
-static PSCSI_PORT_LUN_EXTENSION
-SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                        IN UCHAR PathId,
-                        IN UCHAR TargetId,
-                        IN UCHAR Lun)
+VOID
+NTAPI
+SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                         IN PSCSI_PORT_LUN_EXTENSION LunExtension)
 {
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  ULONG LunExtensionSize;
+    PIO_STACK_LOCATION IrpStack;
+    PIRP NextIrp;
+    PKDEVICE_QUEUE_ENTRY Entry;
+    PSCSI_REQUEST_BLOCK Srb;
 
-  DPRINT("SpiAllocateLunExtension (%p %u %u %u)\n",
-        DeviceExtension, PathId, TargetId, Lun);
 
-  LunExtensionSize =
-    sizeof(SCSI_PORT_LUN_EXTENSION) + DeviceExtension->LunExtensionSize;
-  DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
-
-  LunExtension = ExAllocatePool(NonPagedPool,
-                               LunExtensionSize);
-  if (LunExtension == NULL)
+    /* If LUN is not active or queue is more than maximum allowed  */
+    if (LunExtension->QueueCount >= LunExtension->MaxQueueCount ||
+        !(LunExtension->Flags & SCSI_PORT_LU_ACTIVE))
     {
-      return NULL;
+        /* Release the spinlock and exit */
+        KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+        return;
     }
 
-  RtlZeroMemory(LunExtension,
-               LunExtensionSize);
+    /* Check if we can get a next request */
+    if (LunExtension->Flags &
+        (LUNEX_NEED_REQUEST_SENSE | LUNEX_BUSY |
+         LUNEX_FULL_QUEUE | LUNEX_FROZEN_QUEUE | LUNEX_REQUEST_PENDING))
+    {
+        /* Pending requests can only be started if the queue is empty */
+        if (IsListEmpty(&LunExtension->SrbInfo.Requests) &&
+            !(LunExtension->Flags &
+              (LUNEX_BUSY | LUNEX_FROZEN_QUEUE | LUNEX_FULL_QUEUE | LUNEX_NEED_REQUEST_SENSE)))
+        {
+            /* Make sure we have SRB */
+            ASSERT(LunExtension->SrbInfo.Srb == NULL);
 
-  InsertTailList(&DeviceExtension->LunExtensionListHead,
-                &LunExtension->List);
+            /* Clear active and pending flags */
+            LunExtension->Flags &= ~(LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE);
 
-  LunExtension->PathId = PathId;
-  LunExtension->TargetId = TargetId;
-  LunExtension->Lun = Lun;
+            /* Get next Irp, and clear pending requests list */
+            NextIrp = LunExtension->PendingRequest;
+            LunExtension->PendingRequest = NULL;
 
-  LunExtension->PendingIrpCount = 0;
-  LunExtension->ActiveIrpCount = 0;
+            /* Set attempt counter to zero */
+            LunExtension->AttemptCount = 0;
 
-  LunExtension->NextIrp = NULL;
+            /* Release the spinlock */
+            KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
 
-  return LunExtension;
-}
+            /* Start the next pending request */
+            IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
 
+            return;
+        }
+        else
+        {
+            /* Release the spinlock, without clearing any flags and exit */
+            KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
 
-static VOID
-SpiRemoveLunExtension (IN PSCSI_PORT_LUN_EXTENSION LunExtension)
-{
-  DPRINT("SpiRemoveLunExtension(%p) called\n",
-        LunExtension);
+            return;
+        }
+    }
 
-  if (LunExtension == NULL)
-    return;
+    /* Reset active flag */
+    LunExtension->Flags &= ~SCSI_PORT_LU_ACTIVE;
 
-  RemoveEntryList (&LunExtension->List);
+    /* Set attempt counter to zero */
+    LunExtension->AttemptCount = 0;
 
+    /* Remove packet from the device queue */
+    Entry = KeRemoveByKeyDeviceQueue(&LunExtension->DeviceQueue, LunExtension->SortKey);
+
+    if (Entry != NULL)
+    {
+        /* Get pointer to the next irp */
+        NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
 
-  /* Release LUN extersion data */
+        /* Get point to the SRB */
+        IrpStack = IoGetCurrentIrpStackLocation(NextIrp);
+        Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
 
+        /* Set new key*/
+        LunExtension->SortKey = Srb->QueueSortKey;
+        LunExtension->SortKey++;
 
-  ExFreePool (LunExtension);
+        /* Release the spinlock */
+        KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
 
-  return;
+        /* Start the next pending request */
+        IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
+    }
+    else
+    {
+        /* Release the spinlock */
+        KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+    }
 }
 
 
-static PSCSI_PORT_LUN_EXTENSION
-SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                   IN UCHAR PathId,
-                   IN UCHAR TargetId,
-                   IN UCHAR Lun)
+
+//    ScsiPortDpcForIsr
+//  DESCRIPTION:
+//
+//  RUN LEVEL:
+//
+//  ARGUMENTS:
+//    IN PKDPC          Dpc
+//    IN PDEVICE_OBJECT DpcDeviceObject
+//    IN PIRP           DpcIrp
+//    IN PVOID          DpcContext
+//
+static VOID NTAPI
+ScsiPortDpcForIsr(IN PKDPC Dpc,
+                 IN PDEVICE_OBJECT DpcDeviceObject,
+                 IN PIRP DpcIrp,
+                 IN PVOID DpcContext)
 {
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  PLIST_ENTRY Entry;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DpcDeviceObject->DeviceExtension;
+    SCSI_PORT_INTERRUPT_DATA InterruptData;
+    SCSI_PORT_SAVE_INTERRUPT Context;
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+    BOOLEAN NeedToStartIo;
+    PSCSI_REQUEST_BLOCK_INFO SrbInfo;
 
-  DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
-        DeviceExtension, PathId, TargetId, Lun);
+    DPRINT("ScsiPortDpcForIsr(Dpc %p  DpcDeviceObject %p  DpcIrp %p  DpcContext %p)\n",
+           Dpc, DpcDeviceObject, DpcIrp, DpcContext);
 
-  if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
-    return NULL;
+    /* We need to acquire spinlock */
+    KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
 
-  Entry = DeviceExtension->LunExtensionListHead.Flink;
-  while (Entry != &DeviceExtension->LunExtensionListHead)
+       RtlZeroMemory(&InterruptData, sizeof(SCSI_PORT_INTERRUPT_DATA));
+
+TryAgain:
+
+    /* Interrupt structure must be snapshotted, and only then analyzed */
+    Context.InterruptData = &InterruptData;
+    Context.DeviceExtension = DeviceExtension;
+
+    if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
+                                SpiSaveInterruptData,
+                                &Context))
     {
-      LunExtension = CONTAINING_RECORD(Entry,
-                                      SCSI_PORT_LUN_EXTENSION,
-                                      List);
-      if (LunExtension->PathId == PathId &&
-         LunExtension->TargetId == TargetId &&
-         LunExtension->Lun == Lun)
-       {
-         return LunExtension;
-       }
+        /* Nothing - just return (don't forget to release the spinlock */
+        KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+        DPRINT("ScsiPortDpcForIsr() done\n");
+        return;
+    }
 
-      Entry = Entry->Flink;
+    /* If flush of adapters is needed - do it */
+    if (InterruptData.Flags & SCSI_PORT_FLUSH_ADAPTERS)
+    {
+        /* TODO: Implement */
+        ASSERT(FALSE);
     }
 
-  return NULL;
-}
+    /* Check for IoMapTransfer */
+    if (InterruptData.Flags & SCSI_PORT_MAP_TRANSFER)
+    {
+        /* TODO: Implement */
+        ASSERT(FALSE);
+    }
 
+    /* Check if timer is needed */
+    if (InterruptData.Flags & SCIS_PORT_TIMER_NEEDED)
+    {
+        /* TODO: Implement */
+        ASSERT(FALSE);
+    }
 
-static NTSTATUS
-SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
-               IN OUT PSCSI_REQUEST_BLOCK Srb,
-               IN OUT PIO_STATUS_BLOCK IoStatusBlock,
-               IN OUT PKEVENT Event)
-{
-  PIO_STACK_LOCATION IrpStack;
-  PIRP Irp;
-  NTSTATUS Status;
+    /* If it's ready for the next request */
+    if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
+    {
+        /* Check for a duplicate request (NextRequest+NextLuRequest) */
+        if ((DeviceExtension->Flags &
+            (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED)) ==
+            (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED))
+        {
+            /* Clear busy flag set by ScsiPortStartPacket() */
+            DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
 
-  DPRINT ("SpiSendInquiry() called\n");
+            if (!(InterruptData.Flags & SCSI_PORT_RESET))
+            {
+                /* Ready for next, and no reset is happening */
+                DeviceExtension->TimerCount = -1;
+            }
+        }
+        else
+        {
+            /* Not busy, but not ready for the next request */
+            DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
+            InterruptData.Flags &= ~SCSI_PORT_NEXT_REQUEST_READY;
+        }
+    }
 
+    /* Any resets? */
+    if (InterruptData.Flags & SCSI_PORT_RESET_REPORTED)
+    {
+        /* Hold for a bit */
+        DeviceExtension->TimerCount = 4;
+    }
 
-  KeInitializeEvent (Event,
-                    NotificationEvent,
-                    FALSE);
+    /* Any ready LUN? */
+    if (InterruptData.ReadyLun != NULL)
+    {
 
-  Irp = IoBuildDeviceIoControlRequest (IOCTL_SCSI_EXECUTE_OUT,
-                                      DeviceObject,
-                                      NULL,
-                                      0,
-                                      Srb->DataBuffer,
-                                      Srb->DataTransferLength,
-                                      TRUE,
-                                      Event,
-                                      IoStatusBlock);
-  if (Irp == NULL)
+        /* Process all LUNs from the list*/
+        while (TRUE)
+        {
+            /* Remove it from the list first (as processed) */
+            LunExtension = InterruptData.ReadyLun;
+            InterruptData.ReadyLun = LunExtension->ReadyLun;
+            LunExtension->ReadyLun = NULL;
+
+            /* Get next request for this LUN */
+            SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
+
+            /* Still ready requests exist?
+               If yes - get spinlock, if no - stop here */
+            if (InterruptData.ReadyLun != NULL)
+                KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+            else
+                break;
+        }
+    }
+    else
     {
-      DPRINT("IoBuildDeviceIoControlRequest() failed\n");
-      return STATUS_INSUFFICIENT_RESOURCES;
+        /* Release the spinlock */
+        KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
     }
 
-  /* Attach Srb to the Irp */
-  IrpStack = IoGetNextIrpStackLocation (Irp);
-  IrpStack->Parameters.Scsi.Srb = Srb;
-  Srb->OriginalRequest = Irp;
+    /* If we ready for next packet, start it */
+    if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
+        IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
 
-  /* Call the driver */
-  Status = IoCallDriver (DeviceObject,
-                        Irp);
+    NeedToStartIo = FALSE;
 
-  return Status;
-}
+    /* Loop the completed request list */
+    while (InterruptData.CompletedRequests)
+    {
+        /* Remove the request */
+        SrbInfo = InterruptData.CompletedRequests;
+        InterruptData.CompletedRequests = SrbInfo->CompletedRequests;
+        SrbInfo->CompletedRequests = NULL;
+
+        /* Process it */
+        SpiProcessCompletedRequest(DeviceExtension,
+                                  SrbInfo,
+                                  &NeedToStartIo);
+    }
 
-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;
+    /* Loop abort request list */
+    while (InterruptData.CompletedAbort)
+    {
+        LunExtension = InterruptData.CompletedAbort;
 
-  DPRINT ("SpiScanAdapter() called\n");
+        /* Remove the request */
+        InterruptData.CompletedAbort = LunExtension->CompletedAbortRequests;
 
-  MaxCount = DeviceExtension->PortConfig->NumberOfBuses *
-               DeviceExtension->PortConfig->MaximumNumberOfTargets;
+        /* Get spinlock since we're going to change flags */
+        KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
 
-  ScanDataArray = ExAllocatePool(NonPagedPool, MaxCount * (sizeof(SCSI_PORT_SCAN_ADAPTER) + sizeof(PVOID) + sizeof(KWAIT_BLOCK)));
-  if (ScanDataArray == NULL)
-    {
-      return;
+        /* TODO: Put SrbExtension to the list of free extensions */
+        ASSERT(FALSE);
     }
-  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++)
+    /* If we need - call StartIo routine */
+    if (NeedToStartIo)
     {
-      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;
-       }
+        /* Make sure CurrentIrp is not null! */
+        ASSERT(DpcDeviceObject->CurrentIrp != NULL);
+        ScsiPortStartIo(DpcDeviceObject, DpcDeviceObject->CurrentIrp);
     }
-  do
+
+    /* Everything has been done, check */
+    if (InterruptData.Flags & SCSI_PORT_ENABLE_INT_REQUEST)
     {
-      ActiveCount = 0;
-      WaitCount = 0;
-      for (i = 0; i < MaxCount; i++)
-        {
-          ScanData = &ScanDataArray[i];
-         Srb = &ScanData->Srb;
-          if (ScanData->Active)
-            {
-             if (ScanData->Status == STATUS_PENDING &&
-                 0 == KeReadStateEvent(&ScanData->Event))
-               {
-                 ActiveCount++;
-                 continue;
-               }
-             else
-               {
-                  ScanData->Status = ScanData->IoStatusBlock.Status;
-               }
-             ScanData->Active = FALSE;
-             DPRINT ("Target %lu  Lun %lu\n", ScanData->Target, ScanData->Lun);
-             DPRINT ("Status %lx  Srb.SrbStatus %x\n", ScanData->Status, Srb->SrbStatus);
-             DPRINT ("DeviceTypeQualifier %x\n", ((PINQUIRYDATA)Srb->DataBuffer)->DeviceTypeQualifier);
-
-             if (NT_SUCCESS(ScanData->Status) &&
-                 (Srb->SrbStatus == SRB_STATUS_SUCCESS ||
-                  (Srb->SrbStatus == SRB_STATUS_DATA_OVERRUN &&
-                  /*
-                   * FIXME:
-                   *   The NT 4.0 driver from an inic950 based scsi controller
-                   *   returns only 4 byte of inquiry data, but the device name
-                   *   is visible on NT 4.0. We must implement an other way
-                   *   to get the complete inquiry data.
-                   */
-                   Srb->DataTransferLength >= /*INQUIRYDATABUFFERSIZE*/4)) &&
-                 ((PINQUIRYDATA)Srb->DataBuffer)->DeviceTypeQualifier == 0)
-               {
-                 /* Copy inquiry data */
-                 RtlCopyMemory (&ScanData->LunExtension->InquiryData,
-                                Srb->DataBuffer,
-                                min(sizeof(INQUIRYDATA), Srb->DataTransferLength));
-                 ScanData->Lun++;
-               }
-             else
-               {
-                 SpiRemoveLunExtension (ScanData->LunExtension);
-                 ScanData->Lun = SCSI_MAXIMUM_LOGICAL_UNITS;
-               }
-           }
-          if (ScanData->Lun >= SCSI_MAXIMUM_LOGICAL_UNITS)
-            {
-             continue;
-           }
-          RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
-          Srb->SrbFlags = SRB_FLAGS_DATA_IN;
-          Srb->DataBuffer = ScanData->DataBuffer;
-          Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
-          Srb->DataTransferLength = 255; //256;
-          Srb->CdbLength = 6;
-          Srb->Lun = ScanData->Lun;
-          Srb->PathId = ScanData->Bus;
-          Srb->TargetId = ScanData->Target;
-          Srb->SrbStatus = SRB_STATUS_SUCCESS;
-         Srb->TimeOutValue = 2;
-          Cdb = (PCDB) &Srb->Cdb;
-
-          Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
-          Cdb->CDB6INQUIRY.AllocationLength = 255;
-          Cdb->CDB6INQUIRY.LogicalUnitNumber = ScanData->Lun;
-
-          RtlZeroMemory(Srb->DataBuffer, 256);
-
-          ScanData->LunExtension = SpiAllocateLunExtension (DeviceExtension,
-                                                           ScanData->Bus,
-                                                           ScanData->Target,
-                                                           ScanData->Lun);
-          if (ScanData->LunExtension == NULL)
-           {
-             DPRINT1("Failed to allocate the LUN extension!\n");
-             ScanData->Lun = SCSI_MAXIMUM_LOGICAL_UNITS;
-             continue;
-           }
-          ScanData->Status = SpiSendInquiry (DeviceExtension->DeviceObject,
-                                            Srb,
-                                            &ScanData->IoStatusBlock,
-                                            &ScanData->Event);
-         ScanData->Active = TRUE;
-         ActiveCount++;
-         if (ScanData->Status == STATUS_PENDING)
-           {
-              EventArray[WaitCount] = &ScanData->Event;
-              WaitCount++;
-            }
-       }
-      if (WaitCount > 0 && WaitCount == ActiveCount)
-        {
-          KeWaitForMultipleObjects(WaitCount,
-                                   EventArray,
-                                  WaitAny,
-                                  Executive,
-                                  KernelMode,
-                                  FALSE,
-                                  NULL,
-                                  WaitBlockArray);
-       }
-    }
-  while (ActiveCount > 0);
+        /* Synchronize using spinlock */
+        KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
 
-  ExFreePool(ScanDataArray);
+        /* Request an interrupt */
+        DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension);
 
-  DPRINT ("SpiScanAdapter() done\n");
-}
+        ASSERT(DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET);
 
+        /* Should interrupts be enabled again? */
+        if (DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET)
+        {
+            /* Clear this flag */
+            DeviceExtension->Flags &= ~SCSI_PORT_DISABLE_INT_REQUESET;
 
-static ULONG
-SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                 OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo)
-{
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
-  ULONG Bus;
-  ULONG Target;
-  ULONG Lun;
-  ULONG UnitCount;
+            /* Call a special routine to do this */
+            ASSERT(FALSE);
+#if 0
+            KeSynchronizeExecution(DeviceExtension->Interrupt,
+                                   SpiEnableInterrupts,
+                                   DeviceExtension);
+#endif
+        }
 
-  DPRINT("SpiGetInquiryData() called\n");
+        /* If we need a notification again - loop */
+        if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
+            goto TryAgain;
 
-  /* Copy inquiry data to the port device extension */
-  AdapterBusInfo->NumberOfBuses = DeviceExtension->PortConfig->NumberOfBuses;
+        /* Release the spinlock */
+        KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+    }
 
-  UnitInfo = (PSCSI_INQUIRY_DATA)
-       ((PUCHAR)AdapterBusInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
-        (sizeof(SCSI_BUS_DATA) * (AdapterBusInfo->NumberOfBuses - 1)));
+    DPRINT("ScsiPortDpcForIsr() done\n");
+}
 
-  for (Bus = 0; Bus < AdapterBusInfo->NumberOfBuses; Bus++)
-    {
-      AdapterBusInfo->BusData[Bus].InitiatorBusId =
-       DeviceExtension->PortConfig->InitiatorBusId[Bus];
-      AdapterBusInfo->BusData[Bus].InquiryDataOffset =
-       (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterBusInfo);
+BOOLEAN
+NTAPI
+SpiProcessTimeout(PVOID ServiceContext)
+{
+    PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+    ULONG Bus;
 
-      PrevUnit = NULL;
-      UnitCount = 0;
+    DPRINT("SpiProcessTimeout() entered\n");
 
-      for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
-       {
-         for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
-           {
-             LunExtension = SpiGetLunExtension(DeviceExtension,
-                                               Bus,
-                                               Target,
-                                               Lun);
-             if (LunExtension != NULL)
-               {
-                 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
-                        Bus, Target, Lun);
-          RtlZeroMemory(UnitInfo, sizeof(*UnitInfo));
-                 UnitInfo->PathId = Bus;
-                 UnitInfo->TargetId = Target;
-                 UnitInfo->Lun = Lun;
-                 UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
-                 RtlCopyMemory (&UnitInfo->InquiryData,
-                                &LunExtension->InquiryData,
-                                INQUIRYDATABUFFERSIZE);
-                 if (PrevUnit != NULL)
-                   {
-                     PrevUnit->NextInquiryDataOffset =
-                       (ULONG)((ULONG_PTR)UnitInfo-(ULONG_PTR)AdapterBusInfo);
-                   }
-                 PrevUnit = UnitInfo;
-                 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
-                 UnitCount++;
-               }
-           }
-       }
-      DPRINT("UnitCount: %lu\n", UnitCount);
-      AdapterBusInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
-      if (UnitCount == 0)
-       {
-         AdapterBusInfo->BusData[Bus].InquiryDataOffset = 0;
-       }
-    }
+    DeviceExtension->TimerCount = -1;
 
-  DPRINT("Data size: %lu\n", (ULONG)UnitInfo - (ULONG)AdapterBusInfo);
+    if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
+    {
+        DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET;
 
-  return (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterBusInfo);
-}
+        if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST)
+        {
+            DeviceExtension->InterruptData.Flags &=  ~SCSI_PORT_RESET_REQUEST;
+            ScsiPortStartPacket(ServiceContext);
+        }
 
+        return FALSE;
+    }
+    else
+    {
+        DPRINT("Resetting the bus\n");
 
-static BOOLEAN STDCALL
-ScsiPortIsr(IN PKINTERRUPT Interrupt,
-           IN PVOID ServiceContext)
-{
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+        for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
+        {
+            DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus);
 
-  DPRINT("ScsiPortIsr() called!\n");
+            /* Reset flags and set reset timeout to 4 seconds */
+            DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
+            DeviceExtension->TimerCount = 4;
+        }
 
-  DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
+        /* If miniport requested - request a dpc for it */
+        if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
+            IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
+    }
 
-  return DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
+    return TRUE;
 }
 
 
-//    ScsiPortDpc
-//  DESCRIPTION:
-//
-//  RUN LEVEL:
-//
-//  ARGUMENTS:
-//    IN PKDPC          Dpc
-//    IN PDEVICE_OBJECT DpcDeviceObject
-//    IN PIRP           DpcIrp
-//    IN PVOID          DpcContext
-//
-static VOID STDCALL
-ScsiPortDpc(IN PKDPC Dpc,
-           IN PDEVICE_OBJECT DpcDeviceObject,
-           IN PIRP DpcIrp,
-           IN PVOID DpcContext)
+BOOLEAN
+NTAPI
+SpiResetBus(PVOID ServiceContext)
 {
-  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
 
-  DPRINT("ScsiPortDpc(Dpc %p  DpcDeviceObject %p  DpcIrp %p  DpcContext %p)\n",
-        Dpc, DpcDeviceObject, DpcIrp, DpcContext);
+    /* Perform the bus reset */
+    DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension;
+    DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension,
+                                ResetParams->PathId);
 
-  DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
+    /* Set flags and start the timer */
+    DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
+    DeviceExtension->TimerCount = 4;
 
-  SpiProcessRequests(DeviceExtension, NULL);
+    /* If miniport requested - give him a DPC */
+    if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
+        IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
 
-  DPRINT("ScsiPortDpc() done\n");
+    return TRUE;
 }
 
-
 //    ScsiPortIoTimer
 //  DESCRIPTION:
 //    This function handles timeouts and other time delayed processing
@@ -2417,55 +5041,104 @@ ScsiPortDpc(IN PKDPC Dpc,
 //    IN  PVOID           Context       the Controller extension for the
 //                                      controller the device is on
 //
-static VOID STDCALL
+static VOID NTAPI
 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
-               PVOID Context)
+                PVOID Context)
 {
-  DPRINT1("ScsiPortIoTimer()\n");
-}
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+    ULONG Lun;
+    PIRP Irp;
 
+    DPRINT("ScsiPortIoTimer()\n");
 
-static PSCSI_REQUEST_BLOCK
-ScsiPortInitSenseRequestSrb(PSCSI_REQUEST_BLOCK OriginalSrb)
-{
-  PSCSI_REQUEST_BLOCK Srb;
-  ULONG Length;
-  PCDB Cdb;
+    DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
 
-  Length = sizeof(SCSI_REQUEST_BLOCK) + sizeof(SENSE_DATA) + 32;
-  Srb = ExAllocatePoolWithTag(NonPagedPool,
-                              Length,
-                             TAG('S', 'S', 'r', 'b'));
-  if (Srb == NULL)
+    /* Protect with the spinlock */
+    KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+    /* Check timeouts */
+    if (DeviceExtension->TimerCount > 0)
     {
-      return NULL;
+        /* Decrease the timeout counter */
+        DeviceExtension->TimerCount--;
+
+        if (DeviceExtension->TimerCount == 0)
+        {
+            /* Timeout, process it */
+            if (KeSynchronizeExecution(DeviceExtension->Interrupt,
+                                       SpiProcessTimeout,
+                                       DeviceExtension->DeviceObject))
+            {
+                DPRINT("Error happened during processing timeout, but nothing critical\n");
+            }
+        }
+
+        KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+        /* We should exit now, since timeout is processed */
+        return;
     }
 
-  RtlZeroMemory(Srb, Length);
+    /* Per-Lun scanning of timeouts is needed... */
+    for (Lun = 0; Lun < LUS_NUMBER; Lun++)
+    {
+        LunExtension = DeviceExtension->LunExtensionList[Lun];
+
+        while (LunExtension)
+        {
+            if (LunExtension->Flags & LUNEX_BUSY)
+            {
+                if (!(LunExtension->Flags &
+                    (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE)))
+                {
+                    DPRINT("Retrying busy request\n");
 
-  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;
+                    /* Clear flags, and retry busy request */
+                    LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE);
+                    Irp = LunExtension->BusyRequest;
 
-  Srb->TimeOutValue = 4;
+                    /* Clearing busy request */
+                    LunExtension->BusyRequest = NULL;
 
-  Srb->CdbLength = 6;
-  /* 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);
+                    KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+                    IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
+
+                    KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+                }
+            }
+            else if (LunExtension->RequestTimeout == 0)
+            {
+                RESETBUS_PARAMS ResetParams;
 
-  Cdb = (PCDB)Srb->Cdb;
-  Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
-  Cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
+                LunExtension->RequestTimeout = -1;
 
-  return(Srb);
+                DPRINT("Request timed out, resetting bus\n");
+
+                /* Pass params to the bus reset routine */
+                ResetParams.PathId = LunExtension->PathId;
+                ResetParams.DeviceExtension = DeviceExtension;
+
+                if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
+                                            SpiResetBus,
+                                            &ResetParams))
+                {
+                    DPRINT1("Reset failed\n");
+                }
+            }
+            else if (LunExtension->RequestTimeout > 0)
+            {
+                /* Decrement the timeout counter */
+                LunExtension->RequestTimeout--;
+            }
+
+            LunExtension = LunExtension->Next;
+        }
+    }
+
+    /* Release the spinlock */
+    KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
 }
 
 /**********************************************************************
@@ -2497,8 +5170,7 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
 {
   PSCSI_PORT_LUN_EXTENSION LunExtension;
   OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING KeyName =
-    RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
+  UNICODE_STRING KeyName;
   UNICODE_STRING ValueName;
   WCHAR NameBuffer[64];
   ULONG Disposition;
@@ -2526,6 +5198,8 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
     }
 
   /* Open or create the 'Scsi' subkey */
+  RtlInitUnicodeString(&KeyName,
+                         L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
   InitializeObjectAttributes(&ObjectAttributes,
                             &KeyName,
                             OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
@@ -2577,7 +5251,7 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
    */
 
   /* Set 'DMA Enabled' (REG_DWORD) value */
-  UlongData = (ULONG)!DeviceExtension->PortCapabilities->AdapterUsesPio;
+  UlongData = (ULONG)!DeviceExtension->PortCapabilities.AdapterUsesPio;
   DPRINT("  DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE");
   RtlInitUnicodeString(&ValueName,
                       L"DMA Enabled");
@@ -2715,9 +5389,9 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
          for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
            {
              LunExtension = SpiGetLunExtension(DeviceExtension,
-                                               BusNumber,
-                                               Target,
-                                               Lun);
+                                               (UCHAR)BusNumber,
+                                               (UCHAR)Target,
+                                               (UCHAR)Lun);
              if (LunExtension != NULL)
                {
                  if (Target != CurrentTarget)
@@ -2890,393 +5564,689 @@ ByeBye:
   return Status;
 }
 
-static VOID
-SpiRemoveActiveIrp(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                  PIRP Irp,
-                  PIRP PrevIrp)
+VOID
+NTAPI
+SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
+                    IN PVOID DeviceObject,
+                    IN PVOID SystemArgument1,
+                    IN PVOID SystemArgument2)
 {
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  PIRP CurrentIrp;
-  LunExtension = Irp->Tail.Overlay.DriverContext[2];
-  InterlockedDecrement((PLONG)&LunExtension->ActiveIrpCount);
-  InterlockedDecrement((PLONG)&DeviceExtension->ActiveIrpCount);
-  if (PrevIrp)
+    DPRINT1("Miniport timer DPC\n");
+    ASSERT(FALSE);
+}
+
+static NTSTATUS
+SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                    PHW_INITIALIZATION_DATA HwInitData,
+                    PCONFIGURATION_INFO InternalConfigInfo,
+                    PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+                    BOOLEAN ZeroStruct)
+{
+    UNICODE_STRING UnicodeString;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    PCONFIGURATION_INFORMATION DdkConfigInformation;
+    HANDLE RootKey, Key;
+    BOOLEAN Found;
+    WCHAR DeviceBuffer[16];
+    WCHAR StrBuffer[512];
+    ULONG Bus;
+    NTSTATUS Status;
+
+    /* Zero out the struct if told so */
+    if (ZeroStruct)
+    {
+        /* First zero the portconfig */
+        RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
+
+        /* Then access ranges */
+        RtlZeroMemory(InternalConfigInfo->AccessRanges,
+                      HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
+
+        /* Initialize the struct */
+        ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
+        ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
+        ConfigInfo->InterruptMode = Latched;
+        ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
+        ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
+        ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
+        ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
+        ConfigInfo->MaximumNumberOfTargets = 8;
+
+        /* Store parameters */
+        ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
+        ConfigInfo->MapBuffers = HwInitData->MapBuffers;
+        ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense;
+        ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent;
+        ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing;
+        ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
+
+        /* Get the disk usage */
+        DdkConfigInformation = IoGetConfigurationInformation();
+        ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed;
+        ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed;
+
+        /* Initiator bus id is not set */
+        for (Bus = 0; Bus < 8; Bus++)
+            ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE;
+    }
+
+    ConfigInfo->NumberOfPhysicalBreaks = 17;
+
+    /* Clear this information */
+    InternalConfigInfo->DisableTaggedQueueing = FALSE;
+    InternalConfigInfo->DisableMultipleLun = FALSE;
+
+    /* Store Bus Number */
+    ConfigInfo->SystemIoBusNumber = InternalConfigInfo->BusNumber;
+
+TryNextAd:
+
+    if (ConfigInfo->AdapterInterfaceType == Internal)
+    {
+        /* Open registry key for HW database */
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
+                                   OBJ_CASE_INSENSITIVE,
+                                   NULL,
+                                   NULL);
+
+        Status = ZwOpenKey(&RootKey,
+                           KEY_READ,
+                           &ObjectAttributes);
+
+        if (NT_SUCCESS(Status))
+        {
+            /* Create name for it */
+            swprintf(StrBuffer, L"ScsiAdapter\\%lu",
+                InternalConfigInfo->AdapterNumber);
+
+            RtlInitUnicodeString(&UnicodeString, StrBuffer);
+
+            /* Open device key */
+            InitializeObjectAttributes(&ObjectAttributes,
+                                       &UnicodeString,
+                                       OBJ_CASE_INSENSITIVE,
+                                       RootKey,
+                                       NULL);
+
+            Status = ZwOpenKey(&Key,
+                               KEY_READ,
+                               &ObjectAttributes);
+
+            ZwClose(RootKey);
+
+            if (NT_SUCCESS(Status))
+            {
+                if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
+                {
+                    DPRINT("Hardware info found at %S\n", StrBuffer);
+
+                    /* Parse it */
+                    SpiParseDeviceInfo(DeviceExtension,
+                                       Key,
+                                       ConfigInfo,
+                                       InternalConfigInfo,
+                                       (PUCHAR)StrBuffer);
+
+                     InternalConfigInfo->BusNumber = 0;
+                }
+                else
+                {
+                    /* Try the next adapter */
+                    InternalConfigInfo->AdapterNumber++;
+                    goto TryNextAd;
+                }
+            }
+            else
+            {
+                /* Info was not found, exit */
+                DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
+                return STATUS_DEVICE_DOES_NOT_EXIST;
+            }
+        }
+        else
+        {
+            DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
+        }
+    }
+
+    /* Look at device params */
+    Key = NULL;
+    if (InternalConfigInfo->Parameter)
     {
-      InterlockedExchangePointer(&PrevIrp->Tail.Overlay.DriverContext[0],
-                                Irp->Tail.Overlay.DriverContext[0]);
+        ExFreePool(InternalConfigInfo->Parameter);
+        InternalConfigInfo->Parameter = NULL;
     }
-  else
+
+    if (InternalConfigInfo->ServiceKey != NULL)
     {
-      InterlockedExchangePointer(&DeviceExtension->NextIrp,
-                                Irp->Tail.Overlay.DriverContext[0]);
+        swprintf(DeviceBuffer, L"Device%lu", InternalConfigInfo->AdapterNumber);
+        RtlInitUnicodeString(&UnicodeString, DeviceBuffer);
+
+        /* Open the service key */
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &UnicodeString,
+                                   OBJ_CASE_INSENSITIVE,
+                                   InternalConfigInfo->ServiceKey,
+                                   NULL);
+
+        Status = ZwOpenKey(&Key,
+                           KEY_READ,
+                           &ObjectAttributes);
     }
-  if (LunExtension->NextIrp == Irp)
+
+    /* Parse device key */
+    if (InternalConfigInfo->DeviceKey != NULL)
     {
-      InterlockedExchangePointer(&LunExtension->NextIrp,
-                                Irp->Tail.Overlay.DriverContext[1]);
-      return;
+        SpiParseDeviceInfo(DeviceExtension,
+                           InternalConfigInfo->DeviceKey,
+                           ConfigInfo,
+                           InternalConfigInfo,
+                           (PUCHAR)StrBuffer);
     }
-  else
+
+    /* Then parse hw info */
+    if (Key != NULL)
     {
-      CurrentIrp = LunExtension->NextIrp;
-      while (CurrentIrp)
+        if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
         {
-         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);
+            SpiParseDeviceInfo(DeviceExtension,
+                               Key,
+                               ConfigInfo,
+                               InternalConfigInfo,
+                               (PUCHAR)StrBuffer);
+
+            /* Close the key */
+            ZwClose(Key);
+        }
+        else
+        {
+            /* Adapter not found, go try the next one */
+            InternalConfigInfo->AdapterNumber++;
+
+            /* Close the key */
+            ZwClose(Key);
+
+            goto TryNextAd;
+        }
     }
-}
 
-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);
+    /* Update the last adapter number */
+    InternalConfigInfo->LastAdapterNumber = InternalConfigInfo->AdapterNumber;
+
+    /* Do we have this kind of bus at all? */
+    Found = FALSE;
+    Status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType,
+                                      &InternalConfigInfo->BusNumber,
+                                      NULL,
+                                      NULL,
+                                      NULL,
+                                      NULL,
+                                      SpQueryDeviceCallout,
+                                      &Found);
+
+    /* This bus was not found */
+    if (!Found)
+    {
+        INTERFACE_TYPE InterfaceType = Eisa;
+
+        /* Check for EISA */
+        if (HwInitData->AdapterInterfaceType == Isa)
+        {
+            Status = IoQueryDeviceDescription(&InterfaceType,
+                                              &InternalConfigInfo->BusNumber,
+                                              NULL,
+                                              NULL,
+                                              NULL,
+                                              NULL,
+                                              SpQueryDeviceCallout,
+                                              &Found);
+
+            /* Return respectively */
+            if (Found)
+                return STATUS_SUCCESS;
+            else
+                return STATUS_DEVICE_DOES_NOT_EXIST;
+        }
+        else
+        {
+            return STATUS_DEVICE_DOES_NOT_EXIST;
+        }
+    }
+    else
+    {
+        return STATUS_SUCCESS;
+    }
 }
 
 static VOID
-SpiProcessRequests(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                  IN PIRP NextIrp)
+SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+                   IN HANDLE Key,
+                   IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+                   IN PCONFIGURATION_INFO InternalConfigInfo,
+                   IN PUCHAR Buffer)
 {
-  /*
-   * 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");
+    PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
+    PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
+    PCM_SCSI_DEVICE_DATA ScsiDeviceData;
+    ULONG Length, Count;
+    ULONG Index = 0, RangeCount = 0;
+    UNICODE_STRING UnicodeString;
+    ANSI_STRING AnsiString;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer;
+
+    /* Loop through all values in the device node */
+    while(TRUE)
+    {
+        Status = ZwEnumerateValueKey(Key,
+                                     Index,
+                                     KeyValueFullInformation,
+                                     Buffer,
+                                     512,
+                                     &Length);
 
-  InitializeListHead(&NextIrpListHead);
-  InitializeListHead(&CompleteIrpListHead);
+        if (!NT_SUCCESS(Status))
+            return;
 
-  KeAcquireSpinLock(&DeviceExtension->Lock, &oldIrql);
+        Index++;
 
-  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;
+        /* Length for DWORD is ok? */
+        if (KeyValueInformation->Type == REG_DWORD &&
+            KeyValueInformation->DataLength != sizeof(ULONG))
+        {
+            continue;
+        }
 
-      ListEntry = DeviceExtension->PendingIrpListHead.Flink;
-      while (ListEntry != &DeviceExtension->PendingIrpListHead)
+        /* Get MaximumLogicalUnit */
+        if (_wcsnicmp(KeyValueInformation->Name, L"MaximumLogicalUnit",
+            KeyValueInformation->NameLength/2) == 0)
         {
-          Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
-          if ((ULONG)Irp->Tail.Overlay.DriverContext[2] > Srb->QueueSortKey)
+
+            if (KeyValueInformation->Type != REG_DWORD)
             {
-              break;
-           }
-          ListEntry = ListEntry->Flink;
-       }
-      InsertTailList(ListEntry, (PLIST_ENTRY)&NextIrp->Tail.Overlay.DriverContext[0]);
-      DeviceExtension->PendingIrpCount++;
-      LunExtension->PendingIrpCount++;
-    }
+                DPRINT("Bad data type for MaximumLogicalUnit\n");
+                continue;
+            }
 
-  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);
+            DeviceExtension->MaxLunCount = *((PUCHAR)
+                (Buffer + KeyValueInformation->DataOffset));
 
+            /* Check / reset if needed */
+            if (DeviceExtension->MaxLunCount > SCSI_MAXIMUM_LOGICAL_UNITS)
+                DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
+
+            DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension->MaxLunCount);
+        }
 
-      if (DeviceExtension->Flags & IRP_FLAG_COMPLETE)
+        /* Get InitiatorTargetId */
+        if (_wcsnicmp(KeyValueInformation->Name, L"InitiatorTargetId",
+            KeyValueInformation->NameLength / 2) == 0)
         {
-         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);
+            if (KeyValueInformation->Type != REG_DWORD)
+            {
+                DPRINT("Bad data type for InitiatorTargetId\n");
+                continue;
+            }
+
+            ConfigInfo->InitiatorBusId[0] = *((PUCHAR)
+                (Buffer + KeyValueInformation->DataOffset));
 
-                      Srb->OriginalRequest = LunExtension;
-                      Irp->Tail.Overlay.DriverContext[2] = 0;
+            /* Check / reset if needed */
+            if (ConfigInfo->InitiatorBusId[0] > ConfigInfo->MaximumNumberOfTargets - 1)
+                ConfigInfo->InitiatorBusId[0] = (CCHAR)-1;
 
-                     InsertHeadList(&DeviceExtension->PendingIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
-                     DeviceExtension->PendingIrpCount++;
-                     LunExtension->PendingIrpCount++;
-                     Irp = NextIrp;
-                     continue;
-                   }
+            DPRINT("InitiatorTargetId = %d\n", ConfigInfo->InitiatorBusId[0]);
+        }
+
+        /* Get ScsiDebug */
+        if (_wcsnicmp(KeyValueInformation->Name, L"ScsiDebug",
+            KeyValueInformation->NameLength/2) == 0)
+        {
+            DPRINT("ScsiDebug key not supported\n");
+        }
 
-                  if (OriginalSrb != Srb)
-                   {
-                     SENSE_DATA* SenseInfoBuffer;
+        /* Check for a breakpoint */
+        if (_wcsnicmp(KeyValueInformation->Name, L"BreakPointOnEntry",
+            KeyValueInformation->NameLength/2) == 0)
+        {
+            DPRINT1("Breakpoint on entry requested!\n");
+            DbgBreakPoint();
+        }
 
-                     SenseInfoBuffer = Srb->DataBuffer;
+        /* Get DisableSynchronousTransfers */
+        if (_wcsnicmp(KeyValueInformation->Name, L"DisableSynchronousTransfers",
+            KeyValueInformation->NameLength/2) == 0)
+        {
+            DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+            DPRINT("Synch transfers disabled\n");
+        }
 
-                     DPRINT("Got sense data!\n");
+        /* Get DisableDisconnects */
+        if (_wcsnicmp(KeyValueInformation->Name, L"DisableDisconnects",
+            KeyValueInformation->NameLength/2) == 0)
+        {
+            DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
+            DPRINT("Disconnects disabled\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);
+        /* Get DisableTaggedQueuing */
+        if (_wcsnicmp(KeyValueInformation->Name, L"DisableTaggedQueuing",
+            KeyValueInformation->NameLength/2) == 0)
+        {
+            InternalConfigInfo->DisableTaggedQueueing = TRUE;
+            DPRINT("Tagged queueing disabled\n");
+        }
 
-                     /* 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))
+        /* Get DisableMultipleRequests */
+        if (_wcsnicmp(KeyValueInformation->Name, L"DisableMultipleRequests",
+            KeyValueInformation->NameLength/2) == 0)
         {
-          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);
+            InternalConfigInfo->DisableMultipleLun = TRUE;
+            DPRINT("Multiple requests disabled\n");
         }
-      if (DeviceExtension->Flags & (IRP_FLAG_NEXT|IRP_FLAG_NEXT_LU) &&
-          (DeviceExtension->SrbExtensionSize == 0 || DeviceExtension->CurrentSrbExtensions < DeviceExtension->MaxSrbExtensions))
+
+        /* Get DriverParameters */
+        if (_wcsnicmp(KeyValueInformation->Name, L"DriverParameters",
+            KeyValueInformation->NameLength/2) == 0)
         {
-         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)
+            /* Skip if nothing */
+            if (KeyValueInformation->DataLength == 0)
+                continue;
+
+            /* If there was something previously allocated - free it */
+            if (InternalConfigInfo->Parameter != NULL)
+                ExFreePool(InternalConfigInfo->Parameter);
+
+            /* Allocate it */
+            InternalConfigInfo->Parameter = ExAllocatePoolWithTag(NonPagedPool,
+                                                           KeyValueInformation->DataLength, TAG_SCSIPORT);
+
+            if (InternalConfigInfo->Parameter != NULL)
+            {
+                if (KeyValueInformation->Type != REG_SZ)
                 {
-                 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]);
-               }
-           }
-       }
+                    /* Just copy */
+                    RtlCopyMemory(
+                        InternalConfigInfo->Parameter,
+                        (PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
+                        KeyValueInformation->DataLength);
+                }
+                else
+                {
+                    /* If it's a unicode string, convert it to ansi */
+                    UnicodeString.Length = (USHORT)KeyValueInformation->DataLength;
+                    UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
+                    UnicodeString.Buffer =
+                        (PWSTR)((PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
+
+                    AnsiString.Length = 0;
+                    AnsiString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
+                    AnsiString.Buffer = (PCHAR)InternalConfigInfo->Parameter;
+
+                    Status = RtlUnicodeStringToAnsiString(&AnsiString,
+                                                          &UnicodeString,
+                                                          FALSE);
+
+                    /* In case of error, free the allocated space */
+                    if (!NT_SUCCESS(Status))
+                    {
+                        ExFreePool(InternalConfigInfo->Parameter);
+                        InternalConfigInfo->Parameter = NULL;
+                    }
+
+                }
+            }
 
-      if (!IsListEmpty(&NextIrpListHead))
+            DPRINT("Found driver parameter\n");
+        }
+
+        /* Get MaximumSGList */
+        if (_wcsnicmp(KeyValueInformation->Name, L"MaximumSGList",
+            KeyValueInformation->NameLength/2) == 0)
         {
-         while (!IsListEmpty(&NextIrpListHead))
-           {
-             ListEntry = RemoveTailList(&NextIrpListHead);
-             Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
-             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->Lock);
+            if (KeyValueInformation->Type != REG_DWORD)
+            {
+                DPRINT("Bad data type for MaximumSGList\n");
+                continue;
+            }
 
-             // Start this Irp
-             SpiStartIo(DeviceExtension, Irp);
-             KeAcquireSpinLockAtDpcLevel(&DeviceExtension->Lock);
-           }
-       }
+            ConfigInfo->NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
+
+            /* Check / fix */
+            if (ConfigInfo->NumberOfPhysicalBreaks > SCSI_MAXIMUM_PHYSICAL_BREAKS)
+            {
+                ConfigInfo->NumberOfPhysicalBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS;
+            }
+            else if (ConfigInfo->NumberOfPhysicalBreaks < SCSI_MINIMUM_PHYSICAL_BREAKS)
+            {
+                ConfigInfo->NumberOfPhysicalBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS;
+            }
 
-      if (!IsListEmpty(&DeviceExtension->PendingIrpListHead) &&
-         DeviceExtension->NextIrp == NULL &&
-         (DeviceExtension->SrbExtensionSize == 0 || DeviceExtension->CurrentSrbExtensions < DeviceExtension->MaxSrbExtensions))
+            DPRINT("MaximumSGList = %d\n", ConfigInfo->NumberOfPhysicalBreaks);
+        }
+
+        /* Get NumberOfRequests */
+        if (_wcsnicmp(KeyValueInformation->Name, L"NumberOfRequests",
+            KeyValueInformation->NameLength/2) == 0)
         {
-         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;
+            if (KeyValueInformation->Type != REG_DWORD)
+            {
+                DPRINT("NumberOfRequests has wrong data type\n");
+                continue;
+            }
 
-         LunExtension->PendingIrpCount--;
-         DeviceExtension->PendingIrpCount--;
-          Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
-         LunExtension->ActiveIrpCount++;
-          DeviceExtension->ActiveIrpCount++;
+            DeviceExtension->RequestsNumber = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
 
-         SpiAllocateSrbExtension(DeviceExtension, Srb);
-          KeReleaseSpinLockFromDpcLevel(&DeviceExtension->Lock);
+            /* Check / fix */
+            if (DeviceExtension->RequestsNumber < 16)
+            {
+                DeviceExtension->RequestsNumber = 16;
+            }
+            else if (DeviceExtension->RequestsNumber > 512)
+            {
+                DeviceExtension->RequestsNumber = 512;
+            }
 
-          /* Start this irp */
-          SpiStartIo(DeviceExtension, Irp);
-         KeAcquireSpinLockAtDpcLevel(&DeviceExtension->Lock);
+            DPRINT("Number Of Requests = %d\n", DeviceExtension->RequestsNumber);
         }
-     }
-   KeReleaseSpinLock(&DeviceExtension->Lock, oldIrql);
 
-   DPRINT("SpiProcessRequests() done\n");
- }
+        /* Get resource list */
+        if (_wcsnicmp(KeyValueInformation->Name, L"ResourceList",
+                KeyValueInformation->NameLength/2) == 0 ||
+            _wcsnicmp(KeyValueInformation->Name, L"Configuration Data",
+                KeyValueInformation->NameLength/2) == 0 )
+        {
+            if (KeyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR ||
+                KeyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR))
+            {
+                DPRINT("Bad data type for ResourceList\n");
+                continue;
+            }
+            else
+            {
+                DPRINT("Found ResourceList\n");
+            }
 
-static VOID
-SpiStartIo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-          IN PIRP Irp)
+            FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)(Buffer + KeyValueInformation->DataOffset);
+
+            /* Copy some info from it */
+            InternalConfigInfo->BusNumber = FullResource->BusNumber;
+            ConfigInfo->SystemIoBusNumber = FullResource->BusNumber;
+
+            /* Loop through it */
+            for (Count = 0; Count < FullResource->PartialResourceList.Count; Count++)
+            {
+                /* Get partial descriptor */
+                PartialDescriptor =
+                    &FullResource->PartialResourceList.PartialDescriptors[Count];
+
+                /* Check datalength */
+                if ((ULONG)((PCHAR)(PartialDescriptor + 1) -
+                    (PCHAR)FullResource) > KeyValueInformation->DataLength)
+                {
+                    DPRINT("Resource data is of incorrect size\n");
+                    break;
+                }
+
+                switch (PartialDescriptor->Type)
+                {
+                case CmResourceTypePort:
+                    if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
+                    {
+                        DPRINT("Too many access ranges\n");
+                        continue;
+                    }
+
+                    InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = FALSE;
+                    InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Port.Start;
+                    InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Port.Length;
+                    RangeCount++;
+
+                    break;
+
+                case CmResourceTypeMemory:
+                    if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
+                    {
+                        DPRINT("Too many access ranges\n");
+                        continue;
+                    }
+
+                    InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = TRUE;
+                    InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Memory.Start;
+                    InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Memory.Length;
+                    RangeCount++;
+
+                    break;
+
+                case CmResourceTypeInterrupt:
+                    ConfigInfo->BusInterruptLevel =
+                        PartialDescriptor->u.Interrupt.Level;
+
+                    ConfigInfo->BusInterruptVector =
+                        PartialDescriptor->u.Interrupt.Vector;
+                    break;
+
+                case CmResourceTypeDma:
+                    ConfigInfo->DmaChannel = PartialDescriptor->u.Dma.Channel;
+                    ConfigInfo->DmaPort = PartialDescriptor->u.Dma.Port;
+                    break;
+
+                case CmResourceTypeDeviceSpecific:
+                    if (PartialDescriptor->u.DeviceSpecificData.DataSize <
+                        sizeof(CM_SCSI_DEVICE_DATA) ||
+                        (PCHAR) (PartialDescriptor + 1) - (PCHAR)FullResource +
+                        PartialDescriptor->u.DeviceSpecificData.DataSize >
+                        KeyValueInformation->DataLength)
+                    {
+                        DPRINT("Resource data length is incorrect");
+                        break;
+                    }
+
+                    /* Set only one field from it */
+                    ScsiDeviceData = (PCM_SCSI_DEVICE_DATA) (PartialDescriptor+1);
+                    ConfigInfo->InitiatorBusId[0] = ScsiDeviceData->HostIdentifier;
+                    break;
+                }
+            }
+        }
+    }
+}
+
+NTSTATUS
+NTAPI
+SpQueryDeviceCallout(IN PVOID  Context,
+                     IN PUNICODE_STRING  PathName,
+                     IN INTERFACE_TYPE  BusType,
+                     IN ULONG  BusNumber,
+                     IN PKEY_VALUE_FULL_INFORMATION  *BusInformation,
+                     IN CONFIGURATION_TYPE  ControllerType,
+                     IN ULONG  ControllerNumber,
+                     IN PKEY_VALUE_FULL_INFORMATION  *ControllerInformation,
+                     IN CONFIGURATION_TYPE  PeripheralType,
+                     IN ULONG  PeripheralNumber,
+                     IN PKEY_VALUE_FULL_INFORMATION  *PeripheralInformation)
 {
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  PSCSI_REQUEST_BLOCK Srb;
+    PBOOLEAN Found = (PBOOLEAN)Context;
+    /* We just set our Found variable to TRUE */
+
+    *Found = TRUE;
+    return STATUS_SUCCESS;
+}
+
+IO_ALLOCATION_ACTION
+NTAPI
+ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
+                               IN PIRP Irp,
+                               IN PVOID MapRegisterBase,
+                               IN PVOID Context)
+{
+    KIRQL Irql;
+    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
 
-  DPRINT("SpiStartIo() called!\n");
+    /* Guard access with the spinlock */
+    KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
 
-  assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+    /* Save MapRegisterBase we've got here */
+    DeviceExtension->MapRegisterBase = MapRegisterBase;
 
-  Srb = Irp->Tail.Overlay.DriverContext[3];
-  LunExtension = Irp->Tail.Overlay.DriverContext[2];
+    /* Start pending request */
+    KeSynchronizeExecution(DeviceExtension->Interrupt,
+        ScsiPortStartPacket, DeviceObject);
 
-  Irp->IoStatus.Status = STATUS_SUCCESS;
-  Irp->IoStatus.Information = Srb->DataTransferLength;
+    /* Release spinlock we took */
+    KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
 
-  SpiAddActiveIrp(DeviceExtension, Irp);
+    return KeepObject;
+}
 
-  if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
-                             ScsiPortStartPacket,
-                              Srb))
+static
+NTSTATUS
+SpiStatusSrbToNt(UCHAR SrbStatus)
+{
+    switch (SRB_STATUS(SrbStatus))
     {
-      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);
+    case SRB_STATUS_TIMEOUT:
+    case SRB_STATUS_COMMAND_TIMEOUT:
+        return STATUS_IO_TIMEOUT;
+
+    case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
+    case SRB_STATUS_BAD_FUNCTION:
+        return STATUS_INVALID_DEVICE_REQUEST;
+
+    case SRB_STATUS_NO_DEVICE:
+    case SRB_STATUS_INVALID_LUN:
+    case SRB_STATUS_INVALID_TARGET_ID:
+    case SRB_STATUS_NO_HBA:
+        return STATUS_DEVICE_DOES_NOT_EXIST;
+
+    case SRB_STATUS_DATA_OVERRUN:
+        return STATUS_BUFFER_OVERFLOW;
+
+    case SRB_STATUS_SELECTION_TIMEOUT:
+        return STATUS_DEVICE_NOT_CONNECTED;
+
+    default:
+        return STATUS_IO_DEVICE_ERROR;
     }
 
-  DPRINT("SpiStartIo() done\n");
+    return STATUS_IO_DEVICE_ERROR;
 }
 
 
+#undef ScsiPortConvertPhysicalAddressToUlong
+/*
+ * @implemented
+ */
+ULONG NTAPI
+ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
+{
+  DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
+  return(Address.u.LowPart);
+}
+
 
 /* EOF */