atapi, buslogic, cdrom, class2.
[reactos.git] / reactos / drivers / storage / atapi / atapi.c
index d1fe646..a004aa0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ReactOS kernel
- *  Copyright (C) 2001, 2002 ReactOS Team
+ *  Copyright (C) 2001, 2002, 2003, 2004, 2005 ReactOS Team
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: atapi.c,v 1.26 2002/07/18 00:30:22 ekohl Exp $
+/* $Id$
  *
  * COPYRIGHT:   See COPYING in the top level directory
  * PROJECT:     ReactOS ATAPI miniport driver
- * FILE:        services/storage/atapi/atapi.c
+ * FILE:        drivers/storage/atapi/atapi.c
  * PURPOSE:     ATAPI miniport driver
  * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
+ *              Hartmut Birr
  * REVISIONS:
  *              09-09-2001 Created
  */
  */
 
 #define ENABLE_PCI
+#define ENABLE_NATIVE_PCI
 #define ENABLE_ISA
+#define ENABLE_DMA
 
 //  -------------------------------------------------------------------------
 
-#include <ddk/ntddk.h>
-
-#include "../include/srb.h"
-#include "../include/scsi.h"
-#include "../include/ntddscsi.h"
+#include <ntddk.h>
+#include <srb.h>
+#include <scsi.h>
+#include <ntddscsi.h>
+#include <ntdddisk.h>
+#include <ntddstor.h>
 
 #include "atapi.h"
 
 #define VERSION  "0.0.1"
 
 
+NTSTATUS NTAPI
+DriverEntry(IN PDRIVER_OBJECT DriverObject,
+            IN PUNICODE_STRING RegistryPath);
+
 //  -------------------------------------------------------  File Static Data
 
+#ifdef ENABLE_DMA
+typedef struct _PRD
+{
+  ULONG PhysAddress;
+  ULONG Length;
+} PRD, *PPRD;
+#endif
+
 //    ATAPI_MINIPORT_EXTENSION
 //
 //  DESCRIPTION:
 typedef struct _ATAPI_MINIPORT_EXTENSION
 {
   IDE_DRIVE_IDENTIFY DeviceParams[2];
-  BOOLEAN DevicePresent[2];
-  BOOLEAN DeviceAtapi[2];
+  ULONG DeviceFlags[2];
+  ULONG TransferSize[2];
 
   ULONG CommandPortBase;
   ULONG ControlPortBase;
+  ULONG BusMasterRegisterBase;
 
-  BOOLEAN ExpectingInterrupt;
   PSCSI_REQUEST_BLOCK CurrentSrb;
 
-  PUSHORT DataBuffer;
+  PUCHAR DataBuffer;
+  ULONG DataTransferLength;
+
+  BOOLEAN (FASTCALL *Handler)(IN struct _ATAPI_MINIPORT_EXTENSION* DevExt);
+#ifdef ENABLE_DMA
+  BOOLEAN UseDma;
+  ULONG PRDCount;
+  ULONG PRDMaxCount;
+  PPRD PRDTable;
+  SCSI_PHYSICAL_ADDRESS PRDTablePhysicalAddress;
+#endif
 } ATAPI_MINIPORT_EXTENSION, *PATAPI_MINIPORT_EXTENSION;
 
+/* DeviceFlags */
+#define DEVICE_PRESENT           0x00000001
+#define DEVICE_ATAPI             0x00000002
+#define DEVICE_MULTI_SECTOR_CMD  0x00000004
+#define DEVICE_DWORD_IO          0x00000008
+#define DEVICE_48BIT_ADDRESS     0x00000010
+#define DEVICE_MEDIA_STATUS      0x00000020
+#define DEVICE_DMA_CMD           0x00000040
+#define DEVICE_NO_FLUSH          0x00000080
+
 
 typedef struct _UNIT_EXTENSION
 {
   ULONG Dummy;
 } UNIT_EXTENSION, *PUNIT_EXTENSION;
 
+PCI_SLOT_NUMBER LastSlotNumber;
+
+#ifdef ENABLE_NATIVE_PCI
+typedef struct _PCI_NATIVE_CONTROLLER
+{
+  USHORT VendorID;
+  USHORT DeviceID;
+}
+PCI_NATIVE_CONTROLLER, *PPCI_NATIVE_CONTROLLER;
+
+PCI_NATIVE_CONTROLLER const PciNativeController[] =
+{
+    {
+       0x105A,             // Promise
+       0x4D68,             // PDC20268, Ultra100TX2
+    },
+    {
+       0x105A,             // Promise
+       0x4D30,             // PDC20267, Ultra100
+    }
+};
+#endif
+
 
 //  -----------------------------------------------  Discardable Declarations
 
 #ifdef  ALLOC_PRAGMA
 
-//  make the initialization routines discardable, so that they 
+//  make the initialization routines discardable, so that they
 //  don't waste space
 
 #pragma  alloc_text(init, DriverEntry)
-#pragma  alloc_text(init, IDECreateController)
-#pragma  alloc_text(init, IDEPolledRead)
 
 //  make the PASSIVE_LEVEL routines pageable, so that they don't
 //  waste nonpaged memory
 
-#pragma  alloc_text(page, IDEShutdown)
-#pragma  alloc_text(page, IDEDispatchOpenClose)
-#pragma  alloc_text(page, IDEDispatchRead)
-#pragma  alloc_text(page, IDEDispatchWrite)
-
 #endif  /*  ALLOC_PRAGMA  */
 
 //  ---------------------------------------------------- Forward Declarations
 
+#ifdef ENABLE_DMA
+static BOOLEAN
+AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt,
+            PSCSI_REQUEST_BLOCK Srb,
+            UCHAR cmd);
+#endif
+
 static ULONG STDCALL
 AtapiFindCompatiblePciController(PVOID DeviceExtension,
                                 PVOID HwContext,
@@ -151,9 +210,37 @@ static BOOLEAN STDCALL
 AtapiStartIo(IN PVOID DeviceExtension,
             IN PSCSI_REQUEST_BLOCK Srb);
 
+static VOID
+AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt,
+                   UCHAR command,
+                   BOOLEAN (FASTCALL *Handler)(PATAPI_MINIPORT_EXTENSION));
+
 static BOOLEAN STDCALL
 AtapiInterrupt(IN PVOID DeviceExtension);
 
+static BOOLEAN FASTCALL
+AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt);
+
+static BOOLEAN FASTCALL
+AtapiPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
+
+static BOOLEAN FASTCALL
+AtapiSmartInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
+
+static BOOLEAN FASTCALL
+AtapiReadInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
+
+#ifdef ENABLE_DMA
+static BOOLEAN FASTCALL
+AtapiDmaPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
+
+static BOOLEAN FASTCALL
+AtapiDmaInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
+#endif
+
+static BOOLEAN FASTCALL
+AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
+
 static BOOLEAN
 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
                 PPORT_CONFIGURATION_INFORMATION ConfigInfo);
@@ -166,22 +253,16 @@ AtapiIdentifyDevice(IN ULONG CommandPort,
                    OUT PIDE_DRIVE_IDENTIFY DrvParms);
 
 static BOOLEAN
-IDEResetController(IN ULONG CommandPort,
-                  IN ULONG ControlPort);
-
-static int
 AtapiPolledRead(IN ULONG CommandPort,
                IN ULONG ControlPort,
-               IN BYTE PreComp,
-               IN BYTE SectorCnt,
-               IN BYTE SectorNum,
-               IN BYTE CylinderLow,
-               IN BYTE CylinderHigh,
-               IN BYTE DrvHead,
-               IN BYTE Command,
-               OUT BYTE *Buffer);
-
-
+               IN UCHAR PreComp,
+               IN UCHAR SectorCnt,
+               IN UCHAR SectorNum,
+               IN UCHAR CylinderLow,
+               IN UCHAR CylinderHigh,
+               IN UCHAR DrvHead,
+               IN UCHAR Command,
+               OUT PUCHAR Buffer);
 
 static ULONG
 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
@@ -191,6 +272,10 @@ static ULONG
 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
                    IN PSCSI_REQUEST_BLOCK Srb);
 
+static ULONG
+AtapiSendSmartCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
+                      IN PSCSI_REQUEST_BLOCK Srb);
+
 static ULONG
 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
             IN PSCSI_REQUEST_BLOCK Srb);
@@ -203,18 +288,28 @@ static ULONG
 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
               IN PSCSI_REQUEST_BLOCK Srb);
 
+static ULONG
+AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+               PSCSI_REQUEST_BLOCK Srb);
+
+static ULONG
+AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+                  PSCSI_REQUEST_BLOCK Srb);
 
 static UCHAR
 AtapiErrorToScsi(PVOID DeviceExtension,
                 PSCSI_REQUEST_BLOCK Srb);
 
+static VOID
+AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb);
+
 //  ----------------------------------------------------------------  Inlines
 
 void
