atapi, buslogic, cdrom, class2.
[reactos.git] / reactos / drivers / storage / atapi / atapi.c
index 7e2e237..a004aa0 100644 (file)
@@ -1,10 +1,29 @@
-/* $Id: atapi.c,v 1.7 2002/02/04 01:21:03 ekohl Exp $
+/*
+ *  ReactOS kernel
+ *  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
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* $Id$
  *
  * COPYRIGHT:   See COPYING in the top level directory
  * PROJECT:     ReactOS 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
  */
  *     - handle removable atapi non-cdrom drives
  */
 
-//  -------------------------------------------------------------------------
+#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 NDEBUG
 #include <debug.h>
 
-#define  VERSION  "V0.0.1"
+#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,
@@ -130,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);
@@ -145,22 +253,16 @@ AtapiIdentifyDevice(IN ULONG CommandPort,
                    OUT PIDE_DRIVE_IDENTIFY DrvParms);
 
 static BOOLEAN
-IDEResetController(IN WORD CommandPort,
-                  IN WORD ControlPort);
-
-static int
-AtapiPolledRead(IN WORD CommandPort,
-               IN WORD 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);
-
-
+AtapiPolledRead(IN ULONG CommandPort,
+               IN ULONG ControlPort,
+               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,
@@ -170,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);
@@ -182,13 +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)
@@ -200,33 +321,12 @@ IDESwapBytePairs(char *Buf,
 }
 
 
-static BOOLEAN
-IdeFindDrive(int Address,
-            int DriveIdx)
-{
-  ULONG Cyl;
-
-  DPRINT1("IdeFindDrive(Address %lx DriveIdx %lu) called!\n", Address, DriveIdx);
-
-  IDEWriteDriveHead(Address, IDE_DH_FIXED | (DriveIdx ? IDE_DH_DRV1 : 0));
-  IDEWriteCylinderLow(Address, 0x30);
-
-  Cyl = IDEReadCylinderLow(Address);
-  DPRINT1("Cylinder %lx\n", Cyl);
-
-
-  DPRINT1("IdeFindDrive() done!\n");
-//  for(;;);
-  return(Cyl == 0x30);
-}
-
-
 //  -------------------------------------------------------  Public Interface
 
 //    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.
 //
@@ -236,20 +336,21 @@ IdeFindDrive(int Address,
 //  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)
 {
   HW_INITIALIZATION_DATA InitData;
   NTSTATUS Status;
 
-  DbgPrint("ATAPI Driver %s\n", VERSION);
+  DPRINT("ATAPI Driver %s\n", VERSION);
+  DPRINT("RegistryPath: '%wZ'\n", RegistryPath);
 
   /* Initialize data structure */
   RtlZeroMemory(&InitData,
@@ -266,8 +367,11 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
   InitData.MapBuffers = TRUE;
 
   /* 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;
@@ -281,31 +385,36 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
                              NULL);
 //  if (newStatus < statusToReturn)
 //    statusToReturn = newStatus;
+#endif
 
-  /* Search the ISA bus for ide controllers */
-#if 0
-  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;
@@ -315,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
 
-  DPRINT1( "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,
@@ -338,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,
@@ -353,121 +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 */
-         DPRINT1("Bus %1lu  Device %2lu  Func %1lu  VenID 0x%04hx  DevID 0x%04hx\n",
-                ConfigInfo->SystemIoBusNumber,
-//              SlotNumber.u.AsULONG >> 3,
-//              SlotNumber.u.AsULONG & 0x07,
-                SlotNumber.u.bits.DeviceNumber,
-                SlotNumber.u.bits.FunctionNumber,
-                PciConfig.VendorID,
-                PciConfig.DeviceID);
-         DPRINT("ProgIF 0x%02hx\n", PciConfig.ProgIf);
-
-         DPRINT1("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 */
-             DPRINT1("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)
-           {
+             DPRINT("Primary channel!\n");
+              ChannelFound = AtapiClaimHwResources(DevExt,
+                                                  ConfigInfo,
+                                                  PCIBus,
+                                                  0x1F0,
+                                                  0x3F4,
+                                                  BusMasterBasePort,
+                                                  14);
+              *Again = TRUE;
+          }
+          else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
+          {
              /* Primary channel already claimed: claim secondary channel */
-             DPRINT1("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;
+             DPRINT("Secondary channel!\n");
+
+              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,
@@ -477,29 +701,67 @@ AtapiFindIsaBusController(PVOID DeviceExtension,
                          PBOOLEAN Again)
 {
   PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
+  BOOLEAN ChannelFound = FALSE;
+  BOOLEAN DeviceFound = FALSE;
 
   DPRINT("AtapiFindIsaBusController() called!\n");
 
   *Again = FALSE;
 
-  if (ConfigInfo->AtdiskPrimaryClaimed == TRUE)
-    {
-       DPRINT("Primary IDE controller already claimed!\n");
+  ConfigInfo->NumberOfBuses = 1;
+  ConfigInfo->MaximumNumberOfTargets = 2;
+  ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
 
+  if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
+    {
+      /* Both channels unclaimed: Claim primary channel */
+      DPRINT("Primary channel!\n");
+
+      ChannelFound = AtapiClaimHwResources(DevExt,
+                                          ConfigInfo,
+                                          Isa,
+                                          0x1F0,
+                                          0x3F4,
+                                          0,
+                                          14);
+      *Again = TRUE;
     }
-
-  if (ConfigInfo->AtdiskSecondaryClaimed == TRUE)
+  else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
     {
-       DPRINT("Secondary IDE controller already claimed!\n");
-
+      /* Primary channel already claimed: claim secondary channel */
+      DPRINT("Secondary channel!\n");
+
+      ChannelFound = AtapiClaimHwResources(DevExt,
+                                          ConfigInfo,
+                                          Isa,
+                                          0x170,
+                                          0x374,
+                                          0,
+                                          15);
+      *Again = FALSE;
+    }
+  else
+    {
+      DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
+      *Again = FALSE;
+      return(SP_RETURN_NOT_FOUND);
     }
 
-  DPRINT("AtapiFindIsaBusController() done!\n");
-
-  return(SP_RETURN_NOT_FOUND);
+  /* Find attached devices */
+  if (ChannelFound)
+    {
+      DeviceFound = AtapiFindDevices(DevExt,
+                                    ConfigInfo);
+      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,
@@ -509,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
@@ -542,7 +918,7 @@ AtapiStartIo(IN PVOID DeviceExtension,
   PATAPI_MINIPORT_EXTENSION DevExt;
   ULONG Result;
 
-  DPRINT1("AtapiStartIo() called\n");
+  DPRINT("AtapiStartIo() called\n");
 
   DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
 
@@ -550,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);
@@ -562,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;
@@ -570,222 +1088,137 @@ AtapiStartIo(IN PVOID DeviceExtension,
   if (Result != SRB_STATUS_PENDING)
     {
       DevExt->CurrentSrb = NULL;
-      Srb->SrbStatus = (UCHAR)Result;
-#if 0
+
       ScsiPortNotification(RequestComplete,
                           DeviceExtension,
                           Srb);
-
       ScsiPortNotification(NextRequest,
                           DeviceExtension,
                           NULL);
-#endif
     }
+  else
+    {
+      DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
+    }
+
+  DPRINT("AtapiStartIo() done\n");
 
   return(TRUE);
 }
 
-
 static BOOLEAN STDCALL
 AtapiInterrupt(IN PVOID DeviceExtension)
 {
   PATAPI_MINIPORT_EXTENSION DevExt;
-  PSCSI_REQUEST_BLOCK Srb;
-  ULONG CommandPortBase;
-  ULONG ControlPortBase;
-
-  UCHAR DeviceStatus;
-  BOOLEAN IsLastBlock, AnErrorOccured, RequestIsComplete;
-  ULONG Retries;
-  NTSTATUS ErrorStatus;
-  ULONG ErrorInformation;
-  PUCHAR TargetAddress;
-
-
-
-  DPRINT1("AtapiInterrupt() called!\n");
-
+  UCHAR Status;
   DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
-  Srb = DevExt->CurrentSrb;
-
-  DPRINT1("Srb: %p\n", Srb);
-
-  CommandPortBase = DevExt->CommandPortBase;
-  ControlPortBase = DevExt->ControlPortBase;
 
-  DPRINT("CommandPortBase: %lx  ControlPortBase: %lx\n", CommandPortBase, ControlPortBase);
-
-
-  IsLastBlock = FALSE;
-  AnErrorOccured = FALSE;
-  RequestIsComplete = FALSE;
-  ErrorStatus = STATUS_SUCCESS;
-  ErrorInformation = 0;
-
-  DeviceStatus = IDEReadStatus(CommandPortBase);
-
-  /*  Handle error condition if it exists */
-  if (DeviceStatus & IDE_SR_ERR)
+  if (DevExt->Handler == NULL)
     {
-      BYTE ErrorReg, SectorCount, SectorNum, CylinderLow, CylinderHigh;
-      BYTE DriveHead;
-
-      /* Log the error */
-      ErrorReg = IDEReadError(CommandPortBase);
-      CylinderLow = IDEReadCylinderLow(CommandPortBase);
-      CylinderHigh = IDEReadCylinderHigh(CommandPortBase);
-      DriveHead = IDEReadDriveHead(CommandPortBase);
-      SectorCount = IDEReadSectorCount(CommandPortBase);
-      SectorNum = IDEReadSectorNum(CommandPortBase);
-
-      /* FIXME: should use the NT error logging facility */
-      DbgPrint("ATAPT Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
-              0, //DeviceExtension->Operation,
-              DeviceStatus,
-              ErrorReg,
-              CylinderLow,
-              CylinderHigh,
-              SectorCount,
-              SectorNum);
-
-      /* FIXME: should retry the command and perhaps recalibrate the drive */
-
-        //  Set error status information
-      AnErrorOccured = TRUE;
-      ErrorStatus = STATUS_DISK_OPERATION_FAILED;
-#if 0
-      ErrorInformation = 
-          (((((((CylinderHigh << 8) + CylinderLow) * 
-              DeviceExtension->LogicalHeads) + 
-              (DriveHead % DeviceExtension->LogicalHeads)) * 
-              DeviceExtension->SectorsPerLogTrk) + SectorNum - 1) -
-          DeviceExtension->StartingSector) * DeviceExtension->BytesPerSector;
-#endif
+      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
     {
-      switch (Srb->Cdb[0])
-       {
-         case SCSIOP_READ:
-           DPRINT1("SCSIOP_READ\n");
-
-           /* Update controller/device state variables */
-           TargetAddress = Srb->DataBuffer;
-           Srb->DataBuffer += DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
-           Srb->DataTransferLength -= DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
-//         DevExt->SectorsTransferred++;
-
-           /* Remember whether DRQ should be low at end (last block read) */
-           IsLastBlock = Srb->DataTransferLength == 0;
-
-           /* Wait for DRQ assertion */
-           for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
-                !(IDEReadStatus(CommandPortBase) & IDE_SR_DRQ);
-                Retries++)
-             {
-               KeStallExecutionProcessor(10);
-             }
+      Status = IDEReadAltStatus(DevExt->ControlPortBase);
+      if (Status & IDE_SR_BUSY)
+        {
+         return FALSE;
+       }
+    }
+  return DevExt->Handler(DevExt);
+}
 
-           /* Copy the block of data */
-           IDEReadBlock(CommandPortBase,
-                        TargetAddress,
-                        IDE_SECTOR_BUF_SZ);
+//  ----------------------------------------------------  Discardable statics
 
-           /* 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)
-                 {
-                   AnErrorOccured = TRUE;
-                   ErrorStatus = STATUS_DATA_OVERRUN;
-                   ErrorInformation = 0;
-                 }
-               else
-                 {
+#ifdef ENABLE_DMA
+static BOOLEAN
+AtapiConfigDma(PATAPI_MINIPORT_EXTENSION DeviceExtension, ULONG UnitNumber)
+{
+  BOOLEAN Result = FALSE;
+  UCHAR Status;
 
-#if 0
-                    //  Setup next transfer or set RequestIsComplete
-                  if (DeviceExtension->BytesRequested > 
-                      DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER) 
-                    {
-                      DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
-                      DeviceExtension->SectorsTransferred = 0;
-                      DeviceExtension->BytesToTransfer = 
-                      DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER;
-                      DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
-                    } 
-                  else if (DeviceExtension->BytesRequested > 0) 
-                    {
-                      DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
-                      DeviceExtension->SectorsTransferred = 0;
-                      DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
-                      DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
-                    } 
-                  else
-                    {
-                      RequestIsComplete = TRUE;
+  if (UnitNumber < 2)
+    {
+      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
-                   RequestIsComplete = TRUE;
-                 }
-             }
-           break;
-
-         case SCSIOP_WRITE:
-           DPRINT1("AtapiInterrupt(): SCSIOP_WRITE not implemented yet!\n");
-           RequestIsComplete = TRUE;
-           break;
-      }
+                }
+              Status = IDEReadDMAStatus(DeviceExtension->BusMasterRegisterBase);
+              if (Result)
+                {
+                  IDEWriteDMAStatus(DeviceExtension->BusMasterRegisterBase, Status | (UnitNumber ? 0x40 : 0x20));
+               }
+              else
+                {
+                  IDEWriteDMAStatus(DeviceExtension->BusMasterRegisterBase, Status & (UnitNumber ? ~0x40 : ~0x20));
+                }
+           }
+       }
     }
-
-
-  /* If there was an error or the request is done, complete the packet */
-  if (AnErrorOccured || RequestIsComplete)
-    {
-#if 0
-      /* Set the return status and info values */
-      Irp = ControllerExtension->CurrentIrp;
-      Irp->IoStatus.Status = ErrorStatus;
-      Irp->IoStatus.Information = ErrorInformation;
-
-      /* Clear out controller fields */
-      ControllerExtension->OperationInProgress = FALSE;
-      ControllerExtension->DeviceStatus = 0;
-
-      /* Queue the Dpc to finish up */
-      IoRequestDpc(DeviceExtension->DeviceObject,
-                  Irp,
-                  ControllerExtension);
-#endif
-    }
-  else if (IsLastBlock)
-    {
-#if 0
-      /* Else more data is needed, setup next device I/O */
-      IDEStartController((PVOID)DeviceExtension);
-#endif
-    }
-
-  DPRINT1("AtapiInterrupt() done!\n");
-
-  return(TRUE);
+  return Result;
 }
+#endif
 
-
-
-
-
-
-//  ----------------------------------------------------  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,
@@ -796,35 +1229,46 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
   ULONG ControlPortBase;
   ULONG UnitNumber;
   ULONG Retries;
-  BYTE High, Low;
+  UCHAR High;
+  UCHAR Low;
 
   DPRINT("AtapiFindDevices() called\n");
 
-//  CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
-  CommandPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[0].RangeStart);
+  CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
   DPRINT("  CommandPortBase: %x\n", CommandPortBase);
 
-//  ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
-  ControlPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[1].RangeStart);
+  ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
   DPRINT("  ControlPortBase: %x\n", ControlPortBase);
 
   for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
     {
-      /* disable interrupts */
-      IDEWriteDriveControl(CommandPortBase,
-                          IDE_DC_nIEN);
-
-      /* select drive */
+      /* Select drive */
       IDEWriteDriveHead(CommandPortBase,
                        IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
       ScsiPortStallExecution(500);
+
+      /* Disable interrupts */
+      IDEWriteDriveControl(ControlPortBase,
+                          IDE_DC_nIEN);
+      ScsiPortStallExecution(500);
+
+      /* Check if a device is attached to the interface */
+      IDEWriteCylinderHigh(CommandPortBase, 0xaa);
+      IDEWriteCylinderLow(CommandPortBase, 0x55);
+
+      High = IDEReadCylinderHigh(CommandPortBase);
+      Low = IDEReadCylinderLow(CommandPortBase);
+
       IDEWriteCylinderHigh(CommandPortBase, 0);
       IDEWriteCylinderLow(CommandPortBase, 0);
-      IDEWriteCommand(CommandPortBase, 0x08); /* IDE_COMMAND_ATAPI_RESET */
-//      ScsiPortStallExecution(1000*1000);
-//      IDEWriteDriveHead(CommandPortBase,
-//                     IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
-//                     IDE_DH_FIXED);
+
+      if (Low != 0x55 || High != 0xaa)
+       {
+         DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber, CommandPortBase);
+         continue;
+       }
+
+      AtapiExecuteCommand(DeviceExtension, IDE_CMD_RESET, NULL);
 
       for (Retries = 0; Retries < 20000; Retries++)
        {
@@ -834,10 +1278,11 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
            }
          ScsiPortStallExecution(150);
        }
-      if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
+      if (Retries >= 20000)
        {
-         DbgPrint("Timeout on drive %lu\n", UnitNumber);
-         return(DeviceFound);
+         DPRINT("Timeout on drive %lu\n", UnitNumber);
+         DeviceExtension->DeviceFlags[UnitNumber] &= ~DEVICE_PRESENT;
+         continue;
        }
 
       High = IDEReadCylinderHigh(CommandPortBase);
@@ -857,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
@@ -875,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
@@ -886,82 +1389,46 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
        }
     }
 
-  DPRINT("AtapiFindDrives() done\n");
-
-  return(DeviceFound);
-}
-
-
-//    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 WORD CommandPort,
-                    IN WORD 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);
-    }
-
-  CHECKPOINT;
-  if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
-    {
-      return(FALSE);
-    }
+  /* Reset pending interrupts */
+  IDEReadStatus(CommandPortBase);
+  /* Reenable interrupts */
+  IDEWriteDriveControl(ControlPortBase, 0);
+  ScsiPortStallExecution(500);
+  /* Return with drive 0 selected */
+  IDEWriteDriveHead(CommandPortBase, IDE_DH_FIXED);
+  ScsiPortStallExecution(500);
 
-  CHECKPOINT;
+  DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound) ? "TRUE" : "FALSE");
 
-    //  return TRUE if controller came back to life. and
-    //  the registers are initialized correctly
-  return(IDEReadError(CommandPort) == 1);
+  return(DeviceFound);
 }
 
 
-//    AtapiIdentifyDevice
-//
-//  DESCRIPTION:
-//    Get the identification block from the drive
-//
-//  RUN LEVEL:
-//    PASSIVE_LEVEL
-//
-//  ARGUMENTS:
-//    IN   int                  CommandPort  Address of the command port
-//    IN   int                  DriveNum     The drive index (0,1)
-//    OUT  PIDE_DRIVE_IDENTIFY  DrvParms     Address to write drive ident block
-//
-//  RETURNS:
-//    TRUE  The drive identification block was retrieved successfully
-//
+/*
+ *  AtapiIdentifyDevice
+ *
+ *  DESCRIPTION:
+ *     Get the identification block from the drive
+ *
+ *  RUN LEVEL:
+ *     PASSIVE_LEVEL
+ *
+ *  ARGUMENTS:
+ *     CommandPort
+ *             Address of the command port
+ *     ControlPort
+ *             Address of the control port
+ *     DriveNum
+ *             The drive index (0,1)
+ *     Atapi
+ *             Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
+ *     DrvParms
+ *             Address to write drive ident block
+ *
+ *  RETURNS:
+ *     TRUE: The drive identification block was retrieved successfully
+ *     FALSE: an error ocurred
+ */
 
 static BOOLEAN
 AtapiIdentifyDevice(IN ULONG CommandPort,
@@ -970,9 +1437,15 @@ AtapiIdentifyDevice(IN ULONG CommandPort,
                    IN BOOLEAN Atapi,
                    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((WORD)CommandPort,
-                     (WORD)ControlPort,
+  if (AtapiPolledRead(CommandPort,
+                     ControlPort,
                      0,
                      1,
                      0,
@@ -980,52 +1453,102 @@ AtapiIdentifyDevice(IN ULONG CommandPort,
                      0,
                      (DriveNum ? IDE_DH_DRV1 : 0),
                      (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
-                     (BYTE *)DrvParms) != 0) /* atapi_identify */
+                     (PUCHAR)DrvParms) == FALSE)
     {
-      DPRINT1("IDEPolledRead() failed\n");
+      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);
-  DPRINT("Config:%04x  Cyls:%5d  Heads:%2d  Sectors/Track:%3d  Gaps:%02d %02d\n", 
-         DrvParms->ConfigBits, 
-         DrvParms->LogicalCyls, 
-         DrvParms->LogicalHeads, 
-         DrvParms->SectorsPerTrack, 
-         DrvParms->InterSectorGap, 
+  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,
+         DrvParms->LogicalHeads,
+         DrvParms->SectorsPerTrack,
+         DrvParms->InterSectorGap,
          DrvParms->InterSectorGapSize);
-  DPRINT("Bytes/PLO:%3d  Vendor Cnt:%2d  Serial number:[%.20s]\n", 
-         DrvParms->BytesInPLO, 
-         DrvParms->VendorUniqueCnt, 
-         DrvParms->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, 
+  DPRINT("Bytes/PLO:%3d  Vendor Cnt:%2d  Serial number:[%.20s]\n",
+         DrvParms->BytesInPLO,
+         DrvParms->VendorUniqueCnt,
+         SerialNumber);
+  DPRINT("Cntlr type:%2d  BufSiz:%5d  ECC bytes:%3d  Firmware Rev:[%.8s]\n",
+         DrvParms->ControllerType,
+         DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
+         DrvParms->ECCByteCnt,
+         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->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
          DrvParms->MinPIOTransTime,
          DrvParms->MinDMATransTime);
   DPRINT("TM:Cyls:%d  Heads:%d  Sectors/Trk:%d Capacity:%ld\n",
-         DrvParms->TMCylinders, 
-         DrvParms->TMHeads, 
+         DrvParms->TMCylinders,
+         DrvParms->TMHeads,
          DrvParms->TMSectorsPerTrk,
          (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
   DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
          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);
+       }
+    }
 
+  if (! Atapi && 0 != (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED))
+    {
+      /* LBA ATA drives always have a sector size of 512 */
+      DrvParms->BytesPerSector = 512;
+    }
+  else
+    {
+      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);
-  if (DrvParms->BytesPerSector == 0)
-    DrvParms->BytesPerSector = 512;
+
   return TRUE;
 }
 
@@ -1039,64 +1562,69 @@ 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
-AtapiPolledRead(IN WORD Address,
-               IN WORD 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)
+static BOOLEAN
+AtapiPolledRead(IN ULONG CommandPort,
+               IN ULONG ControlPort,
+               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;
-
-  /* Disable interrupts */
-  Control = IDEReadAltStatus(ControlPort);
-  IDEWriteDriveControl(ControlPort, Control | IDE_DC_nIEN);
 
-  /*  Wait for STATUS.BUSY and STATUS.DRQ to clear  */
+  /* Wait for BUSY to clear */
   for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
     {
-      Status = IDEReadStatus(Address);
-      if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
-       {
-         break;
-       }
+      Status = IDEReadStatus(CommandPort);
+      if (!(Status & IDE_SR_BUSY))
+        {
+          break;
+        }
       ScsiPortStallExecution(10);
     }
-  if (RetryCount == IDE_MAX_BUSY_RETRIES)
+  DPRINT("status=%02x\n", Status);
+  DPRINT("waited %ld usecs for busy to clear\n", RetryCount * 10);
+  if (RetryCount >= IDE_MAX_BUSY_RETRIES)
     {
-      return(IDE_ER_ABRT);
+      DPRINT("Drive is BUSY for too long\n");
+      return FALSE;
     }
 
   /*  Write Drive/Head to select drive  */
-  IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
+  IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
+  ScsiPortStallExecution(500);
+
+  /* Disable interrupts */
+  IDEWriteDriveControl(ControlPort, IDE_DC_nIEN);
+  ScsiPortStallExecution(500);
 
+#if 0
   /*  Wait for STATUS.BUSY and STATUS.DRQ to clear  */
   for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
     {
-      Status = IDEReadStatus(Address);
+      Status = IDEReadStatus(CommandPort);
       if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
        {
          break;
@@ -1105,8 +1633,9 @@ AtapiPolledRead(IN WORD Address,
     }
   if (RetryCount >= IDE_MAX_BUSY_RETRIES)
     {
-      return IDE_ER_ABRT;
+      return FALSE;
     }
+#endif
 
   /*  Issue command to drive  */
   if (DrvHead & IDE_DH_LBA)
@@ -1130,36 +1659,43 @@ AtapiPolledRead(IN WORD Address,
     }
 
   /*  Setup command parameters  */
-  IDEWritePrecomp(Address, PreComp);
-  IDEWriteSectorCount(Address, SectorCnt);
-  IDEWriteSectorNum(Address, SectorNum);
-  IDEWriteCylinderHigh(Address, CylinderHigh);
-  IDEWriteCylinderLow(Address, CylinderLow);
-  IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
+  IDEWritePrecomp(CommandPort, PreComp);
+  IDEWriteSectorCount(CommandPort, SectorCnt);
+  IDEWriteSectorNum(CommandPort, SectorNum);
+  IDEWriteCylinderHigh(CommandPort, CylinderHigh);
+  IDEWriteCylinderLow(CommandPort, CylinderLow);
+  IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
 
   /*  Issue the command  */
-  IDEWriteCommand(Address, Command);
+  IDEWriteCommand(CommandPort, Command);
   ScsiPortStallExecution(50);
 
   /*  wait for DRQ or error  */
   for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
     {
-      Status = IDEReadStatus(Address);
+      Status = IDEReadStatus(CommandPort);
       if (!(Status & IDE_SR_BUSY))
        {
          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);
@@ -1168,8 +1704,11 @@ AtapiPolledRead(IN WORD Address,
   /*  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)
@@ -1177,26 +1716,29 @@ AtapiPolledRead(IN WORD Address,
       /*  Read data into buffer  */
       if (Junk == FALSE)
        {
-         IDEReadBlock(Address, Buffer, IDE_SECTOR_BUF_SZ);
+         IDEReadBlock(CommandPort, Buffer, IDE_SECTOR_BUF_SZ);
          Buffer += IDE_SECTOR_BUF_SZ;
        }
       else
        {
          UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
-         IDEReadBlock(Address, JunkBuffer, IDE_SECTOR_BUF_SZ);
+         IDEReadBlock(CommandPort, JunkBuffer, IDE_SECTOR_BUF_SZ);
        }
       SectorCount++;
 
       /*  Check for error or more sectors to read  */
       for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
        {
-         Status = IDEReadStatus(Address);
+         Status = IDEReadStatus(CommandPort);
          if (!(Status & IDE_SR_BUSY))
            {
              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)
                {
@@ -1214,8 +1756,11 @@ AtapiPolledRead(IN WORD Address,
                      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;
                }
            }
        }
@@ -1226,157 +1771,554 @@ AtapiPolledRead(IN WORD Address,
 //  -------------------------------------------  Nondiscardable statics
 
 static ULONG
-AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
+AtapiSendSmartCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
                      IN PSCSI_REQUEST_BLOCK Srb)
 {
-  DPRINT1("AtapiSendAtapiComamnd() called!\n");
-  DPRINT1("Not implemented yet!\n");
-  return(SRB_STATUS_SELECTION_TIMEOUT);
-}
+  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;
+    }
 
-static ULONG
-AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
-                   IN PSCSI_REQUEST_BLOCK Srb)
-{
-  ULONG SrbStatus = SRB_STATUS_SUCCESS;
+  DeviceExtension->DataTransferLength = 0;
 
-  DPRINT("AtapiSendIdeCommand() called!\n");
+  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;
+    }
 
-  DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n",
-        Srb->PathId,
-        Srb->TargetId,
-        Srb->Lun);
+  Srb->TargetId = InParams.bDriveNumber;
+  
+  /* Set pointer to data buffer. */
+  DeviceExtension->DataBuffer = (PUCHAR)OutParams->bBuffer;
 
-  switch (Srb->Cdb[0])
-    {
-      case SCSIOP_INQUIRY:
-       SrbStatus = AtapiInquiry(DeviceExtension,
-                                Srb);
-       break;
+  DeviceExtension->CurrentSrb = Srb;
 
-      case SCSIOP_READ_CAPACITY:
-       SrbStatus = AtapiReadCapacity(DeviceExtension,
-                                     Srb);
-       break;
+  /*  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);
+    }
 
-      case SCSIOP_READ:
-      case SCSIOP_WRITE:
-       SrbStatus = AtapiReadWrite(DeviceExtension,
-                                  Srb);
-       break;
+  /*  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);
 
-      case SCSIOP_MODE_SENSE:
-      case SCSIOP_TEST_UNIT_READY:
-      case SCSIOP_VERIFY:
-      case SCSIOP_START_STOP_UNIT:
-      case SCSIOP_REQUEST_SENSE:
-       break;
+  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);
 
-     default:
-       DPRINT1("AtapiSendIdeCommand():unknown command %x\n",
-               Srb->Cdb[0]);
-       SrbStatus = SRB_STATUS_INVALID_REQUEST;
-       break;
-    }
+  AtapiExecuteCommand(DeviceExtension, InParams.irDriveRegs.bCommandReg, AtapiSmartInterrupt);
 
-  DPRINT("AtapiSendIdeCommand() done!\n");
+  /* Wait for interrupt. */
+  return SRB_STATUS_PENDING;
 
-  return(SrbStatus);
 }
 
-
 static ULONG
-AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
-            PSCSI_REQUEST_BLOCK Srb)
+AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
+                     IN PSCSI_REQUEST_BLOCK Srb)
 {
-  PIDE_DRIVE_IDENTIFY DeviceParams;
-  PINQUIRYDATA InquiryData;
-  ULONG i;
+  UCHAR ByteCountHigh;
+  UCHAR ByteCountLow;
+  ULONG Retries;
+  ULONG CdbSize;
+  UCHAR Status;
 
-  DPRINT("SCSIOP_INQUIRY: TargetId: %lu\n", Srb->TargetId);
+  DPRINT("AtapiSendAtapiCommand() called!\n");
 
-  if ((Srb->PathId != 0) ||
-      (Srb->TargetId > 1) ||
-      (Srb->Lun != 0) ||
-      (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
+  if (Srb->PathId != 0)
     {
-      return(SRB_STATUS_SELECTION_TIMEOUT);
+      Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
+      return(SRB_STATUS_INVALID_PATH_ID);
     }
 
-  InquiryData = Srb->DataBuffer;
-  DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
-
-  /* clear buffer */
-  for (i = 0; i < Srb->DataTransferLength; i++)
+  if (Srb->TargetId > 1)
     {
-      ((PUCHAR)Srb->DataBuffer)[i] = 0;
+      Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
+      return(SRB_STATUS_INVALID_TARGET_ID);
     }
 
-  /* set device class */
-  if (DeviceExtension->DeviceAtapi[Srb->TargetId] == FALSE)
-    {
-      /* hard-disk */
-      InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
-    }
-  else
+  if (Srb->Lun != 0)
     {
-      /* FIXME: this is incorrect use SCSI-INQUIRY command!! */
-      /* cdrom drive */
-      InquiryData->DeviceType = READ_ONLY_DIRECT_ACCESS_DEVICE;
+      Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+      return(SRB_STATUS_INVALID_LUN);
     }
 
-  DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
-  if (DeviceParams->ConfigBits & 0x80)
+  if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
     {
-      DPRINT1("Removable media!\n");
-      InquiryData->RemovableMedia = 1;
+      Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+      return(SRB_STATUS_NO_DEVICE);
     }
 
-  for (i = 0; i < 20; i += 2)
+  if (Srb->Cdb[0] == SCSIOP_MODE_SENSE)
     {
-      InquiryData->VendorId[i] =
-       ((PUCHAR)DeviceParams->ModelNumber)[i];
-      InquiryData->VendorId[i+1] =
-       ((PUCHAR)DeviceParams->ModelNumber)[i+1];
+      Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+      return (SRB_STATUS_INVALID_REQUEST);
     }
 
-  for (i = 0; i < 4; i++)
+  DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
+        Srb->TargetId);
+
+  if (Srb->Cdb[0] == SCSIOP_INQUIRY)
+    return(AtapiInquiry(DeviceExtension,
+                       Srb));
+
+  /* Set pointer to data buffer. */
+  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++)
     {
-      InquiryData->ProductId[12+i] = ' ';
+      Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+      if (!(Status & IDE_SR_BUSY))
+        {
+          break;
+        }
+      ScsiPortStallExecution(10);
     }
-
-  for (i = 0; i < 4; i += 2)
+  DPRINT("status=%02x\n", Status);
+  DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
+  if (Retries >= IDE_MAX_BUSY_RETRIES)
     {
-      InquiryData->ProductRevisionLevel[i] =
-       ((PUCHAR)DeviceParams->FirmwareRev)[i];
-      InquiryData->ProductRevisionLevel[i+1] =
-       ((PUCHAR)DeviceParams->FirmwareRev)[i+1];
+      DPRINT("Drive is BUSY for too long\n");
+      return(SRB_STATUS_BUSY);
     }
 
-  return(SRB_STATUS_SUCCESS);
+  /* Select the desired drive */
+  IDEWriteDriveHead(DeviceExtension->CommandPortBase,
+                   IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
+
+  /* Wait a little while */
+  ScsiPortStallExecution(50);
+
+#if 0
+  /* Wait for BUSY to clear and DRDY to assert */
+  for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
+    {
+      Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+      if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
+       {
+         break;
+       }
+      ScsiPortStallExecution(10);
+    }
+  DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
+  if (Retries >= IDE_MAX_BUSY_RETRIES)
+    {
+      DPRINT("Drive is BUSY for too long after drive select\n");
+      return(SRB_STATUS_BUSY);
+    }
+#endif
+
+#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)(DeviceExtension->DataTransferLength & 0xFF);
+      ByteCountHigh = (UCHAR)(DeviceExtension->DataTransferLength >> 8);
+    }
+  else
+    {
+      ByteCountLow = 0xFF;
+      ByteCountHigh = 0xFF;
+    }
+
+  /* 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 */
+#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++)
+    {
+      Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+      if ((Status & IDE_SR_DRQ))
+       {
+         break;
+       }
+      ScsiPortStallExecution(10);
+    }
+
+  /* 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 */
+  IDEWriteBlock(DeviceExtension->CommandPortBase,
+               (PUSHORT)Srb->Cdb,
+               CdbSize);
+
+#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);
 }
 
 
 static ULONG
-AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
-                 PSCSI_REQUEST_BLOCK Srb)
+AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
+                   IN PSCSI_REQUEST_BLOCK Srb)
+{
+  ULONG SrbStatus = SRB_STATUS_SUCCESS;
+
+  DPRINT("AtapiSendIdeCommand() called!\n");
+
+  DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n",
+        Srb->PathId,
+        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:
+       SrbStatus = AtapiInquiry(DeviceExtension,
+                                Srb);
+       break;
+
+      case SCSIOP_READ_CAPACITY:
+       SrbStatus = AtapiReadCapacity(DeviceExtension,
+                                     Srb);
+       break;
+
+      case SCSIOP_READ:
+      case SCSIOP_WRITE:
+       SrbStatus = AtapiReadWrite(DeviceExtension,
+                                  Srb);
+       break;
+
+      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:
+       break;
+
+     default:
+       DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
+                Srb->Cdb[0]);
+       SrbStatus = SRB_STATUS_INVALID_REQUEST;
+       break;
+    }
+
+  DPRINT("AtapiSendIdeCommand() done!\n");
+
+  return(SrbStatus);
+}
+
+
+static ULONG
+AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+            PSCSI_REQUEST_BLOCK Srb)
 {
-  PREAD_CAPACITY_DATA CapacityData;
   PIDE_DRIVE_IDENTIFY DeviceParams;
-  ULONG LastSector;
+  PINQUIRYDATA InquiryData;
 
-  DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
+  DPRINT("SCSIOP_INQUIRY: DeviceExtension %p  TargetId: %lu\n",
+        DeviceExtension, Srb->TargetId);
+
+  InquiryData = Srb->DataBuffer;
+  DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
+
+  /* clear buffer */
+  memset(Srb->DataBuffer, 0, Srb->DataTransferLength);
+
+  /* set device class */
+  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;
+    }
 