-IDESwapBytePairs(char *Buf,
+IDESwapBytePairs(UCHAR *Buf,
                  int Cnt)
 {
-  char  t;
+  UCHAR  t;
   int   i;
 
   for (i = 0; i < Cnt; i += 2)
@@ -231,7 +326,7 @@ IDESwapBytePairs(char *Buf,
 //    DriverEntry
 //
 //  DESCRIPTION:
-//    This function initializes the driver, locates and claims 
+//    This function initializes the driver, locates and claims
 //    hardware resources, and creates various NT objects needed
 //    to process I/O requests.
 //
@@ -241,13 +336,13 @@ IDESwapBytePairs(char *Buf,
 //  ARGUMENTS:
 //    IN  PDRIVER_OBJECT   DriverObject  System allocated Driver Object
 //                                       for this driver
-//    IN  PUNICODE_STRING  RegistryPath  Name of registry driver service 
+//    IN  PUNICODE_STRING  RegistryPath  Name of registry driver service
 //                                       key
 //
 //  RETURNS:
 //    NTSTATUS
 
-STDCALL NTSTATUS
+NTSTATUS NTAPI
 DriverEntry(IN PDRIVER_OBJECT DriverObject,
             IN PUNICODE_STRING RegistryPath)
 {
@@ -273,8 +368,10 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
 
   /* Search the PCI bus for compatibility mode ide controllers */
 #ifdef ENABLE_PCI
+  InitData.NeedPhysicalAddresses = TRUE;
+
   InitData.HwFindAdapter = AtapiFindCompatiblePciController;
-  InitData.NumberOfAccessRanges = 2;
+  InitData.NumberOfAccessRanges = 3;
   InitData.AdapterInterfaceType = PCIBus;
 
   InitData.VendorId = NULL;
@@ -290,30 +387,34 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
 //    statusToReturn = newStatus;
 #endif
 
-  /* Search the ISA bus for ide controllers */
-#ifdef ENABLE_ISA
-  InitData.HwFindAdapter = AtapiFindIsaBusController;
-  InitData.NumberOfAccessRanges = 2;
-  InitData.AdapterInterfaceType = Isa;
+  /* Search the PCI bus for all ide controllers */
+#ifdef ENABLE_NATIVE_PCI
+  InitData.NeedPhysicalAddresses = TRUE;
 
-  InitData.VendorId = NULL;
+  InitData.HwFindAdapter = AtapiFindNativePciController;
+  InitData.NumberOfAccessRanges = 3;
+  InitData.AdapterInterfaceType = PCIBus;
+
+  InitData.VendorId = 0;
   InitData.VendorIdLength = 0;
-  InitData.DeviceId = NULL;
+  InitData.DeviceId = 0;
   InitData.DeviceIdLength = 0;
 
+  LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
+
   Status = ScsiPortInitialize(DriverObject,
                              RegistryPath,
                              &InitData,
                              NULL);
-//      if (newStatus < statusToReturn)
-//        statusToReturn = newStatus;
+//  if (newStatus < statusToReturn)
+//    statusToReturn = newStatus;
 #endif
 
-  /* Search the PCI bus for native mode ide controllers */
-#if 0
-  InitData.HwFindAdapter = AtapiFindNativePciController;
+  /* Search the ISA bus for ide controllers */
+#ifdef ENABLE_ISA
+  InitData.HwFindAdapter = AtapiFindIsaBusController;
   InitData.NumberOfAccessRanges = 2;
-  InitData.AdapterInterfaceType = PCIBus;
+  InitData.AdapterInterfaceType = Isa;
 
   InitData.VendorId = NULL;
   InitData.VendorIdLength = 0;
@@ -323,17 +424,133 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
   Status = ScsiPortInitialize(DriverObject,
                              RegistryPath,
                              &InitData,
-                             (PVOID)i);
-//  if (newStatus < statusToReturn)
-//    statusToReturn = newStatus;
+                             NULL);
+//      if (newStatus < statusToReturn)
+//        statusToReturn = newStatus;
 #endif
 
-  DPRINT( "Returning from DriverEntry\n" );
+  DPRINT("Returning from DriverEntry\n");
 
   return(Status);
 }
 
 
+BOOLEAN
+AtapiClaimHwResources(PATAPI_MINIPORT_EXTENSION DevExt,
+                     PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+                     INTERFACE_TYPE InterfaceType,
+                     ULONG CommandPortBase,
+                     ULONG ControlPortBase,
+                     ULONG BusMasterPortBase,
+                     ULONG InterruptVector)
+{
+   SCSI_PHYSICAL_ADDRESS IoAddress;
+   PVOID IoBase;
+#ifdef ENABLE_DMA
+   ULONG Length;
+#endif
+   IoAddress = ScsiPortConvertUlongToPhysicalAddress(CommandPortBase);
+   IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
+                                  InterfaceType,
+                                 ConfigInfo->SystemIoBusNumber,
+                                 IoAddress,
+                                 8,
+                                 TRUE);
+   if (IoBase == NULL)
+   {
+      return FALSE;
+   }
+   DevExt->Handler = NULL;
+   DevExt->CommandPortBase = (ULONG)IoBase;
+   (*ConfigInfo->AccessRanges)[0].RangeStart = IoAddress;
+   (*ConfigInfo->AccessRanges)[0].RangeLength = 8;
+   (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+   if (ControlPortBase)
+   {
+      IoAddress = ScsiPortConvertUlongToPhysicalAddress(ControlPortBase + 2);
+      IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
+                                     InterfaceType,
+                                    ConfigInfo->SystemIoBusNumber,
+                                    IoAddress,
+                                    1,
+                                    TRUE);
+      if (IoBase == NULL)
+      {
+         ScsiPortFreeDeviceBase((PVOID)DevExt,
+                               (PVOID)DevExt->CommandPortBase);
+         return FALSE;
+      }
+      DevExt->ControlPortBase = (ULONG)IoBase;
+      (*ConfigInfo->AccessRanges)[1].RangeStart = IoAddress;
+      (*ConfigInfo->AccessRanges)[1].RangeLength = 1;
+      (*ConfigInfo->AccessRanges)[1].RangeInMemory = FALSE;
+   }
+   if (BusMasterPortBase)
+   {
+      IoAddress = ScsiPortConvertUlongToPhysicalAddress(BusMasterPortBase);
+      IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
+                                     InterfaceType,
+                                    ConfigInfo->SystemIoBusNumber,
+                                    IoAddress,
+                                    8,
+                                    TRUE);
+      if (IoBase == NULL)
+      {
+         ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->CommandPortBase);
+         ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->ControlPortBase);
+         return FALSE;
+      }
+      DevExt->BusMasterRegisterBase = (ULONG)IoBase;
+      (*ConfigInfo->AccessRanges)[2].RangeStart = IoAddress;
+      (*ConfigInfo->AccessRanges)[2].RangeLength = 8;
+      (*ConfigInfo->AccessRanges)[2].RangeInMemory = FALSE;
+#ifdef ENABLE_DMA
+//      ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
+//      ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
+      ConfigInfo->DmaWidth = Width32Bits;
+//      ConfigInfo->DmaSpeed = Compatible;
+      ConfigInfo->ScatterGather = TRUE;
+      ConfigInfo->Master = TRUE;
+      ConfigInfo->NumberOfPhysicalBreaks = 0x10000 / PAGE_SIZE + 1;
+      ConfigInfo->Dma32BitAddresses = TRUE;
+      ConfigInfo->NeedPhysicalAddresses = TRUE;
+      ConfigInfo->MapBuffers = TRUE;
+
+      DevExt->PRDMaxCount = PAGE_SIZE / sizeof(PRD);
+      DevExt->PRDTable = ScsiPortGetUncachedExtension(DevExt, ConfigInfo, sizeof(PRD) * DevExt->PRDMaxCount);
+      if (DevExt->PRDTable != NULL)
+        {
+         DevExt->PRDTablePhysicalAddress = ScsiPortGetPhysicalAddress(DevExt, NULL, DevExt->PRDTable, &Length);
+       }
+      if (DevExt->PRDTable == NULL ||
+         DevExt->PRDTablePhysicalAddress.QuadPart == 0LL ||
+         Length < sizeof(PRD) * DevExt->PRDMaxCount)
+      {
+         ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->CommandPortBase);
+         ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->ControlPortBase);
+         ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->BusMasterRegisterBase);
+        return FALSE;
+      }
+#endif
+   }
+   ConfigInfo->BusInterruptLevel = InterruptVector;
+   ConfigInfo->BusInterruptVector = InterruptVector;
+   ConfigInfo->InterruptMode = (InterfaceType == Isa) ? Latched : LevelSensitive;
+
+   if ((CommandPortBase == 0x1F0 || ControlPortBase == 0x3F4) && !ConfigInfo->AtdiskPrimaryClaimed)
+   {
+      ConfigInfo->AtdiskPrimaryClaimed = TRUE;
+   }
+   if ((CommandPortBase == 0x170 || ControlPortBase == 0x374) && !ConfigInfo->AtdiskSecondaryClaimed)
+   {
+      ConfigInfo->AtdiskSecondaryClaimed = TRUE;
+   }
+   return TRUE;
+}
+
+
+#ifdef ENABLE_PCI
 static ULONG STDCALL
 AtapiFindCompatiblePciController(PVOID DeviceExtension,
                                 PVOID HwContext,
@@ -346,9 +563,13 @@ AtapiFindCompatiblePciController(PVOID DeviceExtension,
   PCI_SLOT_NUMBER SlotNumber;
   PCI_COMMON_CONFIG PciConfig;
   ULONG DataSize;
+  ULONG StartDeviceNumber;
+  ULONG DeviceNumber;
+  ULONG StartFunctionNumber;
   ULONG FunctionNumber;
   BOOLEAN ChannelFound;
   BOOLEAN DeviceFound;
+  ULONG BusMasterBasePort = 0;
 
   DPRINT("AtapiFindCompatiblePciController() Bus: %lu  Slot: %lu\n",
          ConfigInfo->SystemIoBusNumber,
@@ -361,119 +582,116 @@ AtapiFindCompatiblePciController(PVOID DeviceExtension,
       ConfigInfo->AtdiskSecondaryClaimed == TRUE)
     return(SP_RETURN_NOT_FOUND);
 
-
-  SlotNumber.u.AsULONG = 0;
-  for (FunctionNumber = 0 /*ConfigInfo->SlotNumber*/; FunctionNumber < 256; FunctionNumber++)
-    {
-//      SlotNumber.u.bits.FunctionNumber = FunctionNumber;
-//      SlotNumber.u.AsULONG = (FunctionNumber & 0x07);
-      SlotNumber.u.AsULONG = FunctionNumber;
-
-      ChannelFound = FALSE;
-      DeviceFound = FALSE;
-
-      DataSize = ScsiPortGetBusData(DeviceExtension,
-                                   PCIConfiguration,
-                                   0,
-                                   SlotNumber.u.AsULONG,
-                                   &PciConfig,
-                                   sizeof(PCI_COMMON_CONFIG));
-//      if (DataSize != sizeof(PCI_COMMON_CONFIG) ||
-//       PciConfig.VendorID == PCI_INVALID_VENDORID)
-      if (DataSize == 0)
+  SlotNumber.u.AsULONG = ConfigInfo->SlotNumber;
+  StartDeviceNumber = SlotNumber.u.bits.DeviceNumber;
+  StartFunctionNumber = SlotNumber.u.bits.FunctionNumber;
+  for (DeviceNumber = StartDeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
+  {
+     SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+     for (FunctionNumber = StartFunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
+     {
+       SlotNumber.u.bits.FunctionNumber = FunctionNumber;
+       ChannelFound = FALSE;
+       DeviceFound = FALSE;
+
+        DataSize = ScsiPortGetBusData(DeviceExtension,
+                                     PCIConfiguration,
+                                     ConfigInfo->SystemIoBusNumber,
+                                     SlotNumber.u.AsULONG,
+                                     &PciConfig,
+                                     PCI_COMMON_HDR_LENGTH);
+        if (DataSize != PCI_COMMON_HDR_LENGTH)
        {
-//       if ((SlotNumber.u.AsULONG & 0x07) == 0)
-//         return(SP_RETURN_ERROR); /* No bus found */
-
-         continue;
-//       return(SP_RETURN_ERROR);
+          if (FunctionNumber == 0)
+          {
+             break;
+          }
+          else
+          {
+             continue;
+          }
        }
 
-      if (PciConfig.BaseClass == 0x01 &&
-         PciConfig.SubClass == 0x01) // &&
-//       (PciConfig.ProgIf & 0x05) == 0)
+       DPRINT("%x %x\n", PciConfig.BaseClass, PciConfig.SubClass);
+       if (PciConfig.BaseClass == 0x01 &&
+           PciConfig.SubClass == 0x01) // &&
+//         (PciConfig.ProgIf & 0x05) == 0)
        {
-         /* both channels are in compatibility mode */
-         DPRINT("Bus %1lu  Device %2lu  Func %1lu  VenID 0x%04hx  DevID 0x%04hx\n",
-                ConfigInfo->SystemIoBusNumber,
-                SlotNumber.u.bits.DeviceNumber,
-                SlotNumber.u.bits.FunctionNumber,
-                PciConfig.VendorID,
-                PciConfig.DeviceID);
-         DPRINT("ProgIF 0x%02hx\n", PciConfig.ProgIf);
-
-         DPRINT("Found IDE controller in compatibility mode!\n");
-
-         ConfigInfo->NumberOfBuses = 1;
-         ConfigInfo->MaximumNumberOfTargets = 2;
-         ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
-
-         if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
-           {
+          /* both channels are in compatibility mode */
+          DPRINT("Bus %1lu  Device %2lu  Func %1lu  VenID 0x%04hx  DevID 0x%04hx\n",
+                 ConfigInfo->SystemIoBusNumber,
+                 SlotNumber.u.bits.DeviceNumber,
+                 SlotNumber.u.bits.FunctionNumber,
+                 PciConfig.VendorID,
+                 PciConfig.DeviceID);
+          DPRINT("ProgIF 0x%02hx\n", PciConfig.ProgIf);
+
+          DPRINT("Found IDE controller in compatibility mode!\n");
+
+          ConfigInfo->NumberOfBuses = 1;
+          ConfigInfo->MaximumNumberOfTargets = 2;
+          ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
+
+          if (PciConfig.ProgIf & 0x80)
+          {
+             DPRINT("Found IDE Bus Master controller!\n");
+             if (PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_SPACE)
+             {
+                 BusMasterBasePort = PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK;
+                 DPRINT("  IDE Bus Master Registers at IO %lx\n", BusMasterBasePort);
+             }
+          }
+          if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
+          {
              /* Both channels unclaimed: Claim primary channel */
              DPRINT("Primary channel!\n");
-
-             DevExt->CommandPortBase = 0x01F0;
-             DevExt->ControlPortBase = 0x03F6;
-
-             ConfigInfo->BusInterruptLevel = 14;
-             ConfigInfo->BusInterruptVector = 14;
-             ConfigInfo->InterruptMode = LevelSensitive;
-
-             ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x01F0);
-             ConfigInfo->AccessRanges[0].RangeLength = 8;
-             ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
-
-             ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x03F6);
-             ConfigInfo->AccessRanges[1].RangeLength = 1;
-             ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
-
-             ConfigInfo->AtdiskPrimaryClaimed = TRUE;
-             ChannelFound = TRUE;
-             *Again = TRUE;
-           }
-         else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
-           {
+              ChannelFound = AtapiClaimHwResources(DevExt,
+                                                  ConfigInfo,
+                                                  PCIBus,
+                                                  0x1F0,
+                                                  0x3F4,
+                                                  BusMasterBasePort,
+                                                  14);
+              *Again = TRUE;
+          }
+          else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
+          {
              /* Primary channel already claimed: claim secondary channel */
              DPRINT("Secondary channel!\n");
 
-             DevExt->CommandPortBase = 0x0170;
-             DevExt->ControlPortBase = 0x0376;
-
-             ConfigInfo->BusInterruptLevel = 15;
-             ConfigInfo->BusInterruptVector = 15;
-             ConfigInfo->InterruptMode = LevelSensitive;
-
-             ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0170);
-             ConfigInfo->AccessRanges[0].RangeLength = 8;
-             ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
-
-             ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0376);
-             ConfigInfo->AccessRanges[1].RangeLength = 1;
-             ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
-
-             ConfigInfo->AtdiskSecondaryClaimed = TRUE;
-             ChannelFound = TRUE;
+              ChannelFound = AtapiClaimHwResources(DevExt,
+                                                  ConfigInfo,
+                                                  PCIBus,
+                                                  0x170,
+                                                  0x374,
+                                                  BusMasterBasePort ? BusMasterBasePort + 8 : 0,
+                                                  15);
              *Again = FALSE;
-           }
-
-         /* Find attached devices */
-         if (ChannelFound == TRUE)
-           {
-             DeviceFound = AtapiFindDevices(DevExt,
-                                            ConfigInfo);
-           }
-         DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
-         return(SP_RETURN_FOUND);
-        }
-    }
-
+          }
+          /* Find attached devices */
+          if (ChannelFound)
+          {
+             DeviceFound = AtapiFindDevices(DevExt, ConfigInfo);
+             ConfigInfo->SlotNumber = SlotNumber.u.AsULONG;
+             DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
+             return(SP_RETURN_FOUND);
+          }
+       }
+       if (FunctionNumber == 0 && !(PciConfig.HeaderType & PCI_MULTIFUNCTION))
+       {
+          break;
+       }
+     }
+     StartFunctionNumber = 0;
+  }
   DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
 
   return(SP_RETURN_NOT_FOUND);
 }
+#endif
 
 
+#ifdef ENABLE_ISA
 static ULONG STDCALL
 AtapiFindIsaBusController(PVOID DeviceExtension,
                          PVOID HwContext,
@@ -499,47 +717,27 @@ AtapiFindIsaBusController(PVOID DeviceExtension,
       /* Both channels unclaimed: Claim primary channel */
       DPRINT("Primary channel!\n");
 
-      DevExt->CommandPortBase = 0x01F0;
-      DevExt->ControlPortBase = 0x03F6;
-
-      ConfigInfo->BusInterruptLevel = 14;
-      ConfigInfo->BusInterruptVector = 14;
-      ConfigInfo->InterruptMode = LevelSensitive;
-
-      ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x01F0);
-      ConfigInfo->AccessRanges[0].RangeLength = 8;
-      ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
-
-      ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x03F6);
-      ConfigInfo->AccessRanges[1].RangeLength = 1;
-      ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
-
-      ConfigInfo->AtdiskPrimaryClaimed = TRUE;
-      ChannelFound = TRUE;
-      *Again = FALSE/*TRUE*/;
+      ChannelFound = AtapiClaimHwResources(DevExt,
+                                          ConfigInfo,
+                                          Isa,
+                                          0x1F0,
+                                          0x3F4,
+                                          0,
+                                          14);
+      *Again = TRUE;
     }
   else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
     {
       /* Primary channel already claimed: claim secondary channel */
       DPRINT("Secondary channel!\n");
 
-      DevExt->CommandPortBase = 0x0170;
-      DevExt->ControlPortBase = 0x0376;
-
-      ConfigInfo->BusInterruptLevel = 15;
-      ConfigInfo->BusInterruptVector = 15;
-      ConfigInfo->InterruptMode = LevelSensitive;
-
-      ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0170);
-      ConfigInfo->AccessRanges[0].RangeLength = 8;
-      ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
-
-      ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0376);
-      ConfigInfo->AccessRanges[1].RangeLength = 1;
-      ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
-
-      ConfigInfo->AtdiskSecondaryClaimed = TRUE;
-      ChannelFound = TRUE;
+      ChannelFound = AtapiClaimHwResources(DevExt,
+                                          ConfigInfo,
+                                          Isa,
+                                          0x170,
+                                          0x374,
+                                          0,
+                                          15);
       *Again = FALSE;
     }
   else
@@ -554,13 +752,16 @@ AtapiFindIsaBusController(PVOID DeviceExtension,
     {
       DeviceFound = AtapiFindDevices(DevExt,
                                     ConfigInfo);
+      DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
+      return(SP_RETURN_FOUND);
     }
-
-  DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
-  return(SP_RETURN_FOUND);
+  *Again = FALSE;
+  return SP_RETURN_NOT_FOUND;
 }
+#endif
 
 
+#ifdef ENABLE_NATIVE_PCI
 static ULONG STDCALL
 AtapiFindNativePciController(PVOID DeviceExtension,
                             PVOID HwContext,
@@ -570,15 +771,129 @@ AtapiFindNativePciController(PVOID DeviceExtension,
                             PBOOLEAN Again)
 {
   PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
+  PCI_COMMON_CONFIG PciConfig;
+  PCI_SLOT_NUMBER SlotNumber;
+  ULONG DataSize;
+  ULONG DeviceNumber;
+  ULONG StartDeviceNumber;
+  ULONG FunctionNumber;
+  ULONG StartFunctionNumber;
+  ULONG BusMasterBasePort;
+  ULONG Count;
+  BOOLEAN ChannelFound;
 
   DPRINT("AtapiFindNativePciController() called!\n");
 
+  SlotNumber.u.AsULONG = ConfigInfo->SlotNumber;
+  StartDeviceNumber = SlotNumber.u.bits.DeviceNumber;
+  StartFunctionNumber = SlotNumber.u.bits.FunctionNumber;
+  for (DeviceNumber = StartDeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
+  {
+     SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+     for (FunctionNumber = StartFunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
+     {
+       SlotNumber.u.bits.FunctionNumber = FunctionNumber;
+       DataSize = ScsiPortGetBusData(DeviceExtension,
+                                     PCIConfiguration,
+                                     ConfigInfo->SystemIoBusNumber,
+                                     SlotNumber.u.AsULONG,
+                                     &PciConfig,
+                                     PCI_COMMON_HDR_LENGTH);
+       if (DataSize != PCI_COMMON_HDR_LENGTH)
+       {
+          break;
+       }
+       for (Count = 0; Count < sizeof(PciNativeController)/sizeof(PCI_NATIVE_CONTROLLER); Count++)
+       {
+          if (PciConfig.VendorID == PciNativeController[Count].VendorID &&
+              PciConfig.DeviceID == PciNativeController[Count].DeviceID)
+          {
+             break;
+          }
+       }
+       if (Count < sizeof(PciNativeController)/sizeof(PCI_NATIVE_CONTROLLER))
+       {
+          /* We have found a known native pci ide controller */
+          if ((PciConfig.ProgIf & 0x80) && (PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_SPACE))
+          {
+             DPRINT("Found IDE Bus Master controller!\n");
+             BusMasterBasePort = PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK;
+             DPRINT("  IDE Bus Master Registers at IO %lx\n", BusMasterBasePort);
+          }
+          else
+          {
+             BusMasterBasePort = 0;
+          }
+
+          DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig.VendorID, PciConfig.DeviceID);
+          ConfigInfo->NumberOfBuses = 1;
+          ConfigInfo->MaximumNumberOfTargets = 2;
+          ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
+
+          /* FIXME:
+               We must not store and use the last tested slot number. If there is a recall
+               to the some device and we will claim the primary channel again than the call
+               to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
+               claim the secondary channel.
+           */
+          ChannelFound = FALSE;
+          if (LastSlotNumber.u.AsULONG != SlotNumber.u.AsULONG)
+          {
+             /* try to claim primary channel */
+             if ((PciConfig.u.type0.BaseAddresses[0] & PCI_ADDRESS_IO_SPACE) &&
+                 (PciConfig.u.type0.BaseAddresses[1] & PCI_ADDRESS_IO_SPACE))
+             {
+                /* primary channel is enabled */
+                ChannelFound = AtapiClaimHwResources(DevExt,
+                                                     ConfigInfo,
+                                                     PCIBus,
+                                                     PciConfig.u.type0.BaseAddresses[0] & PCI_ADDRESS_IO_ADDRESS_MASK,
+                                                     PciConfig.u.type0.BaseAddresses[1] & PCI_ADDRESS_IO_ADDRESS_MASK,
+                                                     BusMasterBasePort,
+                                                     PciConfig.u.type0.InterruptLine);
+                if (ChannelFound)
+                {
+                    AtapiFindDevices(DevExt, ConfigInfo);
+                    *Again = TRUE;
+                   ConfigInfo->SlotNumber = LastSlotNumber.u.AsULONG = SlotNumber.u.AsULONG;
+                    return SP_RETURN_FOUND;
+                }
+             }
+          }
+          if (!ChannelFound)
+          {
+             /* try to claim secondary channel */
+             if ((PciConfig.u.type0.BaseAddresses[2] & PCI_ADDRESS_IO_SPACE) &&
+                 (PciConfig.u.type0.BaseAddresses[3] & PCI_ADDRESS_IO_SPACE))
+             {
+                /* secondary channel is enabled */
+                ChannelFound = AtapiClaimHwResources(DevExt,
+                                                     ConfigInfo,
+                                                     PCIBus,
+                                                     PciConfig.u.type0.BaseAddresses[2] & PCI_ADDRESS_IO_ADDRESS_MASK,
+                                                     PciConfig.u.type0.BaseAddresses[3] & PCI_ADDRESS_IO_ADDRESS_MASK,
+                                                     BusMasterBasePort ? BusMasterBasePort + 8 : 0,
+                                                     PciConfig.u.type0.InterruptLine);
+                if (ChannelFound)
+                {
+                   AtapiFindDevices(DevExt, ConfigInfo);
+                    *Again = FALSE;
+                   LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
+                    return SP_RETURN_FOUND;
+                }
+             }
+          }
+       }
+     }
+     StartFunctionNumber = 0;
+  }
   *Again = FALSE;
-
+  LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
   DPRINT("AtapiFindNativePciController() done!\n");
 
   return(SP_RETURN_NOT_FOUND);
 }
+#endif
 
 
 static BOOLEAN STDCALL
@@ -611,7 +926,7 @@ AtapiStartIo(IN PVOID DeviceExtension,
     {
       case SRB_FUNCTION_EXECUTE_SCSI:
        DevExt->CurrentSrb = Srb;
-       if (DevExt->DeviceAtapi[Srb->TargetId] == TRUE)
+       if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
          {
            Result = AtapiSendAtapiCommand(DevExt,
                                           Srb);
@@ -623,6 +938,148 @@ AtapiStartIo(IN PVOID DeviceExtension,
          }
        break;
 
+      case SRB_FUNCTION_ABORT_COMMAND:
+       if (DevExt->CurrentSrb != NULL)
+         {
+           Result = SRB_STATUS_ABORT_FAILED;
+         }
+       else
+         {
+           Result = SRB_STATUS_SUCCESS;
+         }
+       break;
+
+      case SRB_FUNCTION_IO_CONTROL:
+        {
+          PSRB_IO_CONTROL SrbIoControl = (PSRB_IO_CONTROL)Srb->DataBuffer;
+          if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) ||
+              Srb->DataTransferLength < SrbIoControl->Length + sizeof(SRB_IO_CONTROL))
+            {
+              Result = SRB_STATUS_INVALID_REQUEST;
+            }
+          else
+            {
+              if (!_strnicmp((char*)SrbIoControl->Signature, "ScsiDisk", 8))
+                {
+                  switch (SrbIoControl->ControlCode)
+                    {
+                      default:
+                        Result = SRB_STATUS_INVALID_REQUEST;
+                        break;
+
+                      case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
+                      case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
+                      case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
+                      case IOCTL_SCSI_MINIPORT_ENABLE_SMART:
+                      case IOCTL_SCSI_MINIPORT_DISABLE_SMART:
+                      case IOCTL_SCSI_MINIPORT_RETURN_STATUS:
+                      case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
+                      case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
+                      case IOCTL_SCSI_MINIPORT_READ_SMART_LOG:
+#if 0
+                      case IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG:
+#endif
+                        Result = AtapiSendSmartCommand(DevExt, Srb);
+                        break;
+
+                      case IOCTL_SCSI_MINIPORT_SMART_VERSION:
+                        {
+                          GETVERSIONINPARAMS Version;      
+                          ULONG i;
+
+                          DPRINT("IOCTL_SCSI_MINIPORT_SMART_VERSION\n");
+
+                          RtlZeroMemory(&Version, sizeof(GETVERSIONINPARAMS));
+                          Version.bVersion = 1;
+                          Version.bRevision = 1;
+                          for (i = 0; i < 2; i++)
+                            {
+                              switch (DevExt->DeviceFlags[i] & (DEVICE_PRESENT|DEVICE_ATAPI))
+                                {
+                                  case DEVICE_PRESENT:
+                                    Version.bIDEDeviceMap |= 0x01 << i;
+                                    break;
+/*
+                                  case DEVICE_PRESENT|DEVICE_ATAPI:
+                                    Version.bIDEDeviceMap |= 0x11 << i;
+                                    break;
+*/
+                                }
+                            }
+                          Version.fCapabilities = CAP_ATA_ID_CMD/*|CAP_ATAPI_ID_CMD|CAP_SMART_CMD*/;
+                          SrbIoControl->Length = min(sizeof(GETVERSIONINPARAMS), Srb->DataTransferLength - sizeof(SRB_IO_CONTROL));
+                          memcpy(SrbIoControl + 1, &Version, SrbIoControl->Length);
+                          Result = SRB_STATUS_SUCCESS;
+                          break;
+                        }
+
+                      case IOCTL_SCSI_MINIPORT_IDENTIFY:
+                        {
+                          SENDCMDOUTPARAMS OutParams;
+                          SENDCMDINPARAMS InParams = *(PSENDCMDINPARAMS)(SrbIoControl + 1);
+
+                          DPRINT("IOCTL_SCSI_MINIPORT_IDENTIFY\n");
+
+                          if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1)
+                            {
+                              Result = SRB_STATUS_INVALID_REQUEST;
+                              break;
+                            }
+                  
+                          RtlZeroMemory(&OutParams, sizeof(SENDCMDOUTPARAMS));
+
+                          if (InParams.irDriveRegs.bCommandReg != IDE_CMD_IDENT_ATA_DRV)
+                            {
+                              DPRINT("bCommandReg: %x\n", InParams.irDriveRegs.bCommandReg);
+                              OutParams.DriverStatus.bIDEError = 1;
+                              Result = SRB_STATUS_INVALID_REQUEST;
+                            }
+                          else if (InParams.bDriveNumber > 1 ||
+                                   (DevExt->DeviceFlags[InParams.bDriveNumber] & (DEVICE_PRESENT|DEVICE_ATAPI)) != DEVICE_PRESENT)
+                            {
+                              OutParams.DriverStatus.bIDEError = 1;
+                              Result = SRB_STATUS_NO_DEVICE;
+                            }
+                          else
+                            {
+                              Result = SRB_STATUS_SUCCESS;
+                            }
+                          if (Result == SRB_STATUS_SUCCESS)
+                            {
+                              SrbIoControl->Length = min(sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE, Srb->DataTransferLength - sizeof(SRB_IO_CONTROL));
+                            }
+                          else
+                            {
+                              SrbIoControl->Length = min(sizeof(SENDCMDOUTPARAMS) - 1, Srb->DataTransferLength - sizeof(SRB_IO_CONTROL));
+                            }
+
+                          if (SrbIoControl->Length >= sizeof(SENDCMDOUTPARAMS) - 1)
+                            {
+                              OutParams.cBufferSize = min(SrbIoControl->Length, IDENTIFY_BUFFER_SIZE);
+                            }
+                          
+                          memcpy(SrbIoControl + 1, &OutParams, min (SrbIoControl->Length, sizeof(SENDCMDOUTPARAMS) - 1));
+                         
+                          if (SrbIoControl->Length > sizeof(SENDCMDOUTPARAMS) - 1)
+                            {
+                              RtlCopyMemory((PVOID)((ULONG_PTR)(SrbIoControl + 1) + sizeof(SENDCMDOUTPARAMS) - 1), &DevExt->DeviceParams[InParams.bDriveNumber], OutParams.cBufferSize);
+                            }
+                          break;
+                        }
+                    }
+                }
+              else
+                {
+                  Result = SRB_STATUS_INVALID_REQUEST;
+                  SrbIoControl->Length = 0;
+                }
+            }
+          break;
+        }
+
+      default:
+       Result = SRB_STATUS_INVALID_REQUEST;
+       break;
     }
 
   Srb->SrbStatus = Result;
@@ -631,7 +1088,6 @@ AtapiStartIo(IN PVOID DeviceExtension,
   if (Result != SRB_STATUS_PENDING)
     {
       DevExt->CurrentSrb = NULL;
-      Srb->SrbStatus = (UCHAR)Result;
 
       ScsiPortNotification(RequestComplete,
                           DeviceExtension,
@@ -650,262 +1106,169 @@ AtapiStartIo(IN PVOID DeviceExtension,
   return(TRUE);
 }
 
-
 static BOOLEAN STDCALL
 AtapiInterrupt(IN PVOID DeviceExtension)
 {
   PATAPI_MINIPORT_EXTENSION DevExt;
-  PSCSI_REQUEST_BLOCK Srb;
-  ULONG CommandPortBase;
-  ULONG ControlPortBase;
+  UCHAR Status;
+  DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
 
-  UCHAR DeviceStatus;
-  BOOLEAN IsLastBlock;
-  BOOLEAN IsAtapi;
-  ULONG Retries;
-  PUCHAR TargetAddress;
-  ULONG SectorSize;
-  ULONG TransferSize;
+  if (DevExt->Handler == NULL)
+    {
+      Status =  IDEReadAltStatus(DevExt->ControlPortBase);
+      if ((Status & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_DRQ)) != IDE_SR_DRDY)
+        {
+         static ULONG Count = 0;
+         Count++;
+         DPRINT1("Unexpected Interrupt, CommandPort=%04x, Status=%02x, Count=%ld\n",
+                 DevExt->CommandPortBase, Status, Count);
+       }
+      return FALSE;
+    }
+#ifdef ENABLE_DMA
+  if (DevExt->UseDma)
+    {
+      Status = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
+      if (!(Status & 0x04))
+        {
+         return FALSE;
+       }
+    }
+  else
+#endif
+    {
+      Status = IDEReadAltStatus(DevExt->ControlPortBase);
+      if (Status & IDE_SR_BUSY)
+        {
+         return FALSE;
+       }
+    }
+  return DevExt->Handler(DevExt);
+}
 
+//  ----------------------------------------------------  Discardable statics
 
-  DPRINT("AtapiInterrupt() called!\n");
+#ifdef ENABLE_DMA
+static BOOLEAN
+AtapiConfigDma(PATAPI_MINIPORT_EXTENSION DeviceExtension, ULONG UnitNumber)
+{
+  BOOLEAN Result = FALSE;
+  UCHAR Status;
 
-  DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
-  if (DevExt->ExpectingInterrupt == FALSE)
+  if (UnitNumber < 2)
     {
-      DPRINT("AtapiInterrupt(): Unexpected interrupt\n");
-      return(FALSE);
+      if (DeviceExtension->PRDTable)
+        {
+          if (DeviceExtension->DeviceParams[UnitNumber].Capabilities & IDE_DRID_DMA_SUPPORTED)
+            {
+              if ((DeviceExtension->DeviceParams[UnitNumber].TMFieldsValid & 0x0004) &&
+                  (DeviceExtension->DeviceParams[UnitNumber].UltraDmaModes & 0x7F00))
+                {
+                  Result = TRUE;
+                }
+              else if (DeviceExtension->DeviceParams[UnitNumber].TMFieldsValid & 0x0002)
+               {
+                 if ((DeviceExtension->DeviceParams[UnitNumber].MultiDmaModes & 0x0404) == 0x0404)
+                   {
+                      Result = TRUE;
+                    }
+#if 0
+                  /* FIXME:
+                  *   should we support single mode dma ?
+                  */
+                 else if ((DeviceExtension->DeviceParams[UnitNumber].DmaModes & 0x0404) == 0x0404)
+                   {
+                      Result = TRUE;
+                   }
+#endif
+                }
+              Status = IDEReadDMAStatus(DeviceExtension->BusMasterRegisterBase);
+              if (Result)
+                {
+                  IDEWriteDMAStatus(DeviceExtension->BusMasterRegisterBase, Status | (UnitNumber ? 0x40 : 0x20));
+               }
+              else
+                {
+                  IDEWriteDMAStatus(DeviceExtension->BusMasterRegisterBase, Status & (UnitNumber ? ~0x40 : ~0x20));
+                }
+           }
+       }
     }
+  return Result;
+}
+#endif
 
-  Srb = DevExt->CurrentSrb;
-  DPRINT("Srb: %p\n", Srb);
+/**********************************************************************
+ * NAME                                                        INTERNAL
+ *     AtapiFindDevices
+ *
+ * DESCRIPTION
+ *     Searches for devices on the given port.
+ *
+ * RUN LEVEL
+ *     PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ *     DeviceExtension
+ *             Port device specific information.
+ *
+ *     ConfigInfo
+ *             Port configuration information.
+ *
+ * RETURN VALUE
+ *     TRUE: At least one device is attached to the port.
+ *     FALSE: No device is attached to the port.
+ */
 
-  CommandPortBase = DevExt->CommandPortBase;
-  ControlPortBase = DevExt->ControlPortBase;
-  DPRINT("CommandPortBase: %lx  ControlPortBase: %lx\n", CommandPortBase, ControlPortBase);
+static BOOLEAN
+AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+                PPORT_CONFIGURATION_INFORMATION ConfigInfo)
+{
+  BOOLEAN DeviceFound = FALSE;
+  ULONG CommandPortBase;
+  ULONG ControlPortBase;
+  ULONG UnitNumber;
+  ULONG Retries;
+  UCHAR High;
+  UCHAR Low;
 
-  IsAtapi = DevExt->DeviceAtapi[Srb->TargetId];
-  DPRINT("IsAtapi == %s\n", (IsAtapi) ? "TRUE" : "FALSE");
+  DPRINT("AtapiFindDevices() called\n");
 
-  IsLastBlock = FALSE;
+  CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
+  DPRINT("  CommandPortBase: %x\n", CommandPortBase);
 
-  DeviceStatus = IDEReadStatus(CommandPortBase);
+  ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
+  DPRINT("  ControlPortBase: %x\n", ControlPortBase);
 
-  if ((DeviceStatus & IDE_SR_ERR) &&
-      (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE))
-    {
-      /* Report error condition */
-      Srb->SrbStatus = SRB_STATUS_ERROR;
-      IsLastBlock = TRUE;
-    }
-  else
+  for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
     {
-      if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
-       {
-         DPRINT("Read data\n");
+      /* Select drive */
+      IDEWriteDriveHead(CommandPortBase,
+                       IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
+      ScsiPortStallExecution(500);
 
-         /* Update controller/device state variables */
-         TargetAddress = Srb->DataBuffer;
+      /* Disable interrupts */
+      IDEWriteDriveControl(ControlPortBase,
+                          IDE_DC_nIEN);
+      ScsiPortStallExecution(500);
 
-         if (IsAtapi)
-           {
-             TransferSize = IDEReadCylinderLow(CommandPortBase);
-             TransferSize += IDEReadCylinderHigh(CommandPortBase) << 8;
-           }
-         else
-           {
-             TransferSize = DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
-           }
+      /* Check if a device is attached to the interface */
+      IDEWriteCylinderHigh(CommandPortBase, 0xaa);
+      IDEWriteCylinderLow(CommandPortBase, 0x55);
 
-         DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
-         DPRINT("TransferSize: %lu\n", TransferSize);
+      High = IDEReadCylinderHigh(CommandPortBase);
+      Low = IDEReadCylinderLow(CommandPortBase);
 
-         if (Srb->DataTransferLength <= TransferSize)
-           {
-             Srb->DataTransferLength = 0;
-             IsLastBlock = TRUE;
-           }
-         else
-           {
-             Srb->DataTransferLength -= TransferSize;
-             IsLastBlock = FALSE;
-           }
-         Srb->DataBuffer += TransferSize;
-         DPRINT("IsLastBlock == %s\n", (IsLastBlock) ? "TRUE" : "FALSE");
-
-         /* Wait for DRQ assertion */
-         for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
-              !(IDEReadStatus(CommandPortBase) & IDE_SR_DRQ);
-              Retries++)
-           {
-               KeStallExecutionProcessor(10);
-           }
-
-         /* Copy the block of data */
-         IDEReadBlock(CommandPortBase,
-                      TargetAddress,
-                      TransferSize);
-
-         /* check DRQ */
-         if (IsLastBlock)
-           {
-             for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
-                  (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
-                  Retries++)
-               {
-                 KeStallExecutionProcessor(10);
-               }
-
-             /* Check for data overrun */
-             if (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
-               {
-                 /* FIXME: Handle error! */
-                 DPRINT1("AtapiInterrupt(): data overrun error!");
-               }
-           }
-
-         Srb->SrbStatus = SRB_STATUS_SUCCESS;
-       }
-      else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
-       {
-         DPRINT("Write data\n");
-
-         if (Srb->DataTransferLength == 0)
-           {
-
-             for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
-                  (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
-                  Retries++)
-               {
-                 KeStallExecutionProcessor(10);
-               }
-
-             /* Check for data overrun */
-             if (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
-               {
-                 /* FIXME: Handle error! */
-                 DPRINT1("AtapiInterrupt(): data overrun error!");
-               }
-
-             DevExt->ExpectingInterrupt = FALSE;
-             IsLastBlock = TRUE;
-           }
-         else
-           {
-             /* Update SRB data */
-             SectorSize = DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
-
-             TargetAddress = Srb->DataBuffer;
-             Srb->DataBuffer += SectorSize;
-             Srb->DataTransferLength -= SectorSize;
-
-             /* Write the sector */
-             IDEWriteBlock(CommandPortBase,
-                           TargetAddress,
-                           SectorSize);
-           }
+      IDEWriteCylinderHigh(CommandPortBase, 0);
+      IDEWriteCylinderLow(CommandPortBase, 0);
 
-         Srb->SrbStatus = SRB_STATUS_SUCCESS;
-       }
-      else
+      if (Low != 0x55 || High != 0xaa)
        {
-         DPRINT1("Unspecified transfer direction!\n");
-         Srb->SrbStatus = SRB_STATUS_SUCCESS; // SRB_STATUS_ERROR;
-         IsLastBlock = TRUE;
+         DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber, CommandPortBase);
+         continue;
        }
-    }
-
-
-  if (Srb->SrbStatus == SRB_STATUS_ERROR)
-    {
-      Srb->SrbStatus = AtapiErrorToScsi(DeviceExtension,
-                                       Srb);
-    }
-
-
-  /* complete this packet */
-  if (IsLastBlock)
-    {
-      DevExt->ExpectingInterrupt = FALSE;
-
-      ScsiPortNotification(RequestComplete,
-                          DeviceExtension,
-                          Srb);
-
-      ScsiPortNotification(NextRequest,
-                          DeviceExtension,
-                          NULL);
-    }
-
-  DPRINT("AtapiInterrupt() done!\n");
-
-  return(TRUE);
-}
-
-
-
-
-
-
-//  ----------------------------------------------------  Discardable statics
-
-
-/**********************************************************************
- * NAME                                                        INTERNAL
- *     AtapiFindDevices
- *
- * DESCRIPTION
- *     Searches for devices on the given port.
- *
- * RUN LEVEL
- *     PASSIVE_LEVEL
- *
- * ARGUMENTS
- *     DeviceExtension
- *             Port device specific information.
- *
- *     ConfigInfo
- *             Port configuration information.
- *
- * RETURN VALUE
- *     TRUE: At least one device is attached to the port.
- *     FALSE: No device is attached to the port.
- */
 
-static BOOLEAN
-AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
-                PPORT_CONFIGURATION_INFORMATION ConfigInfo)
-{
-  BOOLEAN DeviceFound = FALSE;
-  ULONG CommandPortBase;
-  ULONG ControlPortBase;
-  ULONG UnitNumber;
-  ULONG Retries;
-  BYTE High, Low;
-
-  DPRINT("AtapiFindDevices() called\n");
-
-  CommandPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[0].RangeStart);
-  DPRINT("  CommandPortBase: %x\n", CommandPortBase);
-
-  ControlPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[1].RangeStart);
-  DPRINT("  ControlPortBase: %x\n", ControlPortBase);
-
-  for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
-    {
-      /* Select drive */
-      IDEWriteDriveHead(CommandPortBase,
-                       IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
-      ScsiPortStallExecution(500);
-
-      /* Disable interrupts */
-      IDEWriteDriveControl(ControlPortBase,
-                          IDE_DC_nIEN);
-      ScsiPortStallExecution(500);
-
-      IDEWriteCylinderHigh(CommandPortBase, 0);
-      IDEWriteCylinderLow(CommandPortBase, 0);
-      IDEWriteCommand(CommandPortBase, IDE_CMD_RESET);
+      AtapiExecuteCommand(DeviceExtension, IDE_CMD_RESET, NULL);
 
       for (Retries = 0; Retries < 20000; Retries++)
        {
@@ -918,7 +1281,7 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
       if (Retries >= 20000)
        {
          DPRINT("Timeout on drive %lu\n", UnitNumber);
-         DeviceExtension->DevicePresent[UnitNumber] = FALSE;
+         DeviceExtension->DeviceFlags[UnitNumber] &= ~DEVICE_PRESENT;
          continue;
        }
 
@@ -939,8 +1302,27 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
                                  &DeviceExtension->DeviceParams[UnitNumber]))
            {
              DPRINT("  ATAPI drive found!\n");
-             DeviceExtension->DevicePresent[UnitNumber] = TRUE;
-             DeviceExtension->DeviceAtapi[UnitNumber] = TRUE;
+             DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
+             DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_ATAPI;
+             DeviceExtension->TransferSize[UnitNumber] =
+               DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
+#ifdef ENABLE_DMA
+              if (AtapiConfigDma(DeviceExtension, UnitNumber))
+               {
+                 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DMA_CMD;
+               }
+#endif
+              if (!(DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x1000) ||
+                 !(DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x1000))
+                {
+                  DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;                      
+                }
+
+              /* Don't flush CD/DVD drives */
+              if (((DeviceExtension->DeviceParams[UnitNumber].ConfigBits >> 8) & 0x1F) == READ_ONLY_DIRECT_ACCESS_DEVICE)
+               {
+                 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;
+               }
              DeviceFound = TRUE;
            }
          else
@@ -957,8 +1339,47 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
                                  &DeviceExtension->DeviceParams[UnitNumber]))
            {
              DPRINT("  IDE drive found!\n");
-             DeviceExtension->DevicePresent[UnitNumber] = TRUE;
-             DeviceExtension->DeviceAtapi[UnitNumber] = FALSE;
+             DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
+             DeviceExtension->TransferSize[UnitNumber] = DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
+             if ((DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0x8000) &&
+                 (DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0xff) &&
+                 (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0x100) &&
+                 (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff))
+               {
+                 DeviceExtension->TransferSize[UnitNumber] *= (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff);
+                 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_MULTI_SECTOR_CMD;
+               }
+             if (DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x0400 &&
+                 DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x0400)
+               {
+                 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_48BIT_ADDRESS;
+               }
+             if (DeviceExtension->DeviceParams[UnitNumber].DWordIo)
+               {
+                 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DWORD_IO;
+               }
+#ifdef ENABLE_DMA
+             if (AtapiConfigDma(DeviceExtension, UnitNumber))
+               {
+                 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DMA_CMD;
+               }
+#endif
+              if (DeviceExtension->DeviceFlags[UnitNumber] & DEVICE_48BIT_ADDRESS)
+                {
+                  if (!(DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x2000) ||
+                     !(DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x2000))
+                    {
+                      DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;                      
+                    }
+                }
+              else
+                {
+                  if (!(DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x1000) ||
+                     !(DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x1000))
+                    {
+                      DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;                      
+                    }
+                }
              DeviceFound = TRUE;
            }
          else