-  if ((Srb->PathId != 0) ||
-      (Srb->TargetId > 1) ||
-      (Srb->Lun != 0) ||
-      (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
+  DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
+  if (DeviceParams->ConfigBits & 0x80)
     {
-      return(SRB_STATUS_SELECTION_TIMEOUT);
+      DPRINT("Removable media!\n");
+      InquiryData->RemovableMedia = 1;
     }
 
+  memcpy(InquiryData->VendorId, DeviceParams->ModelNumber, 20);
+  IDESwapBytePairs(InquiryData->VendorId, 20);
+
+  memcpy(&InquiryData->ProductId[12], "    ", 4);
+
+  memcpy(InquiryData->ProductRevisionLevel, DeviceParams->FirmwareRev, 4);
+  IDESwapBytePairs(InquiryData->ProductRevisionLevel, 4);
+
+  InquiryData->AdditionalLength = 31;
+
+  DPRINT("VendorId: '%.20s'\n", InquiryData->VendorId);
+
+  Srb->SrbStatus = SRB_STATUS_SUCCESS;
+  return(SRB_STATUS_SUCCESS);
+}
+
+
+static ULONG
+AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+                 PSCSI_REQUEST_BLOCK Srb)
+{
+  PREAD_CAPACITY_DATA CapacityData;
+  PIDE_DRIVE_IDENTIFY DeviceParams;
+  LARGE_INTEGER LastSector;
 
+  DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
   CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
   DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
 
@@ -1386,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) |
@@ -1406,6 +2367,7 @@ AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
         LastSector,
         CapacityData->LogicalBlockAddress);
 