@@ -968,6 +1389,14 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
        }
     }
 
+  /* Reset pending interrupts */
+  IDEReadStatus(CommandPortBase);
+  /* Reenable interrupts */
+  IDEWriteDriveControl(ControlPortBase, 0);
+  ScsiPortStallExecution(500);
+  /* Return with drive 0 selected */
+  IDEWriteDriveHead(CommandPortBase, IDE_DH_FIXED);
+  ScsiPortStallExecution(500);
 
   DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound) ? "TRUE" : "FALSE");
 
@@ -975,56 +1404,6 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
 }
 
 
-//    AtapiResetController
-//
-//  DESCRIPTION:
-//    Reset the controller and report completion status
-//
-//  RUN LEVEL:
-//    PASSIVE_LEVEL
-//
-//  ARGUMENTS:
-//    IN  WORD  CommandPort  The address of the command port
-//    IN  WORD  ControlPort  The address of the control port
-//
-//  RETURNS:
-//
-
-static BOOLEAN
-AtapiResetController(IN ULONG CommandPort,
-                    IN ULONG ControlPort)
-{
-  int Retries;
-
-  /* Assert drive reset line */
-  IDEWriteDriveControl(ControlPort, IDE_DC_SRST);
-
-  /* Wait for min. 25 microseconds */
-  ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH);
-
-  /* Negate drive reset line */
-  IDEWriteDriveControl(ControlPort, 0);
-
-  /* Wait for BUSY negation */
-  for (Retries = 0; Retries < IDE_RESET_BUSY_TIMEOUT * 1000; Retries++)
-    {
-      if (!(IDEReadStatus(CommandPort) & IDE_SR_BUSY))
-       {
-         break;
-       }
-      ScsiPortStallExecution(10);
-    }
-
-  if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
-    {
-      return(FALSE);
-    }
-
-    //  return TRUE if controller came back to life. and
-    //  the registers are initialized correctly
-  return(IDEReadError(CommandPort) == 1);
-}
-
 /*
  *  AtapiIdentifyDevice
  *
@@ -1059,6 +1438,10 @@ AtapiIdentifyDevice(IN ULONG CommandPort,
                    OUT PIDE_DRIVE_IDENTIFY DrvParms)
 {
   LONG i;
+  ULONG mode;
+  char SerialNumber[20];
+  char FirmwareRev[8];
+  char ModelNumber[40];
 
   /*  Get the Drive Identify block from drive or die  */
   if (AtapiPolledRead(CommandPort,
@@ -1070,16 +1453,19 @@ AtapiIdentifyDevice(IN ULONG CommandPort,
                      0,
                      (DriveNum ? IDE_DH_DRV1 : 0),
                      (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
-                     (BYTE *)DrvParms) != 0)
+                     (PUCHAR)DrvParms) == FALSE)
     {
-      DPRINT("IDEPolledRead() failed\n");
-      return(FALSE);
+      DPRINT("AtapiPolledRead() failed\n");
+      return FALSE;
     }
 
   /*  Report on drive parameters if debug mode  */
-  IDESwapBytePairs(DrvParms->SerialNumber, 20);
-  IDESwapBytePairs(DrvParms->FirmwareRev, 8);
-  IDESwapBytePairs(DrvParms->ModelNumber, 40);
+  memcpy(SerialNumber, DrvParms->SerialNumber, 20);
+  memcpy(FirmwareRev, DrvParms->FirmwareRev, 8);
+  memcpy(ModelNumber, DrvParms->ModelNumber, 40);
+  IDESwapBytePairs((PUCHAR)SerialNumber, 20);
+  IDESwapBytePairs((PUCHAR)FirmwareRev, 8);
+  IDESwapBytePairs((PUCHAR)ModelNumber, 40);
   DPRINT("Config:%04x  Cyls:%5d  Heads:%2d  Sectors/Track:%3d  Gaps:%02d %02d\n",
          DrvParms->ConfigBits,
          DrvParms->LogicalCyls,
@@ -1090,15 +1476,16 @@ AtapiIdentifyDevice(IN ULONG CommandPort,
   DPRINT("Bytes/PLO:%3d  Vendor Cnt:%2d  Serial number:[%.20s]\n",
          DrvParms->BytesInPLO,
          DrvParms->VendorUniqueCnt,
-         DrvParms->SerialNumber);
+         SerialNumber);
   DPRINT("Cntlr type:%2d  BufSiz:%5d  ECC bytes:%3d  Firmware Rev:[%.8s]\n",
          DrvParms->ControllerType,
          DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
          DrvParms->ECCByteCnt,
-         DrvParms->FirmwareRev);
-  DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
-  DPRINT("RWMult?:%02x  LBA:%d  DMA:%d  MinPIO:%d ns  MinDMA:%d ns\n",
-         (DrvParms->RWMultImplemented) & 0xff,
+         FirmwareRev);
+  DPRINT("Model:[%.40s]\n", ModelNumber);
+  DPRINT("RWMultMax?:%04x  RWMult?:%02x  LBA:%d  DMA:%d  MinPIO:%d ns  MinDMA:%d ns\n",
+         (DrvParms->RWMultImplemented),
+        (DrvParms->RWMultCurrent) & 0xff,
          (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
          (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
          DrvParms->MinPIOTransTime,
@@ -1112,26 +1499,57 @@ AtapiIdentifyDevice(IN ULONG CommandPort,
          DrvParms->TMSectorCountHi,
          DrvParms->TMSectorCountLo,
          (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
+  DPRINT("SupportedFeatures83: %x, EnabledFeatures86 %x\n", DrvParms->SupportedFeatures83, DrvParms->EnabledFeatures86);
+  DPRINT("Max48BitAddress: %I64d\n", *(PULONGLONG)DrvParms->Max48BitAddress);
+  if (DrvParms->TMFieldsValid & 0x0004)
+    {
+      if ((DrvParms->UltraDmaModes >> 8) && (DrvParms->UltraDmaModes & 0xff))
+        {
+         mode = 7;
+         while (!(DrvParms->UltraDmaModes & (0x0100 << mode)))
+           {
+             mode--;
+           }
+         DPRINT("Ultra DMA mode %d is selected\n", mode);
+       }
+      else if ((DrvParms->MultiDmaModes >> 8) & (DrvParms->MultiDmaModes & 0x07))
+        {
+         mode = 2;
+         while(!(DrvParms->MultiDmaModes & (0x01 << mode)))
+           {
+             mode--;
+           }
+         DPRINT("Multi DMA mode %d is selected\n", mode);
+       }
+    }
 
-  DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
-  if (DrvParms->BytesPerSector == 0)
+  if (! Atapi && 0 != (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED))
     {
+      /* LBA ATA drives always have a sector size of 512 */
       DrvParms->BytesPerSector = 512;
     }
   else
     {
-      for (i = 15; i >= 0; i--)
-       {
-         if (DrvParms->BytesPerSector & (1 << i))
-           {
-             DrvParms->BytesPerSector = 1 << i;
-             break;
-           }
-       }
+      DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
+      if (DrvParms->BytesPerSector == 0)
+        {
+          DrvParms->BytesPerSector = 512;
+        }
+      else
+        {
+          for (i = 15; i >= 0; i--)
+            {
+              if (DrvParms->BytesPerSector & (1 << i))
+                {
+                  DrvParms->BytesPerSector = 1 << i;
+                  break;
+                }
+            }
+        }
     }
   DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
 
-  return(TRUE);
+  return TRUE;
 }
 
 
@@ -1144,39 +1562,38 @@ AtapiIdentifyDevice(IN ULONG CommandPort,
 //    PASSIVE_LEVEL
 //
 //  ARGUMENTS:
-//    IN   WORD  Address       Address of command port for drive
-//    IN   BYTE  PreComp       Value to write to precomp register
-//    IN   BYTE  SectorCnt     Value to write to sectorCnt register
-//    IN   BYTE  SectorNum     Value to write to sectorNum register
-//    IN   BYTE  CylinderLow   Value to write to CylinderLow register
-//    IN   BYTE  CylinderHigh  Value to write to CylinderHigh register
-//    IN   BYTE  DrvHead       Value to write to Drive/Head register
-//    IN   BYTE  Command       Value to write to Command register
-//    OUT  BYTE  *Buffer       Buffer for output data
+//    IN   ULONG  CommandPort   Address of command port for drive
+//    IN   ULONG  ControlPort   Address of control port for drive
+//    IN   UCHAR  PreComp       Value to write to precomp register
+//    IN   UCHAR  SectorCnt     Value to write to sectorCnt register
+//    IN   UCHAR  SectorNum     Value to write to sectorNum register
+//    IN   UCHAR  CylinderLow   Value to write to CylinderLow register
+//    IN   UCHAR  CylinderHigh  Value to write to CylinderHigh register
+//    IN   UCHAR  DrvHead       Value to write to Drive/Head register
+//    IN   UCHAR  Command       Value to write to Command register
+//    OUT  PUCHAR Buffer        Buffer for output data
 //
 //  RETURNS:
-//    int  0 is success, non 0 is an error code
+//    BOOLEAN: TRUE success, FALSE error
 //
 
-static int
+static BOOLEAN
 AtapiPolledRead(IN ULONG CommandPort,
                IN ULONG ControlPort,
-               IN BYTE PreComp,
-               IN BYTE SectorCnt,
-               IN BYTE SectorNum,
-               IN BYTE CylinderLow,
-               IN BYTE CylinderHigh,
-               IN BYTE DrvHead,
-               IN BYTE Command,
-               OUT BYTE *Buffer)
+               IN UCHAR PreComp,
+               IN UCHAR SectorCnt,
+               IN UCHAR SectorNum,
+               IN UCHAR CylinderLow,
+               IN UCHAR CylinderHigh,
+               IN UCHAR DrvHead,
+               IN UCHAR Command,
+               OUT PUCHAR Buffer)
 {
   ULONG SectorCount = 0;
   ULONG RetryCount;
   BOOLEAN Junk = FALSE;
   UCHAR Status;
-  UCHAR Control;
 
-//#if 0
   /* Wait for BUSY to clear */
   for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
     {
@@ -1192,17 +1609,15 @@ AtapiPolledRead(IN ULONG CommandPort,
   if (RetryCount >= IDE_MAX_BUSY_RETRIES)
     {
       DPRINT("Drive is BUSY for too long\n");
-      return(IDE_ER_ABRT);
+      return FALSE;
     }
-//#endif
 
   /*  Write Drive/Head to select drive  */
   IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
   ScsiPortStallExecution(500);
 
   /* Disable interrupts */
-  Control = IDEReadAltStatus(ControlPort);
-  IDEWriteDriveControl(ControlPort, Control | IDE_DC_nIEN);
+  IDEWriteDriveControl(ControlPort, IDE_DC_nIEN);
   ScsiPortStallExecution(500);
 
 #if 0
@@ -1218,7 +1633,7 @@ AtapiPolledRead(IN ULONG CommandPort,
     }
   if (RetryCount >= IDE_MAX_BUSY_RETRIES)
     {
-      return IDE_ER_ABRT;
+      return FALSE;
     }
 #endif
 
@@ -1263,17 +1678,24 @@ AtapiPolledRead(IN ULONG CommandPort,
        {
          if (Status & IDE_SR_ERR)
            {
-             IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
-             return(IDE_ER_ABRT);
+             IDEWriteDriveControl(ControlPort, 0);
+             ScsiPortStallExecution(50);
+             IDEReadStatus(CommandPort);
+
+             return FALSE;
            }
+
          if (Status & IDE_SR_DRQ)
            {
              break;
            }
          else
            {
-             IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
-             return(IDE_ER_ABRT);
+             IDEWriteDriveControl(ControlPort, 0);
+             ScsiPortStallExecution(50);
+             IDEReadStatus(CommandPort);
+
+             return FALSE;
            }
        }
       ScsiPortStallExecution(10);
@@ -1282,8 +1704,11 @@ AtapiPolledRead(IN ULONG CommandPort,
   /*  timed out  */
   if (RetryCount >= IDE_MAX_POLL_RETRIES)
     {
-      IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
-      return(IDE_ER_ABRT);
+      IDEWriteDriveControl(ControlPort, 0);
+      ScsiPortStallExecution(50);
+      IDEReadStatus(CommandPort);
+
+      return FALSE;
     }
 
   while (1)
@@ -1309,8 +1734,11 @@ AtapiPolledRead(IN ULONG CommandPort,
            {
              if (Status & IDE_SR_ERR)
                {
-                 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
-                 return(IDE_ER_ABRT);
+                 IDEWriteDriveControl(ControlPort, 0);
+                 ScsiPortStallExecution(50);
+                 IDEReadStatus(CommandPort);
+
+                 return FALSE;
                }
              if (Status & IDE_SR_DRQ)
                {
@@ -1328,8 +1756,11 @@ AtapiPolledRead(IN ULONG CommandPort,
                      DPRINT("Read %lu sectors of junk!\n",
                             SectorCount - SectorCnt);
                    }
-                 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
-                 return(0);
+                 IDEWriteDriveControl(ControlPort, 0);
+                 ScsiPortStallExecution(50);
+                 IDEReadStatus(CommandPort);
+
+                 return TRUE;
                }
            }
        }
@@ -1339,6 +1770,219 @@ AtapiPolledRead(IN ULONG CommandPort,
 
 //  -------------------------------------------  Nondiscardable statics
 
+static ULONG
+AtapiSendSmartCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
+                     IN PSCSI_REQUEST_BLOCK Srb)
+{
+  PSRB_IO_CONTROL SrbIoControl = (PSRB_IO_CONTROL)Srb->DataBuffer;
+  SENDCMDINPARAMS InParams;
+  PSENDCMDOUTPARAMS OutParams = (PSENDCMDOUTPARAMS)(SrbIoControl + 1);
+  ULONG Retries;
+  UCHAR Status;
+
+  if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS) - 1 ||
+      SrbIoControl->Length < sizeof(SENDCMDOUTPARAMS) - 1)
+    {
+      return SRB_STATUS_INVALID_REQUEST;
+    }
+  InParams = *(PSENDCMDINPARAMS)(SrbIoControl + 1);
+
+  DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x\n",
+         InParams.irDriveRegs.bFeaturesReg,
+         InParams.irDriveRegs.bSectorCountReg,
+         InParams.irDriveRegs.bSectorNumberReg,
+         InParams.irDriveRegs.bCylLowReg,
+         InParams.irDriveRegs.bCylHighReg,
+         InParams.irDriveRegs.bDriveHeadReg,
+         InParams.irDriveRegs.bCommandReg,
+         InParams.irDriveRegs.bReserved);
+
+  if (InParams.bDriveNumber > 1 ||
+      (DeviceExtension->DeviceFlags[InParams.bDriveNumber] & (DEVICE_PRESENT|DEVICE_ATAPI)) != DEVICE_PRESENT)
+    {
+      RtlZeroMemory(&OutParams, sizeof(SENDCMDOUTPARAMS));
+      OutParams->DriverStatus.bIDEError = 1;
+      return SRB_STATUS_NO_DEVICE;
+    }
+
+  DeviceExtension->DataTransferLength = 0;
+
+  switch (SrbIoControl->ControlCode)
+    {
+      case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
+        DPRINT("IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS\n");
+
+        if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS) - 1 + READ_ATTRIBUTE_BUFFER_SIZE ||
+            SrbIoControl->Length < sizeof(SENDCMDOUTPARAMS) - 1 + READ_ATTRIBUTE_BUFFER_SIZE ||
+            InParams.irDriveRegs.bFeaturesReg != READ_ATTRIBUTES ||
+            InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+            InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+            InParams.irDriveRegs.bCommandReg != SMART_CMD)
+          {
+            return SRB_STATUS_INVALID_REQUEST;            
+          }
+        InParams.irDriveRegs.bSectorCountReg = 0; 
+        InParams.irDriveRegs.bSectorNumberReg = 0;
+        DeviceExtension->DataTransferLength = READ_ATTRIBUTE_BUFFER_SIZE;
+        break;
+      
+      case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
+        DPRINT("IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS\n");
+
+        if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS) - 1 + READ_THRESHOLD_BUFFER_SIZE ||
+            SrbIoControl->Length < sizeof(SENDCMDOUTPARAMS) - 1 + READ_THRESHOLD_BUFFER_SIZE ||
+            InParams.irDriveRegs.bFeaturesReg != READ_THRESHOLDS ||
+            InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+            InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+            InParams.irDriveRegs.bCommandReg != SMART_CMD)
+          {
+            return SRB_STATUS_INVALID_REQUEST;            
+          }
+        InParams.irDriveRegs.bSectorCountReg = 0; 
+        InParams.irDriveRegs.bSectorNumberReg = 0;
+        DeviceExtension->DataTransferLength = READ_THRESHOLD_BUFFER_SIZE;
+        break;
+
+      case IOCTL_SCSI_MINIPORT_READ_SMART_LOG:
+        DPRINT("IOCTL_SCSI_MINIPORT_READ_SMART_LOG\n");
+
+        if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS) - 1 + max(1, InParams.irDriveRegs.bSectorCountReg) * SMART_LOG_SECTOR_SIZE ||
+            SrbIoControl->Length < sizeof(SENDCMDOUTPARAMS) - 1 + max(1, InParams.irDriveRegs.bSectorCountReg) * SMART_LOG_SECTOR_SIZE ||
+            InParams.irDriveRegs.bFeaturesReg != SMART_READ_LOG ||
+            InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+            InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+            InParams.irDriveRegs.bCommandReg != SMART_CMD)
+          {
+            return SRB_STATUS_INVALID_REQUEST;            
+          }
+        DeviceExtension->DataTransferLength = max(1, InParams.irDriveRegs.bSectorCountReg) * SMART_LOG_SECTOR_SIZE;
+        break;
+
+      case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
+        DPRINT("IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE\n");
+
+        if (InParams.irDriveRegs.bFeaturesReg != ENABLE_DISABLE_AUTOSAVE ||
+            (InParams.irDriveRegs.bSectorCountReg != 0 && InParams.irDriveRegs.bSectorCountReg != 1) || 
+            InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+            InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+            InParams.irDriveRegs.bCommandReg != SMART_CMD)
+          {
+            return SRB_STATUS_INVALID_REQUEST;            
+          }
+        InParams.irDriveRegs.bSectorNumberReg = 0;
+        break;
+
+      case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
+        DPRINT("IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES\n");
+
+        if (InParams.irDriveRegs.bFeaturesReg != SAVE_ATTRIBUTE_VALUES ||
+            (InParams.irDriveRegs.bSectorCountReg != 0 && InParams.irDriveRegs.bSectorCountReg != 0xf1) || 
+            InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+            InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+            InParams.irDriveRegs.bCommandReg != SMART_CMD)
+          {
+            return SRB_STATUS_INVALID_REQUEST;            
+          }
+        InParams.irDriveRegs.bSectorNumberReg = 0;
+        break;
+
+      case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
+        DPRINT("IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS\n");
+
+        if (InParams.irDriveRegs.bFeaturesReg != EXECUTE_OFFLINE_DIAGS ||
+            InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+            InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+            InParams.irDriveRegs.bCommandReg != SMART_CMD)
+          {
+            return SRB_STATUS_INVALID_REQUEST;            
+          }
+        InParams.irDriveRegs.bSectorCountReg = 0; 
+        break;
+
+      case IOCTL_SCSI_MINIPORT_ENABLE_SMART:
+        DPRINT("IOCTL_SCSI_MINIPORT_ENABLE_SMART\n");
+
+        if (InParams.irDriveRegs.bFeaturesReg != ENABLE_SMART ||
+            InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+            InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+            InParams.irDriveRegs.bCommandReg != SMART_CMD)
+          {
+            return SRB_STATUS_INVALID_REQUEST;            
+          }
+        InParams.irDriveRegs.bSectorCountReg = 0; 
+        InParams.irDriveRegs.bSectorNumberReg = 0;
+        break;
+
+      case IOCTL_SCSI_MINIPORT_DISABLE_SMART:
+        DPRINT("IOCTL_SCSI_MINIPORT_DISABLE_SMART\n");
+
+        if (InParams.irDriveRegs.bFeaturesReg != DISABLE_SMART ||
+            InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+            InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+            InParams.irDriveRegs.bCommandReg != SMART_CMD)
+          {
+            return SRB_STATUS_INVALID_REQUEST;            
+          }
+        InParams.irDriveRegs.bSectorCountReg = 0; 
+        InParams.irDriveRegs.bSectorNumberReg = 0;
+        break;
+
+      case IOCTL_SCSI_MINIPORT_RETURN_STATUS:
+        DPRINT("IOCTL_SCSI_MINIPORT_RETURN_STATUS\n");
+
+        if (InParams.irDriveRegs.bFeaturesReg != RETURN_SMART_STATUS ||
+            InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+            InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+            InParams.irDriveRegs.bCommandReg != SMART_CMD)
+          {
+            return SRB_STATUS_INVALID_REQUEST;            
+          }
+        InParams.irDriveRegs.bSectorCountReg = 0; 
+        InParams.irDriveRegs.bSectorNumberReg = 0;
+        break;
+    }
+
+  Srb->TargetId = InParams.bDriveNumber;
+  
+  /* Set pointer to data buffer. */
+  DeviceExtension->DataBuffer = (PUCHAR)OutParams->bBuffer;
+
+  DeviceExtension->CurrentSrb = Srb;
+
+  /*  wait for BUSY to clear  */
+  for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
+    {
+      Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+      if (!(Status & IDE_SR_BUSY))
+        {
+          break;
+        }
+      ScsiPortStallExecution(10);
+    }
+  if (Retries >= IDE_MAX_BUSY_RETRIES)
+    {
+      DPRINT ("Drive is BUSY for too long\n");
+      return(SRB_STATUS_BUSY);
+    }
+
+  /*  Select the desired drive  */
+  InParams.irDriveRegs.bDriveHeadReg = (InParams.bDriveNumber ? IDE_DH_DRV1 : IDE_DH_DRV0) | IDE_DH_FIXED;
+  IDEWriteDriveHead(DeviceExtension->CommandPortBase, InParams.irDriveRegs.bDriveHeadReg);
+  ScsiPortStallExecution(2);
+
+  IDEWritePrecomp(DeviceExtension->CommandPortBase, InParams.irDriveRegs.bFeaturesReg);
+  IDEWriteSectorCount(DeviceExtension->CommandPortBase, InParams.irDriveRegs.bSectorCountReg);
+  IDEWriteSectorNum(DeviceExtension->CommandPortBase, InParams.irDriveRegs.bSectorNumberReg);
+  IDEWriteCylinderLow(DeviceExtension->CommandPortBase, InParams.irDriveRegs.bCylLowReg);
+  IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, InParams.irDriveRegs.bCylHighReg);
+
+  AtapiExecuteCommand(DeviceExtension, InParams.irDriveRegs.bCommandReg, AtapiSmartInterrupt);
+
+  /* Wait for interrupt. */
+  return SRB_STATUS_PENDING;
+
+}
+
 static ULONG
 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
                      IN PSCSI_REQUEST_BLOCK Srb)
@@ -1369,12 +2013,18 @@ AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
       return(SRB_STATUS_INVALID_LUN);
     }
 
-  if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
+  if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
     {
       Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
       return(SRB_STATUS_NO_DEVICE);
     }
 
+  if (Srb->Cdb[0] == SCSIOP_MODE_SENSE)
+    {
+      Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+      return (SRB_STATUS_INVALID_REQUEST);
+    }
+
   DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
         Srb->TargetId);
 
@@ -1383,9 +2033,12 @@ AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
                        Srb));
 
   /* Set pointer to data buffer. */
-  DeviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
+  DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
+  DeviceExtension->DataTransferLength = Srb->DataTransferLength;
   DeviceExtension->CurrentSrb = Srb;
 
+  DPRINT("BufferAddress %x, BufferLength %d\n", Srb->DataBuffer, Srb->DataTransferLength);
+
   /* Wait for BUSY to clear */
   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
     {
@@ -1430,10 +2083,22 @@ AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
     }
 #endif
 
-  if (Srb->DataTransferLength < 0x10000)
+#ifdef ENABLE_DMA
+  if ((DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DMA_CMD) &&
+      (Srb->Cdb[0] == SCSIOP_READ || Srb->Cdb[0] == SCSIOP_WRITE))
+    {
+      DeviceExtension->UseDma = AtapiInitDma(DeviceExtension, Srb, Srb->SrbFlags & SRB_FLAGS_DATA_IN ? 1 << 3 : 0);
+    }
+  else
+    {
+      DeviceExtension->UseDma = FALSE;
+    }
+#endif
+
+  if (DeviceExtension->DataTransferLength < 0x10000)
     {
-      ByteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
-      ByteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8);
+      ByteCountLow = (UCHAR)(DeviceExtension->DataTransferLength & 0xFF);
+      ByteCountHigh = (UCHAR)(DeviceExtension->DataTransferLength >> 8);
     }
   else
     {
@@ -1442,14 +2107,27 @@ AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
     }
 
   /* Set feature register */
+#ifdef ENABLE_DMA
+  IDEWritePrecomp(DeviceExtension->CommandPortBase, DeviceExtension->UseDma ? 1 : 0);
+#else
   IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
+#endif
 
   /* Set command packet length */
   IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, ByteCountHigh);
   IDEWriteCylinderLow(DeviceExtension->CommandPortBase, ByteCountLow);
 
   /* Issue command to drive */