+  Srb->SrbStatus = SRB_STATUS_SUCCESS;
   return(SRB_STATUS_SUCCESS);
 }
 
@@ -1415,30 +2377,20 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
               PSCSI_REQUEST_BLOCK Srb)
 {
   PIDE_DRIVE_IDENTIFY DeviceParams;
-
-  ULONG StartingSector,i;
+  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->TargetId > 1) ||
-      (Srb->Lun != 0) ||
-      (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
-    {
-      return(SRB_STATUS_SELECTION_TIMEOUT);
-    }
-
-    DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
-          Srb->TargetId);
+  DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
+        Srb->TargetId);
 
   DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
 
@@ -1456,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)
-    {
-      Command = IDE_CMD_READ;
-    }
-  else
+  if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
     {
-      Command = IDE_CMD_WRITE;
+      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
     }
-
-  if (DrvHead & IDE_DH_LBA)
+  else if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
     {
-      DPRINT1("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
+      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;
+
+      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
     {
-      DPRINT1("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
+      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++)
@@ -1529,36 +2490,20 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
         }
       ScsiPortStallExecution(10);
     }
-  DPRINT ("status=%02x\n", Status);
-  DPRINT ("waited %ld usecs for busy to clear\n", Retries * 10);
+  DPRINT("status=%02x\n", Status);
+  DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
   if (Retries >= IDE_MAX_BUSY_RETRIES)
     {
       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  */
   IDEWriteDriveHead(DeviceExtension->CommandPortBase,
                    IDE_DH_FIXED | DrvHead);
 
+  ScsiPortStallExecution(10);
+#if 0
   /*  wait for BUSY to clear and DRDY to assert */
   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
     {
@@ -1569,61 +2514,1038 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
        }
       ScsiPortStallExecution(10);
     }
-  DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
+  DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
   if (Retries >= IDE_MAX_BUSY_RETRIES)
     {
-      DPRINT ("Drive is BUSY for too long after drive select\n");
+      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
 
-  if (Command == IDE_CMD_WRITE)
+  /* Setup command parameters */
+  if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
     {
-      DPRINT1("Write not implemented yet!\n");
-      return(SRB_STATUS_SUCCESS);
+      IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
+      IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount >> 8);
+      IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber[1]);
+      IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow[1]);
+      IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh[1]);
     }
 