-  IDEWriteCommand(DeviceExtension->CommandPortBase, 0xA0); /* Packet command */
+#ifdef ENABLE_DMA
+  if (DeviceExtension->UseDma)
+    {
+      AtapiExecuteCommand(DeviceExtension, IDE_CMD_PACKET, AtapiDmaPacketInterrupt);
+    }
+  else
+#endif
+    {
+      AtapiExecuteCommand(DeviceExtension, IDE_CMD_PACKET, AtapiPacketInterrupt);
+    }
 
   /* Wait for DRQ to assert */
   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
@@ -1462,7 +2140,16 @@ AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
       ScsiPortStallExecution(10);
     }
 
-  CdbSize = (DeviceExtension->DeviceParams[Srb->TargetId].ConfigBits & 0x3 == 1) ? 16 : 12;
+  /* Convert special SCSI SRBs to ATAPI format */
+  switch (Srb->Cdb[0])
+    {
+      case SCSIOP_FORMAT_UNIT:
+      case SCSIOP_MODE_SELECT:
+       AtapiScsiSrbToAtapi (Srb);
+       break;
+    }
+
+  CdbSize = ((DeviceExtension->DeviceParams[Srb->TargetId].ConfigBits & 0x3) == 1) ? 16 : 12;
   DPRINT("CdbSize: %lu\n", CdbSize);
 
   /* Write command packet */
@@ -1470,9 +2157,16 @@ AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
                (PUSHORT)Srb->Cdb,
                CdbSize);
 
-  DeviceExtension->ExpectingInterrupt = TRUE;
-
-  DPRINT("AtapiSendAtapiCommand() done\n");
+#ifdef ENABLE_DMA
+  if (DeviceExtension->UseDma)
+    {
+      UCHAR DmaCommand;
+      /* start DMA */
+      DmaCommand = IDEReadDMACommand(DeviceExtension->BusMasterRegisterBase);
+      IDEWriteDMACommand(DeviceExtension->BusMasterRegisterBase, DmaCommand|0x01);
+    }
+#endif
+  DPRINT("AtapiSendAtapiCommand() done\n");
 
   return(SRB_STATUS_PENDING);
 }
@@ -1491,6 +2185,30 @@ AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
         Srb->TargetId,
         Srb->Lun);
 
+  if (Srb->PathId != 0)
+    {
+      Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
+      return(SRB_STATUS_INVALID_PATH_ID);
+    }
+
+  if (Srb->TargetId > 1)
+    {
+      Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
+      return(SRB_STATUS_INVALID_TARGET_ID);
+    }
+
+  if (Srb->Lun != 0)
+    {
+      Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+      return(SRB_STATUS_INVALID_LUN);
+    }
+
+  if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
+    {
+      Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+      return(SRB_STATUS_NO_DEVICE);
+    }
+
   switch (Srb->Cdb[0])
     {
       case SCSIOP_INQUIRY:
@@ -1509,8 +2227,18 @@ AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
                                   Srb);
        break;
 
-      case SCSIOP_MODE_SENSE:
+      case SCSIOP_SYNCHRONIZE_CACHE:
+       SrbStatus = AtapiFlushCache(DeviceExtension,
+                                   Srb);
+       break;
+
       case SCSIOP_TEST_UNIT_READY:
+       SrbStatus = AtapiTestUnitReady(DeviceExtension,
+                                      Srb);
+       break;
+
+      case SCSIOP_MODE_SENSE:
+
       case SCSIOP_VERIFY:
       case SCSIOP_START_STOP_UNIT:
       case SCSIOP_REQUEST_SENSE:
@@ -1535,56 +2263,28 @@ AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
 {
   PIDE_DRIVE_IDENTIFY DeviceParams;
   PINQUIRYDATA InquiryData;
-  ULONG i;
 
   DPRINT("SCSIOP_INQUIRY: DeviceExtension %p  TargetId: %lu\n",
         DeviceExtension, Srb->TargetId);
 
-  if (Srb->PathId != 0)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
-      return(SRB_STATUS_INVALID_PATH_ID);
-    }
-
-  if (Srb->TargetId > 1)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
-      return(SRB_STATUS_INVALID_TARGET_ID);
-    }
-
-  if (Srb->Lun != 0)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
-      return(SRB_STATUS_INVALID_LUN);
-    }
-
-  if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
-    {
-      Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
-      return(SRB_STATUS_NO_DEVICE);
-    }
-
   InquiryData = Srb->DataBuffer;
   DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
 
   /* clear buffer */
-  for (i = 0; i < Srb->DataTransferLength; i++)
-    {
-      ((PUCHAR)Srb->DataBuffer)[i] = 0;
-    }
+  memset(Srb->DataBuffer, 0, Srb->DataTransferLength);
 
   /* set device class */
-  if (DeviceExtension->DeviceAtapi[Srb->TargetId] == FALSE)
-    {
-      /* hard-disk */
-      InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
-    }
-  else
+  if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
     {
       /* get it from the ATAPI configuration word */
       InquiryData->DeviceType = (DeviceParams->ConfigBits >> 8) & 0x1F;
       DPRINT("Device class: %u\n", InquiryData->DeviceType);
     }
+  else
+    {
+      /* hard-disk */
+      InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
+    }
 
   DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
   if (DeviceParams->ConfigBits & 0x80)
@@ -1593,26 +2293,15 @@ AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
       InquiryData->RemovableMedia = 1;
     }
 
-  for (i = 0; i < 20; i += 2)
-    {
-      InquiryData->VendorId[i] =
-       ((PUCHAR)DeviceParams->ModelNumber)[i];
-      InquiryData->VendorId[i+1] =
-       ((PUCHAR)DeviceParams->ModelNumber)[i+1];
-    }
+  memcpy(InquiryData->VendorId, DeviceParams->ModelNumber, 20);
+  IDESwapBytePairs(InquiryData->VendorId, 20);
 
-  for (i = 0; i < 4; i++)
-    {
-      InquiryData->ProductId[12+i] = ' ';
-    }
+  memcpy(&InquiryData->ProductId[12], "    ", 4);
 
-  for (i = 0; i < 4; i += 2)
-    {
-      InquiryData->ProductRevisionLevel[i] =
-       ((PUCHAR)DeviceParams->FirmwareRev)[i];
-      InquiryData->ProductRevisionLevel[i+1] =
-       ((PUCHAR)DeviceParams->FirmwareRev)[i+1];
-    }
+  memcpy(InquiryData->ProductRevisionLevel, DeviceParams->FirmwareRev, 4);
+  IDESwapBytePairs(InquiryData->ProductRevisionLevel, 4);
+
+  InquiryData->AdditionalLength = 31;
 
   DPRINT("VendorId: '%.20s'\n", InquiryData->VendorId);
 
@@ -1627,34 +2316,9 @@ AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
 {
   PREAD_CAPACITY_DATA CapacityData;
   PIDE_DRIVE_IDENTIFY DeviceParams;
-  ULONG LastSector;
+  LARGE_INTEGER LastSector;
 
   DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
-
-  if (Srb->PathId != 0)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
-      return(SRB_STATUS_INVALID_PATH_ID);
-    }
-
-  if (Srb->TargetId > 1)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
-      return(SRB_STATUS_INVALID_TARGET_ID);
-    }
-
-  if (Srb->Lun != 0)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
-      return(SRB_STATUS_INVALID_LUN);
-    }
-
-  if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
-    {
-      Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
-      return(SRB_STATUS_NO_DEVICE);
-    }
-
   CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
   DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
 
@@ -1664,14 +2328,33 @@ AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
   /* Calculate last sector (big-endian). */
   if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
     {
-      LastSector = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
-                           DeviceParams->TMSectorCountLo) - 1;
+      if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
+        {
+         ((PUSHORT)&LastSector)[0] = DeviceParams->Max48BitAddress[0];
+         ((PUSHORT)&LastSector)[1] = DeviceParams->Max48BitAddress[1];
+         ((PUSHORT)&LastSector)[2] = DeviceParams->Max48BitAddress[2];
+         ((PUSHORT)&LastSector)[3] = DeviceParams->Max48BitAddress[3];
+         LastSector.QuadPart -= 1;
+
+       }
+      else
+        {
+         LastSector.u.HighPart = 0;
+          LastSector.u.LowPart = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
+                                        DeviceParams->TMSectorCountLo)-1;
+       }
     }
   else
     {
-      LastSector = (ULONG)(DeviceParams->LogicalCyls *
-                          DeviceParams->LogicalHeads *
-                          DeviceParams->SectorsPerTrack)-1;
+      LastSector.u.HighPart = 0;
+      LastSector.u.LowPart = (ULONG)(DeviceParams->LogicalCyls *
+                                    DeviceParams->LogicalHeads *
+                                    DeviceParams->SectorsPerTrack)-1;
+    }
+  if (LastSector.u.HighPart)
+    {
+      DPRINT1("Disk is too large for our implementation (%I64d sectors\n", LastSector.QuadPart);
+      KEBUGCHECK(0);
     }
 
   CapacityData->LogicalBlockAddress = (((PUCHAR)&LastSector)[0] << 24) |
@@ -1696,40 +2379,16 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
   PIDE_DRIVE_IDENTIFY DeviceParams;
   ULONG StartingSector;
   ULONG SectorCount;
-  UCHAR CylinderHigh;
-  UCHAR CylinderLow;
+  UCHAR CylinderHigh[2];
+  UCHAR CylinderLow[2];
   UCHAR DrvHead;
-  UCHAR SectorNumber;
+  UCHAR SectorNumber[2];
   UCHAR Command;
   ULONG Retries;
   UCHAR Status;
+  BOOLEAN (FASTCALL *Handler)(PATAPI_MINIPORT_EXTENSION DevExt);
 
   DPRINT("AtapiReadWrite() called!\n");
-
-  if (Srb->PathId != 0)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
-      return(SRB_STATUS_INVALID_PATH_ID);
-    }
-
-  if (Srb->TargetId > 1)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
-      return(SRB_STATUS_INVALID_TARGET_ID);
-    }
-
-  if (Srb->Lun != 0)
-    {
-      Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
-      return(SRB_STATUS_INVALID_LUN);
-    }
-
-  if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
-    {
-      Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
-      return(SRB_STATUS_NO_DEVICE);
-    }
-
   DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
         Srb->TargetId);
 
@@ -1749,68 +2408,77 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
         Srb->DataTransferLength,
         SectorCount);
 
-  if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
-    {
-      SectorNumber = StartingSector & 0xff;
-      CylinderLow = (StartingSector >> 8) & 0xff;
-      CylinderHigh = (StartingSector >> 16) & 0xff;
-      DrvHead = ((StartingSector >> 24) & 0x0f) | 
-          (Srb->TargetId ? IDE_DH_DRV1 : 0) |
-          IDE_DH_LBA;
-    }
-  else
-    {
-      SectorNumber = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
-      StartingSector /= DeviceParams->SectorsPerTrack;
-      DrvHead = (StartingSector % DeviceParams->LogicalHeads) | 
-          (Srb->TargetId ? IDE_DH_DRV1 : 0);
-      StartingSector /= DeviceParams->LogicalHeads;
-      CylinderLow = StartingSector & 0xff;
-      CylinderHigh = StartingSector >> 8;
-    }
-
-
-  if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
+  if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
     {
-      Command = IDE_CMD_READ;
+      SectorNumber[0] = StartingSector & 0xff;
+      CylinderLow[0] = (StartingSector >> 8) & 0xff;
+      CylinderHigh[0] = (StartingSector >> 16) & 0xff;
+      SectorNumber[1] = (StartingSector >> 24) & 0xff;
+      CylinderLow[1] = 0;
+      CylinderHigh[1] = 0;
+      DrvHead = (Srb->TargetId ? IDE_DH_DRV1 : 0) | IDE_DH_LBA;
+#if 0
+      DPRINT("%s:BUS=%04x:DRV=%d:LBA48=1:BLK=%08d:SC=%02x:CM=%02x\n",
+            (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
+            DeviceExtension->CommandPortBase,
+            DrvHead & IDE_DH_DRV1 ? 1 : 0,
+            (SectorNumber[1] << 24) +
+            (CylinderHigh[0] << 16) + (CylinderLow[0] << 8) + DectorNumberLow[0],
+            SectorCount,
+            Command);
+#endif
     }
-  else
+  else if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
     {
-      Command = IDE_CMD_WRITE;
-    }
+      SectorNumber[0] = StartingSector & 0xff;
+      CylinderLow[0] = (StartingSector >> 8) & 0xff;
+      CylinderHigh[0] = (StartingSector >> 16) & 0xff;
+      SectorNumber[1] = 0;
+      CylinderLow[1] = 0;
+      CylinderHigh[1] = 0;
+      DrvHead = ((StartingSector >> 24) & 0x0f) |
+                 (Srb->TargetId ? IDE_DH_DRV1 : 0) |
+                IDE_DH_LBA;
 
-  if (DrvHead & IDE_DH_LBA)
-    {
       DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
             (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
             DeviceExtension->CommandPortBase,
             DrvHead & IDE_DH_DRV1 ? 1 : 0,
             ((DrvHead & 0x0f) << 24) +
-              (CylinderHigh << 16) + (CylinderLow << 8) + SectorNumber,
+            (CylinderHigh[0] << 16) + (CylinderLow[0] << 8) + SectorNumber[0],
             SectorCount,
             Command);
     }
   else
     {
+      SectorNumber[0] = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
+      StartingSector /= DeviceParams->SectorsPerTrack;
+      DrvHead = (StartingSector % DeviceParams->LogicalHeads) |
+          (Srb->TargetId ? IDE_DH_DRV1 : 0);
+      StartingSector /= DeviceParams->LogicalHeads;
+      CylinderLow[0] = StartingSector & 0xff;
+      CylinderHigh[0] = StartingSector >> 8;
+      SectorNumber[1] = 0;
+      CylinderLow[1] = 0;
+      CylinderHigh[1] = 0;
+
       DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
              (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
              DeviceExtension->CommandPortBase,
-             DrvHead & IDE_DH_DRV1 ? 1 : 0, 
-             CylinderHigh,
-             CylinderLow,
+             DrvHead & IDE_DH_DRV1 ? 1 : 0,
+             CylinderHigh[0],
+             CylinderLow[0],
              DrvHead & 0x0f,
-             SectorNumber,
+             SectorNumber[0],
              SectorCount,
              Command);
     }
 
   /* Set pointer to data buffer. */
-  DeviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
+  DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
+  DeviceExtension->DataTransferLength = Srb->DataTransferLength;
 
   DeviceExtension->CurrentSrb = Srb;
-  DeviceExtension->ExpectingInterrupt = TRUE;
-
-
 
   /*  wait for BUSY to clear  */
   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
@@ -1828,24 +2496,6 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
     {
       DPRINT ("Drive is BUSY for too long\n");
       return(SRB_STATUS_BUSY);
-#if 0
-      if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
-        {
-          DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
-          Irp = ControllerExtension->CurrentIrp;
-          Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
-          Irp->IoStatus.Information = 0;
-
-          return FALSE;
-        }
-      else
-        {
-          DPRINT ("Beginning drive reset sequence\n");
-          IDEBeginControllerReset(ControllerExtension);
-
-          return TRUE;
-        }
-#endif
     }
 
   /*  Select the desired drive  */
@@ -1869,91 +2519,132 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
     {
       DPRINT("Drive is BUSY for too long after drive select\n");
       return(SRB_STATUS_BUSY);
-#if 0
-      if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
-       {
-          DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
-          Irp = ControllerExtension->CurrentIrp;
-          Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
-          Irp->IoStatus.Information = 0;
-
-          return FALSE;
-       }
-      else
-        {
-          DPRINT("Beginning drive reset sequence\n");
-          IDEBeginControllerReset(ControllerExtension);
-
-          return TRUE;
-        }
-#endif
     }
 #endif
 
-  /* Indicate expecting an interrupt. */
-  DeviceExtension->ExpectingInterrupt = TRUE;
-
   /* Setup command parameters */
-  IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
-  IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount);
-  IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber);
-  IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh);
-  IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow);
-  IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
+  if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
+    {
+      IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
+      IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount >> 8);
+      IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber[1]);
+      IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow[1]);
+      IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh[1]);
+    }
 
-  /* Issue command to drive */
-  IDEWriteCommand(DeviceExtension->CommandPortBase, Command);
+  IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
+  IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount & 0xff);
+  IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber[0]);
+  IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow[0]);
+  IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh[0]);
 