-  /* 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);
-
-  /*  Issue command to drive  */
-  IDEWriteCommand(DeviceExtension->CommandPortBase, Command);
-//  ControllerExtension->TimerState = IDETimerCmdWait;
-//  ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
-
-
-  /* FIXME: Write data here! */
-
-
-  DPRINT("AtapiReadWrite() done!\n");
-
-  /* Wait for interrupt. */
-  return(SRB_STATUS_PENDING);
-}
+  IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount & 0xff);
+  IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber[0]);
+  IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow[0]);
+  IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh[0]);
+
+#ifdef ENABLE_DMA
+  if (DeviceExtension->PRDTable &&
+      DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DMA_CMD)
+    {
+      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)
+           {
+              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;
+           }
+       }
+      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;
+           }
+       }
+    }
+
+  AtapiExecuteCommand(DeviceExtension, Command, Handler);
+
+#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;
+
+          /* 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);
+           }
+
+          /* 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");
+
+  /* Wait for interrupt. */
+  return(SRB_STATUS_PENDING);
+}
+
+
+static ULONG
+AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+               PSCSI_REQUEST_BLOCK Srb)
+{
+  ULONG Retries;
+  UCHAR Status;
+
+  DPRINT("AtapiFlushCache() called!\n");
+  DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
+        Srb->TargetId);
+
+  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->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
+    {
+      switch (ErrorReg >> 4)
+       {
+         case SCSI_SENSE_NO_SENSE:
+           DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
+           ScsiStatus = SCSISTAT_CHECK_CONDITION;
+           SrbStatus = SRB_STATUS_ERROR;
+           break;
+
+         case SCSI_SENSE_RECOVERED_ERROR:
+           DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
+           ScsiStatus = 0;
+           SrbStatus = SRB_STATUS_SUCCESS;
+           break;
+
+         case SCSI_SENSE_NOT_READY:
+           DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
+           ScsiStatus = SCSISTAT_CHECK_CONDITION;
+           SrbStatus = SRB_STATUS_ERROR;
+           break;
+
+         case SCSI_SENSE_MEDIUM_ERROR:
+           DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
+           ScsiStatus = SCSISTAT_CHECK_CONDITION;
+           SrbStatus = SRB_STATUS_ERROR;
+           break;
+
+         case SCSI_SENSE_HARDWARE_ERROR:
+           DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
+           ScsiStatus = SCSISTAT_CHECK_CONDITION;
+           SrbStatus = SRB_STATUS_ERROR;
+           break;
+
+         case SCSI_SENSE_ILLEGAL_REQUEST:
+           DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
+           ScsiStatus = SCSISTAT_CHECK_CONDITION;
+           SrbStatus = SRB_STATUS_ERROR;
+           break;
+
+         case SCSI_SENSE_UNIT_ATTENTION:
+           DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
+           ScsiStatus = SCSISTAT_CHECK_CONDITION;
+           SrbStatus = SRB_STATUS_ERROR;
+           break;
+
+         case SCSI_SENSE_DATA_PROTECT:
+           DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
+           ScsiStatus = SCSISTAT_CHECK_CONDITION;
+           SrbStatus = SRB_STATUS_ERROR;
+           break;
+
+         case SCSI_SENSE_BLANK_CHECK:
+           DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
+           ScsiStatus = SCSISTAT_CHECK_CONDITION;
+           SrbStatus = SRB_STATUS_ERROR;
+           break;
+
+         case SCSI_SENSE_ABORTED_COMMAND:
+           DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
+           ScsiStatus = SCSISTAT_CHECK_CONDITION;
+           SrbStatus = SRB_STATUS_ERROR;
+           break;
+
+         default:
+           DPRINT("ATAPI error: Invalid sense key\n");
+           ScsiStatus = 0;
+           SrbStatus = SRB_STATUS_ERROR;
+           break;
+       }
+    }
+  else
+    {
+      DPRINT1("IDE error: %02x\n", ErrorReg);
+
+      ScsiStatus = 0;
+      SrbStatus = SRB_STATUS_ERROR;
+
+#if 0
+      UCHAR SectorCount, SectorNum, CylinderLow, CylinderHigh;
+      UCHAR DriveHead;
+
+      CylinderLow = IDEReadCylinderLow(CommandPortBase);
+      CylinderHigh = IDEReadCylinderHigh(CommandPortBase);
+      DriveHead = IDEReadDriveHead(CommandPortBase);
+      SectorCount = IDEReadSectorCount(CommandPortBase);
+      SectorNum = IDEReadSectorNum(CommandPortBase);
+
+      DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
+             ErrorReg,
+             CylinderLow,
+             CylinderHigh,
+             SectorCount,
+             SectorNum);
+#endif
+    }
+
+
+
+  Srb->ScsiStatus = ScsiStatus;
+
+  DPRINT("AtapiErrorToScsi() done\n");
+
+  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 */