-  /* Write data block */
-  if (Command == IDE_CMD_WRITE)
+#ifdef ENABLE_DMA
+  if (DeviceExtension->PRDTable &&
+      DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DMA_CMD)
     {
-      PUCHAR TargetAddress;
-      ULONG SectorSize;
-
-      /* Wait for controller ready */
-      for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
-       {
-         BYTE  Status = IDEReadStatus(DeviceExtension->CommandPortBase);
-         if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
+      DeviceExtension->UseDma = AtapiInitDma(DeviceExtension, Srb, Srb->SrbFlags & SRB_FLAGS_DATA_IN ? 1 << 3 : 0);
+    }
+  if (DeviceExtension->UseDma)
+    {
+      Handler = AtapiDmaInterrupt;
+      if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
+        {
+         Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_DMA_EXT : IDE_CMD_WRITE_DMA_EXT;
+       }
+      else
+        {
+          Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_DMA : IDE_CMD_WRITE_DMA;
+       }
+    }
+  else
+#endif
+    {
+      Handler = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? AtapiReadInterrupt : AtapiWriteInterrupt;
+      if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MULTI_SECTOR_CMD)
+        {
+          if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
            {
-             break;
+              Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_MULTIPLE_EXT : IDE_CMD_WRITE_MULTIPLE_EXT;
+           }
+         else
+           {
+              Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_MULTIPLE : IDE_CMD_WRITE_MULTIPLE;
            }
-         KeStallExecutionProcessor(10);
        }
-      if (Retries >= IDE_MAX_BUSY_RETRIES)
-       {
-         DPRINT("Drive is BUSY for too long after sending write command\n");
-         return(SRB_STATUS_BUSY);
-#if 0
-          if (DeviceExtension->Retries++ > IDE_MAX_CMD_RETRIES)
-            {
-              Irp = ControllerExtension->CurrentIrp;
-              Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
-              Irp->IoStatus.Information = 0;
+      else
+        {
+          if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
+           {
+             Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_EXT : IDE_CMD_WRITE_EXT;
+           }
+         else
+           {
+             Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ : IDE_CMD_WRITE;
+           }
+       }
+    }
 
-              return FALSE;
-            }
-          else
-            {
-              IDEBeginControllerReset(ControllerExtension);
+  AtapiExecuteCommand(DeviceExtension, Command, Handler);
 
-              return TRUE;
-            }
+#ifdef ENABLE_DMA
+  if (DeviceExtension->UseDma)
+    {
+      UCHAR DmaCommand;
+      /* start DMA */
+      DmaCommand = IDEReadDMACommand(DeviceExtension->BusMasterRegisterBase);
+      IDEWriteDMACommand(DeviceExtension->BusMasterRegisterBase, DmaCommand|0x01);
+    }
+  else
 #endif
-       }
+    {
+      if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
+        {
+          /* Write data block */
+          PUCHAR TargetAddress;
+          ULONG TransferSize;
 
-      /* Update SRB data */
-      SectorSize = DeviceExtension->DeviceParams[Srb->TargetId].BytesPerSector;
-      TargetAddress = Srb->DataBuffer;
-      Srb->DataBuffer += SectorSize;
-      Srb->DataTransferLength -= SectorSize;
+          /* Wait for controller ready */
+          for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
+           {
+             UCHAR  Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+             if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
+               {
+                 break;
+               }
+             ScsiPortStallExecution(10);
+           }
+          if (Retries >= IDE_MAX_WRITE_RETRIES)
+           {
+             DPRINT1("Drive is BUSY for too long after sending write command\n");
+             return(SRB_STATUS_BUSY);
+           }
 
-      /* Write data block */
-      IDEWriteBlock(DeviceExtension->CommandPortBase,
-                   TargetAddress,
-                   SectorSize);
-    }
+          /* Update DeviceExtension data */
+          TransferSize = DeviceExtension->TransferSize[Srb->TargetId];
+          if (DeviceExtension->DataTransferLength < TransferSize)
+           {
+             TransferSize = DeviceExtension->DataTransferLength;
+           }
 
+          TargetAddress = DeviceExtension->DataBuffer;
+          DeviceExtension->DataBuffer += TransferSize;
+          DeviceExtension->DataTransferLength -= TransferSize;
+
+          /* Write data block */
+          if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
+           {
+             IDEWriteBlock32(DeviceExtension->CommandPortBase,
+                             TargetAddress,
+                             TransferSize);
+           }
+          else
+           {
+             IDEWriteBlock(DeviceExtension->CommandPortBase,
+                           TargetAddress,
+                           TransferSize);
+           }
+       }
+    }
 
   DPRINT("AtapiReadWrite() done!\n");
 
@@ -1962,27 +2653,180 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
 }
 
 
-static UCHAR
-AtapiErrorToScsi(PVOID DeviceExtension,
-                PSCSI_REQUEST_BLOCK Srb)
+static ULONG
+AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+               PSCSI_REQUEST_BLOCK Srb)
 {
-  PATAPI_MINIPORT_EXTENSION DevExt;
-  ULONG CommandPortBase;
-  ULONG ControlPortBase;
-  UCHAR ErrorReg;
-  UCHAR ScsiStatus;
-  UCHAR SrbStatus;
+  ULONG Retries;
+  UCHAR Status;
 
-  DPRINT("AtapiErrorToScsi() called\n");
+  DPRINT("AtapiFlushCache() called!\n");
+  DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
+        Srb->TargetId);
 
-  DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
+  if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_NO_FLUSH)
+    {
+      /*
+       * NOTE: Don't flush the cache for CD/DVD drives. Although
+       * the ATAPI-6 standard allows that, it has been experimentally
+       * proved that it can damage some broken LG drives. Afterall
+       * it doesn't make sense to flush cache on devices we don't
+       * write to.
+       */
+       
+      /* The device states it doesn't support the command or it is disabled */      
+      DPRINT("The drive doesn't support FLUSH_CACHE\n");
+      return SRB_STATUS_INVALID_REQUEST;
+    }
+
+  /* Wait for BUSY to clear */
+  for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
+    {
+      Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+      if (!(Status & IDE_SR_BUSY))
+        {
+          break;
+        }
+      ScsiPortStallExecution(10);
+    }
+  DPRINT("Status=%02x\n", Status);
+  DPRINT("Waited %ld usecs for busy to clear\n", Retries * 10);
+  if (Retries >= IDE_MAX_BUSY_RETRIES)
+    {
+      DPRINT1("Drive is BUSY for too long\n");
+      return(SRB_STATUS_BUSY);
+    }
+
+  /* Select the desired drive */
+  IDEWriteDriveHead(DeviceExtension->CommandPortBase,
+                   IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
+  ScsiPortStallExecution(10);
+
+  /* Issue command to drive */
+  AtapiExecuteCommand(DeviceExtension,
+                     DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS ? IDE_CMD_FLUSH_CACHE_EXT : IDE_CMD_FLUSH_CACHE,
+                     AtapiNoDataInterrupt);
+
+
+  DPRINT("AtapiFlushCache() done!\n");
+
+  /* Wait for interrupt. */
+  return(SRB_STATUS_PENDING);
+}
+
+
+static ULONG
+AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+                  PSCSI_REQUEST_BLOCK Srb)
+{
+  ULONG Retries;
+  UCHAR Status;
+  UCHAR Error;
+
+  DPRINT1("AtapiTestUnitReady() called!\n");
+
+  DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
+        Srb->TargetId);
+
+  /* Return success if media status is not supported */
+  if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MEDIA_STATUS))
+    {
+      Srb->SrbStatus = SRB_STATUS_SUCCESS;
+      return(SRB_STATUS_SUCCESS);
+    }
+
+  /* Wait for BUSY to clear */
+  for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
+    {
+      Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+      if (!(Status & IDE_SR_BUSY))
+        {
+          break;
+        }
+      ScsiPortStallExecution(10);
+    }
+  DPRINT1("Status=%02x\n", Status);
+  DPRINT1("Waited %ld usecs for busy to clear\n", Retries * 10);
+  if (Retries >= IDE_MAX_BUSY_RETRIES)
+    {
+      DPRINT1("Drive is BUSY for too long\n");
+      return(SRB_STATUS_BUSY);
+    }
+
+  /* Select the desired drive */
+  IDEWriteDriveHead(DeviceExtension->CommandPortBase,
+                   IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
+  ScsiPortStallExecution(10);
+
+  /* Issue command to drive */
+  AtapiExecuteCommand(DeviceExtension, IDE_CMD_GET_MEDIA_STATUS, AtapiNoDataInterrupt);
+
+  /* Wait for controller ready */
+  for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
+    {
+      Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+      if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
+       {
+         break;
+       }
+      ScsiPortStallExecution(10);
+    }
+  if (Retries >= IDE_MAX_WRITE_RETRIES)
+    {
+      DPRINT1("Drive is BUSY for too long after sending write command\n");
+      DeviceExtension->Handler = NULL;
+      return(SRB_STATUS_BUSY);
+    }
+
+  if (Status & IDE_SR_ERR)
+    {
+      Error = IDEReadError(DeviceExtension->CommandPortBase);
+      if (Error == IDE_ER_UNC)
+       {
+CHECKPOINT1;
+         /* Handle write protection 'error' */
+         Srb->SrbStatus = SRB_STATUS_SUCCESS;
+          DeviceExtension->Handler = NULL;
+         return(SRB_STATUS_SUCCESS);
+       }
+      else
+       {
+CHECKPOINT1;
+         /* Indicate expecting an interrupt. */
+         return(SRB_STATUS_PENDING);
+       }
+    }
+
+  DeviceExtension->Handler = NULL;
+
+  DPRINT1("AtapiTestUnitReady() done!\n");
+
+  Srb->SrbStatus = SRB_STATUS_SUCCESS;
+  return(SRB_STATUS_SUCCESS);
+}
+
+
+static UCHAR
+AtapiErrorToScsi(PVOID DeviceExtension,
+                PSCSI_REQUEST_BLOCK Srb)
+{
+  PATAPI_MINIPORT_EXTENSION DevExt;
+  ULONG CommandPortBase;
+  ULONG ControlPortBase;
+  UCHAR ErrorReg;
+  UCHAR ScsiStatus;
+  UCHAR SrbStatus;
+
+  DPRINT("AtapiErrorToScsi() called\n");
+
+  DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
 
   CommandPortBase = DevExt->CommandPortBase;
   ControlPortBase = DevExt->ControlPortBase;
 
   ErrorReg = IDEReadError(CommandPortBase);
 
-  if (DevExt->DeviceAtapi[Srb->TargetId])
+  if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
     {
       switch (ErrorReg >> 4)
        {
@@ -2088,4 +2932,620 @@ AtapiErrorToScsi(PVOID DeviceExtension,
   return(SrbStatus);
 }
 
+
+static VOID
+AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb)
+{
+  DPRINT("AtapiConvertScsiToAtapi() called\n");
+
+  Srb->CdbLength = 12;
+
+  switch (Srb->Cdb[0])
+    {
+      case SCSIOP_FORMAT_UNIT:
+       Srb->Cdb[0] = ATAPI_FORMAT_UNIT;
+       break;
+
+      case SCSIOP_MODE_SELECT:
+         {
+           PATAPI_MODE_SELECT12 AtapiModeSelect;
+           UCHAR Length;
+
+           AtapiModeSelect = (PATAPI_MODE_SELECT12)Srb->Cdb;
+           Length = ((PCDB)Srb->Cdb)->MODE_SELECT.ParameterListLength;
+
+           RtlZeroMemory (Srb->Cdb,
+                          MAXIMUM_CDB_SIZE);
+           AtapiModeSelect->OperationCode = ATAPI_MODE_SELECT;
+           AtapiModeSelect->PFBit = 1;
+           AtapiModeSelect->ParameterListLengthMsb = 0;
+           AtapiModeSelect->ParameterListLengthLsb = Length;
+         }
+       break;
+    }
+}
+
+static VOID FASTCALL
+AtapiCompleteRequest(PATAPI_MINIPORT_EXTENSION DevExt,
+                    UCHAR SrbStatus)
+{
+  PSCSI_REQUEST_BLOCK Srb;
+  Srb = DevExt->CurrentSrb;
+
+  DPRINT("AtapiCompleteRequest(DevExt %x, SrbStatus %x)\n", DevExt, SrbStatus);
+
+  Srb->SrbStatus = SrbStatus;
+  if (SrbStatus == SRB_STATUS_ERROR)
+    {
+      Srb->SrbStatus = AtapiErrorToScsi((PVOID)DevExt, Srb);
+    }
+  else if (SrbStatus == SRB_STATUS_DATA_OVERRUN)
+    {
+      Srb->DataTransferLength -= DevExt->DataTransferLength;
+    }
+
+  DevExt->Handler = NULL;
+  ScsiPortNotification(RequestComplete, (PVOID)DevExt, Srb);
+  ScsiPortNotification(NextRequest, (PVOID)DevExt, NULL);
+}
+
+#ifdef ENABLE_DMA
+static BOOLEAN FASTCALL
+AtapiDmaPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
+{
+  UCHAR SrbStatus;
+  UCHAR DmaCommand;
+  UCHAR DmaStatus;
+  UCHAR Status;
+  UCHAR Error;
+  UCHAR SensKey;
+
+  DPRINT("AtapiPacketDmaInterrupt\n");
+
+  DevExt->UseDma = FALSE;
+
+  /* stop DMA */
+  DmaCommand = IDEReadDMACommand(DevExt->BusMasterRegisterBase);
+  IDEWriteDMACommand(DevExt->BusMasterRegisterBase, DmaCommand & 0xfe);
+  /* get DMA status */
+  DmaStatus = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
+  /* clear the INTR & ERROR bits */
+  IDEWriteDMAStatus(DevExt->BusMasterRegisterBase, DmaStatus | 0x06);
+
+  Status = IDEReadStatus(DevExt->CommandPortBase);
+  DPRINT("DriveStatus: %x\n", Status);
+
+  if (Status & (IDE_SR_BUSY|IDE_SR_ERR))
+    {
+      if (Status & IDE_SR_ERR)
+        {
+         Error = IDEReadError(DevExt->CommandPortBase);
+         SensKey = Error >> 4;
+         DPRINT("DriveError: %x, SenseKey: %x\n", Error, SensKey);
+       }
+      SrbStatus = SRB_STATUS_ERROR;
+    }
+  else
+    {
+      if ((DmaStatus & 0x07) != 0x04)
+        {
+          DPRINT("DmaStatus: %02x\n", DmaStatus);
+          SrbStatus = SRB_STATUS_ERROR;
+       }
+      else
+        {
+         SrbStatus = STATUS_SUCCESS;
+       }
+    }
+  AtapiCompleteRequest(DevExt, SrbStatus);
+  DPRINT("AtapiDmaPacketInterrupt() done\n");
+  return TRUE;
+}
+#endif
+
+static BOOLEAN FASTCALL
+AtapiPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
+{
+  PSCSI_REQUEST_BLOCK Srb;
+  UCHAR Status;
+  UCHAR IntReason;
+  ULONG TransferSize;
+  ULONG JunkSize = 0;
+  BOOLEAN IsLastBlock;
+  PUCHAR TargetAddress;
+  ULONG Retries;
+  UCHAR SrbStatus;
+  UCHAR Error;
+  UCHAR SensKey;
+
+  DPRINT("AtapiPacketInterrupt()\n");
+
+  Srb = DevExt->CurrentSrb;
+
+  Status = IDEReadStatus(DevExt->CommandPortBase);
+  DPRINT("DriveStatus: %x\n", Status);
+
+  if (Status & (IDE_SR_BUSY|IDE_SR_ERR))
+    {
+      if (Status & IDE_SR_ERR)
+        {
+         Error = IDEReadError(DevExt->CommandPortBase);
+         SensKey = Error >> 4;
+         DPRINT("DriveError: %x, SenseKey: %x\n", Error, SensKey);
+       }
+
+      AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
+      DPRINT("AtapiPacketInterrupt() done\n");
+      return TRUE;
+    }
+
+  IntReason = IDEReadSectorCount(DevExt->CommandPortBase);
+  TransferSize = IDEReadCylinderLow(DevExt->CommandPortBase);
+  TransferSize += IDEReadCylinderHigh(DevExt->CommandPortBase) << 8;
+
+  if (!(Status & IDE_SR_DRQ))
+    {
+      if (DevExt->DataTransferLength > 0)
+        {
+         DPRINT1("AtapiPacketInterrupt: data underrun (%d bytes), command was %02x\n",
+                 DevExt->DataTransferLength, Srb->Cdb[0]);
+         SrbStatus = SRB_STATUS_DATA_OVERRUN;
+       }
+      else
+        {
+         SrbStatus = SRB_STATUS_SUCCESS;
+       }
+      AtapiCompleteRequest(DevExt, SrbStatus);
+      DPRINT("AtapiPacketInterrupt() done\n");
+      return TRUE;
+    }
+
+  TargetAddress = DevExt->DataBuffer;
+
+  if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
+    {
+      DPRINT("read data\n");
+      if (DevExt->DataTransferLength <= TransferSize)
+        {
+         JunkSize = TransferSize - DevExt->DataTransferLength;
+         TransferSize = DevExt->DataTransferLength;
+
+         DevExt->DataTransferLength = 0;
+         IsLastBlock = TRUE;
+       }
+      else
+       {
+         DevExt->DataTransferLength -= TransferSize;
+         IsLastBlock = FALSE;
+       }
+
+      DPRINT("TargetAddress %x, TransferSize %d\n", TargetAddress, TransferSize);
+
+      DevExt->DataBuffer += TransferSize;
+
+      IDEReadBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
+
+      /* check DRQ */
+      if (IsLastBlock)
+        {
+         /* Read remaining junk from device */
+         while (JunkSize > 0)
+           {
+             IDEReadWord(DevExt->CommandPortBase);
+             JunkSize -= 2;
+           }
+
+         for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES && (IDEReadStatus(DevExt->CommandPortBase) & IDE_SR_BUSY); Retries++)
+           {
+             ScsiPortStallExecution(10);
+           }
+
+         /* Check for data overrun */
+         while (IDEReadStatus(DevExt->CommandPortBase) & IDE_SR_DRQ)
+           {
+             DPRINT1("AtapiInterrupt(): reading overrun data!\n");
+             IDEReadWord(DevExt->CommandPortBase);
+           }
+       }
+
+      SrbStatus = SRB_STATUS_SUCCESS;
+    }
+  else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
+    {
+      DPRINT("write data\n");
+      if (DevExt->DataTransferLength < TransferSize)
+        {
+         TransferSize = DevExt->DataTransferLength;
+       }
+
+      TargetAddress = DevExt->DataBuffer;
+
+      DPRINT("TargetAddress %x, TransferSize %x\n", TargetAddress, TransferSize);
+
+      DevExt->DataBuffer += TransferSize;
+      DevExt->DataTransferLength -= TransferSize;
+
+      /* Write the sector */
+      IDEWriteBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
+      SrbStatus = SRB_STATUS_SUCCESS;
+      IsLastBlock = FALSE;
+    }
+  else
+    {
+      DPRINT("Unspecified transfer direction!\n");
+      SrbStatus = SRB_STATUS_SUCCESS;
+      IsLastBlock = TRUE;
+    }
+  if (IsLastBlock)
+    {
+      AtapiCompleteRequest(DevExt, SrbStatus);
+    }
+  DPRINT("AtapiPacketInterrupt() done\n");
+  return TRUE;
+}
+
+static BOOLEAN FASTCALL
+AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
+{
+  UCHAR Status;
+
+  DPRINT("AtapiNoDataInterrupt()\n");
+
+  Status = IDEReadStatus(DevExt->CommandPortBase);
+  AtapiCompleteRequest(DevExt,
+                       (Status & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_DRQ)) == IDE_SR_DRDY ? SRB_STATUS_SUCCESS : SRB_STATUS_ERROR);
+
+  DPRINT("AtapiNoDatanterrupt() done!\n");
+  return TRUE;
+}
+
+#ifdef ENABLE_DMA
+static BOOLEAN FASTCALL
+AtapiDmaInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
+{
+  UCHAR DmaCommand;
+  UCHAR DmaStatus;
+  UCHAR Status;
+
+  DPRINT("AtapiDmaInterrupt()\n");
+
+  DevExt->UseDma = FALSE;
+  /* stop DMA */
+  DmaCommand = IDEReadDMACommand(DevExt->BusMasterRegisterBase);
+  IDEWriteDMACommand(DevExt->BusMasterRegisterBase, DmaCommand & 0xfe);
+  /* get DMA status */
+  DmaStatus = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
+  /* clear the INTR & ERROR bits */
+  IDEWriteDMAStatus(DevExt->BusMasterRegisterBase, DmaStatus | 0x06);
+
+  /* read the drive status */
+  Status = IDEReadStatus(DevExt->CommandPortBase);
+  if ((Status & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_WERR|IDE_SR_DRQ)) == IDE_SR_DRDY &&
+      (DmaStatus & 0x07) == 4)
+    {
+      AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
+      DPRINT("AtapiDmaInterrupt() done\n");
+      return TRUE;
+    }
+  DPRINT1("Status %x\n", Status);
+  DPRINT1("%x\n", DmaStatus);
+  AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
+  DPRINT1("AtapiDmaReadInterrupt() done\n");
+  return TRUE;
+}
+#endif
+
+static BOOLEAN FASTCALL
+AtapiSmartInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
+{
+  PSCSI_REQUEST_BLOCK Srb;
+  UCHAR DeviceStatus;
+  PSRB_IO_CONTROL SrbIoControl;
+  PSENDCMDOUTPARAMS OutParams;
+  PIDEREGS IdeRegs;
+
+  DPRINT("AtapiSmartInterrupt() called!\n");
+
+  Srb = DevExt->CurrentSrb;
+
+
+  DeviceStatus = IDEReadStatus(DevExt->CommandPortBase);
+  if ((DeviceStatus & (IDE_SR_DRQ|IDE_SR_BUSY|IDE_SR_ERR)) != (DevExt->DataTransferLength ? IDE_SR_DRQ : 0))
+    {
+      if (DeviceStatus & (IDE_SR_ERR|IDE_SR_DRQ))
+        {
+         AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
+          DPRINT("AtapiSmartInterrupt() done!\n");
+         return TRUE;
+        }
+      DPRINT("AtapiSmartInterrupt() done!\n");
+      return FALSE;
+    }
+
+  DPRINT("CommandPortBase: %lx  ControlPortBase: %lx\n", DevExt->CommandPortBase, DevExt->ControlPortBase);
+
+  if (DevExt->DataTransferLength)
+    {
+      IDEReadBlock(DevExt->CommandPortBase, DevExt->DataBuffer, 512);
+      DevExt->DataTransferLength -= 512;
+      DevExt->DataBuffer += 512;
+    }
+
+  if (DevExt->DataTransferLength == 0)
+    {
+      SrbIoControl = (PSRB_IO_CONTROL)Srb->DataBuffer;
+      OutParams = (PSENDCMDOUTPARAMS)(SrbIoControl + 1);
+
+      OutParams->DriverStatus.bDriverError = 0;
+      OutParams->DriverStatus.bIDEError = 0;
+
+      if (SrbIoControl->ControlCode == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
+        {
+          IdeRegs = (PIDEREGS)OutParams->bBuffer;
+
+          IdeRegs->bFeaturesReg = RETURN_SMART_STATUS;
+          IdeRegs->bSectorCountReg = IDEReadSectorCount(DevExt->CommandPortBase);
+          IdeRegs->bSectorNumberReg = IDEReadSectorNum(DevExt->CommandPortBase);
+          IdeRegs->bCylLowReg = IDEReadCylinderLow(DevExt->CommandPortBase);
+          IdeRegs->bCylHighReg = IDEReadCylinderHigh(DevExt->CommandPortBase);
+          IdeRegs->bDriveHeadReg = IDEReadDriveHead(DevExt->CommandPortBase);
+          IdeRegs->bCommandReg = SMART_CMD;
+          IdeRegs->bReserved = 0;
+
+          OutParams->cBufferSize = 8;
+        }
+      else
+        {
+          OutParams->cBufferSize = DevExt->DataBuffer - OutParams->bBuffer;
+        }
+
+      AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
+    }
+
+  DPRINT("AtapiSmartInterrupt() done!\n");
+
+  return(TRUE);
+}
+
+
+static BOOLEAN FASTCALL
+AtapiReadInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
+{
+  PSCSI_REQUEST_BLOCK Srb;
+  UCHAR DeviceStatus;
+  BOOLEAN IsLastBlock;
+  PUCHAR TargetAddress;
+  ULONG TransferSize;
+
+  DPRINT("AtapiReadInterrupt() called!\n");
+
+  Srb = DevExt->CurrentSrb;
+
+  DeviceStatus = IDEReadStatus(DevExt->CommandPortBase);
+  if ((DeviceStatus & (IDE_SR_DRQ|IDE_SR_BUSY|IDE_SR_ERR)) != IDE_SR_DRQ)
+    {
+      if (DeviceStatus & (IDE_SR_ERR|IDE_SR_DRQ))
+        {
+         AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
+          DPRINT("AtapiReadInterrupt() done!\n");
+         return TRUE;
+        }
+      DPRINT("AtapiReadInterrupt() done!\n");
+      return FALSE;
+    }
+
+  DPRINT("CommandPortBase: %lx  ControlPortBase: %lx\n", DevExt->CommandPortBase, DevExt->ControlPortBase);
+
+  /* Update controller/device state variables */
+  TargetAddress = DevExt->DataBuffer;
+  TransferSize = DevExt->TransferSize[Srb->TargetId];
+
+  DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
+  DPRINT("TransferSize: %lu\n", TransferSize);
+
+  if (DevExt->DataTransferLength <= TransferSize)
+    {
+       TransferSize = DevExt->DataTransferLength;
+       DevExt->DataTransferLength = 0;
+       IsLastBlock = TRUE;
+    }
+  else
+    {
+      DevExt->DataTransferLength -= TransferSize;
+      IsLastBlock = FALSE;
+    }
+  DevExt->DataBuffer += TransferSize;
+  DPRINT("IsLastBlock == %s\n", (IsLastBlock) ? "TRUE" : "FALSE");
+
+  /* Copy the block of data */
+  if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
+    {
+      IDEReadBlock32(DevExt->CommandPortBase, TargetAddress, TransferSize);
+    }
+  else
+    {
+      IDEReadBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
+    }
+
+  if (IsLastBlock)
+    {
+      AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
+    }
+
+  DPRINT("AtapiReadInterrupt() done!\n");
+
+  return(TRUE);
+}
+
+static BOOLEAN FASTCALL
+AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt)
+{
+  PSCSI_REQUEST_BLOCK Srb;
+  UCHAR DeviceStatus;
+  BOOLEAN IsLastBlock;
+  PUCHAR TargetAddress;
+  ULONG TransferSize;
+
+  DPRINT("AtapiWriteInterrupt() called!\n");
+
+  DeviceStatus = IDEReadStatus(DevExt->CommandPortBase);
+  if ((DeviceStatus & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_WERR)) != IDE_SR_DRDY)
+    {
+      if (DeviceStatus & (IDE_SR_DRDY|IDE_SR_ERR|IDE_SR_WERR))
+        {
+         AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
+          DPRINT("AtapiWriteInterrupt() done!\n");
+         return TRUE;
+        }
+      DPRINT("AtapiWriteInterrupt() done!\n");
+      return FALSE;
+    }
+  else
+    {
+     Srb = DevExt->CurrentSrb;
+     TransferSize = DevExt->TransferSize[Srb->TargetId];
+      if (DevExt->DataTransferLength < TransferSize)
+        {
+         TransferSize = DevExt->DataTransferLength;
+       }
+      if (TransferSize > 0 && (DeviceStatus & IDE_SR_DRQ))
+        {
+         IsLastBlock = FALSE;
+         TargetAddress = DevExt->DataBuffer;
+          DevExt->DataBuffer += TransferSize;
+         DevExt->DataTransferLength -= TransferSize;
+
+          DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
+          DPRINT("TransferSize: %lu\n", TransferSize);
+         /* Write the sector */
+         if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
+           {
+             IDEWriteBlock32(DevExt->CommandPortBase, TargetAddress, TransferSize);
+           }
+         else
+           {
+             IDEWriteBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
+           }
+       }
+      else if (DeviceStatus & IDE_SR_DRQ)
+        {
+          DPRINT("AtapiWriteInterrupt(): data overrun error!\n");
+          IsLastBlock = TRUE;
+       }
+      else if (TransferSize > 0 && !(DeviceStatus & IDE_SR_DRQ))
+        {
+         DPRINT1("%d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", TransferSize);
+         IsLastBlock = TRUE;
+        }
+      else
+        {
+         IsLastBlock = TRUE;
+       }
+      if (IsLastBlock)
+        {
+          AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
+        }
+      DPRINT("AtapiWriteInterrupt() done!\n");
+      return TRUE;
+    }
+}
+
+static VOID
+AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt,
+                   UCHAR command,
+                   BOOLEAN (FASTCALL *Handler)(PATAPI_MINIPORT_EXTENSION))
+{
+  if (DevExt->Handler != NULL)
+    {
+      DPRINT1("DevExt->Handler is already set!!\n");
+    }
+  DevExt->Handler = Handler;
+  IDEWriteCommand(DevExt->CommandPortBase, command);
+  ScsiPortStallExecution(1);
+}
+
+#ifdef ENABLE_DMA
+static BOOLEAN
+AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt,
+            PSCSI_REQUEST_BLOCK Srb,
+            UCHAR cmd)
+{
+  PVOID StartAddress;
+  PVOID EndAddress;
+  PPRD PRDEntry = DevExt->PRDTable;
+  SCSI_PHYSICAL_ADDRESS PhysicalAddress;
+  ULONG Length;
+  ULONG tmpLength;
+  UCHAR Status;
+
+  DPRINT("AtapiInitDma()\n");
+
+  StartAddress = Srb->DataBuffer;
+  EndAddress = (PVOID)((ULONG_PTR)StartAddress + Srb->DataTransferLength);
+  DevExt->PRDCount = 0;
+
+  while (StartAddress < EndAddress)
+    {
+      PhysicalAddress = ScsiPortGetPhysicalAddress(DevExt, Srb, StartAddress, &Length);
+      if (PhysicalAddress.QuadPart == 0LL || Length == 0)
+        {
+         return FALSE;
+       }
+
+      while (Length)
+        {
+         /* calculate the length up to the next 64k boundary */
+         tmpLength = 0x10000 - (PhysicalAddress.u.LowPart & 0xffff);
+         if (tmpLength > Length)
+           {
+             tmpLength = Length;
+           }
+         DevExt->PRDCount++;
+         if (DevExt->PRDCount > DevExt->PRDMaxCount)
+           {
+             return FALSE;
+           }
+         if (tmpLength == 0x10000)
+           {
+             /* Some dirty controllers cannot handle 64k transfers. We split a 64k transfer in two 32k. */
+             tmpLength = 0x8000;
+             DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
+                    DevExt->PRDCount - 1, StartAddress, PhysicalAddress.u.LowPart, tmpLength);
+             PRDEntry->PhysAddress = PhysicalAddress.u.LowPart;
+             PRDEntry->Length = tmpLength;
+             PRDEntry++;
+             DevExt->PRDCount++;
+             if (DevExt->PRDCount > DevExt->PRDMaxCount)
+               {
+                 return FALSE;
+               }
+              PhysicalAddress.u.LowPart += tmpLength;
+             StartAddress = (PVOID)((ULONG_PTR)StartAddress + tmpLength);
+             Length -= tmpLength;
+             PRDEntry->PhysAddress = PhysicalAddress.u.LowPart;
+           }
+         DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
+                DevExt->PRDCount - 1, StartAddress, PhysicalAddress.u.LowPart, tmpLength);
+         PRDEntry->PhysAddress = PhysicalAddress.u.LowPart;
+          PRDEntry->Length = tmpLength;
+          PRDEntry++;
+          StartAddress = (PVOID)((ULONG_PTR)StartAddress + tmpLength);
+          PhysicalAddress.u.LowPart += tmpLength;
+         Length -= tmpLength;
+       }
+    }
+  /* set the end marker in the last PRD */
+  PRDEntry--;
+  PRDEntry->Length |= 0x80000000;
+  /* set the PDR table */
+  IDEWritePRDTable(DevExt->BusMasterRegisterBase, DevExt->PRDTablePhysicalAddress.u.LowPart);
+  /* write the DMA command */
+  IDEWriteDMACommand(DevExt->BusMasterRegisterBase, cmd);
+  /* reset the status and interrupt bit */
+  Status = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
+  IDEWriteDMAStatus(DevExt->BusMasterRegisterBase, Status | 0x06);
+  return TRUE;
+}
+#endif
+
 /* EOF */