update for HEAD-2003021201
[reactos.git] / drivers / storage / atapi / atapi.c
index be4eaff..d85ba3a 100644 (file)
@@ -41,6 +41,7 @@
  */
 
 #define ENABLE_PCI
+#define ENABLE_NATIVE_PCI
 #define ENABLE_ISA
 
 //  -------------------------------------------------------------------------
@@ -75,6 +76,10 @@ typedef struct _ATAPI_MINIPORT_EXTENSION
   IDE_DRIVE_IDENTIFY DeviceParams[2];
   BOOLEAN DevicePresent[2];
   BOOLEAN DeviceAtapi[2];
+  ULONG TransferSize[2]; 
+  BOOLEAN MultiSectorCommand[2];
+  BOOLEAN DWordIo[2];
+
 
   ULONG CommandPortBase;
   ULONG ControlPortBase;
@@ -83,7 +88,9 @@ typedef struct _ATAPI_MINIPORT_EXTENSION
   BOOLEAN ExpectingInterrupt;
   PSCSI_REQUEST_BLOCK CurrentSrb;
 
-  PUSHORT DataBuffer;
+
+  PUCHAR DataBuffer;
+  ULONG DataTransferLength;
 } ATAPI_MINIPORT_EXTENSION, *PATAPI_MINIPORT_EXTENSION;
 
 
@@ -92,6 +99,29 @@ 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
 
@@ -203,6 +233,9 @@ 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 UCHAR
 AtapiErrorToScsi(PVOID DeviceExtension,
@@ -271,6 +304,7 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
 
   InitData.MapBuffers = TRUE;
 
+
   /* Search the PCI bus for compatibility mode ide controllers */
 #ifdef ENABLE_PCI
   InitData.HwFindAdapter = AtapiFindCompatiblePciController;
@@ -290,30 +324,33 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
 //    statusToReturn = newStatus;
 #endif
 
-  /* Search the ISA bus for ide controllers */
-#ifdef ENABLE_ISA
-  InitData.HwFindAdapter = AtapiFindIsaBusController;
-  InitData.NumberOfAccessRanges = 2;
-  InitData.AdapterInterfaceType = Isa;
+  /* Search the PCI bus for all ide controllers */
+#ifdef ENABLE_NATIVE_PCI
 
-  InitData.VendorId = NULL;
+  InitData.HwFindAdapter = AtapiFindNativePciController;
+  InitData.NumberOfAccessRanges = 3;
+  InitData.AdapterInterfaceType = PCIBus;
+
+  InitData.VendorId = 0;
   InitData.VendorIdLength = 0;
-  InitData.DeviceId = NULL;
+  InitData.DeviceId = 0;
   InitData.DeviceIdLength = 0;
 
+  LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
+
   Status = ScsiPortInitialize(DriverObject,
                              RegistryPath,
                              &InitData,
                              NULL);
-//      if (newStatus < statusToReturn)
-//        statusToReturn = newStatus;
+//  if (newStatus < statusToReturn)
+//    statusToReturn = newStatus;
 #endif
 
-  /* Search the PCI bus for native mode ide controllers */
-#if 0
-  InitData.HwFindAdapter = AtapiFindNativePciController;
+  /* Search the ISA bus for ide controllers */
+#ifdef ENABLE_ISA
+  InitData.HwFindAdapter = AtapiFindIsaBusController;
   InitData.NumberOfAccessRanges = 2;
-  InitData.AdapterInterfaceType = PCIBus;
+  InitData.AdapterInterfaceType = Isa;
 
   InitData.VendorId = NULL;
   InitData.VendorIdLength = 0;
@@ -323,9 +360,9 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
   Status = ScsiPortInitialize(DriverObject,
                              RegistryPath,
                              &InitData,
-                             (PVOID)i);
-//  if (newStatus < statusToReturn)
-//    statusToReturn = newStatus;
+                             NULL);
+//      if (newStatus < statusToReturn)
+//        statusToReturn = newStatus;
 #endif
 
   DPRINT("Returning from DriverEntry\n");
@@ -334,6 +371,90 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
 }
 
 
+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;
+   
+   IoAddress = ScsiPortConvertUlongToPhysicalAddress(CommandPortBase);
+   IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
+                                  InterfaceType,
+                                 ConfigInfo->SystemIoBusNumber,
+                                 IoAddress,
+                                 8,
+                                 TRUE);
+   if (IoBase == NULL)
+   {
+      return FALSE;
+   }
+   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;
+      }
+      ConfigInfo->AccessRanges[2].RangeStart = IoAddress;
+      ConfigInfo->AccessRanges[2].RangeLength = 8;
+      ConfigInfo->AccessRanges[2].RangeInMemory = FALSE;
+   }
+   ConfigInfo->BusInterruptLevel = InterruptVector;
+   ConfigInfo->BusInterruptVector = InterruptVector;
+   ConfigInfo->InterruptMode = (InterfaceType == Isa) ? Latched : LevelSensitive;
+
+   if ((CommandPortBase == 0x1F0 || ControlPortBase == 0x3F4) && !ConfigInfo->AtdiskPrimaryClaimed)
+   {
+      ConfigInfo->AtdiskPrimaryClaimed = TRUE;
+   }
+   if ((CommandPortBase == 0x170 || ControlPortBase == 0x374) && !ConfigInfo->AtdiskSecondaryClaimed)
+   {
+      ConfigInfo->AtdiskSecondaryClaimed = TRUE;
+   }
+   return TRUE;
+}
+
+
+#ifdef ENABLE_PCI
 static ULONG STDCALL
 AtapiFindCompatiblePciController(PVOID DeviceExtension,
                                 PVOID HwContext,
@@ -346,9 +467,13 @@ AtapiFindCompatiblePciController(PVOID DeviceExtension,
   PCI_SLOT_NUMBER SlotNumber;
   PCI_COMMON_CONFIG PciConfig;
   ULONG DataSize;
+  ULONG StartDeviceNumber;
+  ULONG DeviceNumber;
+  ULONG StartFunctionNumber;
   ULONG FunctionNumber;
   BOOLEAN ChannelFound;
   BOOLEAN DeviceFound;
+  ULONG BusMasterBasePort = 0;
 
   DPRINT("AtapiFindCompatiblePciController() Bus: %lu  Slot: %lu\n",
          ConfigInfo->SystemIoBusNumber,
@@ -361,155 +486,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.AsULONG = FunctionNumber;
-
-      ChannelFound = FALSE;
-      DeviceFound = FALSE;
-
-      DataSize = ScsiPortGetBusData(DeviceExtension,
-                                   PCIConfiguration,
-                                   0,
-                                   SlotNumber.u.AsULONG,
-                                   &PciConfig,
-                                   sizeof(PCI_COMMON_CONFIG));
-//      if (DataSize != sizeof(PCI_COMMON_CONFIG) ||
-//       PciConfig.VendorID == PCI_INVALID_VENDORID)
-      if (DataSize == 0)
+  SlotNumber.u.AsULONG = ConfigInfo->SlotNumber;
+  StartDeviceNumber = SlotNumber.u.bits.DeviceNumber;
+  StartFunctionNumber = SlotNumber.u.bits.FunctionNumber;
+  for (DeviceNumber = StartDeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
+  {
+     SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+     for (FunctionNumber = StartFunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
+     {
+       SlotNumber.u.bits.FunctionNumber = FunctionNumber;
+       ChannelFound = FALSE;
+       DeviceFound = FALSE;
+
+        DataSize = ScsiPortGetBusData(DeviceExtension,
+                                     PCIConfiguration,
+                                     ConfigInfo->SystemIoBusNumber,
+                                     SlotNumber.u.AsULONG,
+                                     &PciConfig,
+                                     PCI_COMMON_HDR_LENGTH);
+        if (DataSize != PCI_COMMON_HDR_LENGTH)
        {
-//       if ((SlotNumber.u.AsULONG & 0x07) == 0)
-//         return(SP_RETURN_ERROR); /* No bus found */
-
-         continue;
-//       return(SP_RETURN_ERROR);
+          if (FunctionNumber == 0)
+          {
+             break;
+          }
+          else
+          {
+             continue;
+          }
        }
-
-      if (PciConfig.BaseClass == 0x01 &&
-         PciConfig.SubClass == 0x01) // &&
-//       (PciConfig.ProgIf & 0x05) == 0)
+         
+       DPRINT("%x %x\n", PciConfig.BaseClass, PciConfig.SubClass);
+       if (PciConfig.BaseClass == 0x01 &&
+           PciConfig.SubClass == 0x01) // &&
+//         (PciConfig.ProgIf & 0x05) == 0)
        {
-         /* both channels are in compatibility mode */
-         DPRINT("Bus %1lu  Device %2lu  Func %1lu  VenID 0x%04hx  DevID 0x%04hx\n",
-                ConfigInfo->SystemIoBusNumber,
-                SlotNumber.u.bits.DeviceNumber,
-                SlotNumber.u.bits.FunctionNumber,
-                PciConfig.VendorID,
-                PciConfig.DeviceID);
-         DPRINT("ProgIF 0x%02hx\n", PciConfig.ProgIf);
-
-         DPRINT("Found IDE controller in compatibility mode!\n");
-
-         ConfigInfo->NumberOfBuses = 1;
-         ConfigInfo->MaximumNumberOfTargets = 2;
-         ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
-
-         if (PciConfig.ProgIf & 0x80)
-           {
+          /* 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] & 0x00000001)
-               {
-                 DPRINT("  IDE Bus Master Registers at IO %lx\n",
-                         PciConfig.u.type0.BaseAddresses[4] & ~0x00000003);
-               }
-           }
-
-         if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
-           {
+             if (PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_SPACE)
+             {
+                 BusMasterBasePort = PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK;
+                 DPRINT("  IDE Bus Master Registers at IO %lx\n", BusMasterBasePort);
+             }
+          }
+          if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
+          {
              /* Both channels unclaimed: Claim primary channel */
              DPRINT("Primary channel!\n");
-
-             DevExt->CommandPortBase = 0x01F0;
-             DevExt->ControlPortBase = 0x03F6;
-
-             ConfigInfo->BusInterruptLevel = 14;
-             ConfigInfo->BusInterruptVector = 14;
-             ConfigInfo->InterruptMode = LevelSensitive;
-
-             ConfigInfo->AccessRanges[0].RangeStart =
-               ScsiPortConvertUlongToPhysicalAddress(0x01F0);
-             ConfigInfo->AccessRanges[0].RangeLength = 8;
-             ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
-
-             ConfigInfo->AccessRanges[1].RangeStart =
-               ScsiPortConvertUlongToPhysicalAddress(0x03F6);
-             ConfigInfo->AccessRanges[1].RangeLength = 1;
-             ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
-
-             /* Claim bus master registers */
-             if (PciConfig.ProgIf & 0x80)
-               {
-                 DevExt->BusMasterRegisterBase =
-                   PciConfig.u.type0.BaseAddresses[4] & ~0x00000003;
-
-                 ConfigInfo->AccessRanges[2].RangeStart =
-                   ScsiPortConvertUlongToPhysicalAddress(DevExt->BusMasterRegisterBase);
-                 ConfigInfo->AccessRanges[2].RangeLength = 8;
-                 ConfigInfo->AccessRanges[2].RangeInMemory = FALSE;
-               }
-
-             ConfigInfo->AtdiskPrimaryClaimed = TRUE;
-             ChannelFound = TRUE;
-             *Again = TRUE;
-           }
-         else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
-           {
+              ChannelFound = AtapiClaimHwResources(DevExt,
+                                                  ConfigInfo,
+                                                  PCIBus,
+                                                  0x1F0,
+                                                  0x3F4,
+                                                  BusMasterBasePort,
+                                                  14);
+              *Again = TRUE;
+          }
+          else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
+          {
              /* Primary channel already claimed: claim secondary channel */
              DPRINT("Secondary channel!\n");
 
-             DevExt->CommandPortBase = 0x0170;
-             DevExt->ControlPortBase = 0x0376;
-
-             ConfigInfo->BusInterruptLevel = 15;
-             ConfigInfo->BusInterruptVector = 15;
-             ConfigInfo->InterruptMode = LevelSensitive;
-
-             ConfigInfo->AccessRanges[0].RangeStart =
-               ScsiPortConvertUlongToPhysicalAddress(0x0170);
-             ConfigInfo->AccessRanges[0].RangeLength = 8;
-             ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
-
-             ConfigInfo->AccessRanges[1].RangeStart =
-               ScsiPortConvertUlongToPhysicalAddress(0x0376);
-             ConfigInfo->AccessRanges[1].RangeLength = 1;
-             ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
-
-             /* Claim bus master registers */
-             if (PciConfig.ProgIf & 0x80)
-               {
-                 DevExt->BusMasterRegisterBase =
-                   (PciConfig.u.type0.BaseAddresses[4] & ~0x00000003) + 8;
-
-                 ConfigInfo->AccessRanges[2].RangeStart =
-                   ScsiPortConvertUlongToPhysicalAddress(DevExt->BusMasterRegisterBase);
-                 ConfigInfo->AccessRanges[2].RangeLength = 8;
-                 ConfigInfo->AccessRanges[2].RangeInMemory = FALSE;
-               }
-
-             ConfigInfo->AtdiskSecondaryClaimed = TRUE;
-             ChannelFound = TRUE;
+              ChannelFound = AtapiClaimHwResources(DevExt,
+                                                  ConfigInfo,
+                                                  PCIBus,
+                                                  0x170,
+                                                  0x374,
+                                                  BusMasterBasePort ? BusMasterBasePort + 8 : 0,
+                                                  15);
              *Again = FALSE;
-           }
-
-         /* Find attached devices */
-         if (ChannelFound == TRUE)
-           {
-             DeviceFound = AtapiFindDevices(DevExt,
-                                            ConfigInfo);
-           }
-         DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
-         return(SP_RETURN_FOUND);
-        }
-    }
-
+          }
+          /* Find attached devices */
+          if (ChannelFound)
+          {
+             DeviceFound = AtapiFindDevices(DevExt, ConfigInfo);
+             ConfigInfo->SlotNumber = SlotNumber.u.AsULONG;
+             DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
+             return(SP_RETURN_FOUND);
+          }
+       }
+       if (FunctionNumber == 0 && !(PciConfig.HeaderType & PCI_MULTIFUNCTION))
+       {
+          break;
+       }
+     } 
+     StartFunctionNumber = 0;
+  }
   DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
 
   return(SP_RETURN_NOT_FOUND);
 }
+#endif
 
 
+#ifdef ENABLE_ISA
 static ULONG STDCALL
 AtapiFindIsaBusController(PVOID DeviceExtension,
                          PVOID HwContext,
@@ -535,47 +621,27 @@ AtapiFindIsaBusController(PVOID DeviceExtension,
       /* Both channels unclaimed: Claim primary channel */
       DPRINT("Primary channel!\n");
 
-      DevExt->CommandPortBase = 0x01F0;
-      DevExt->ControlPortBase = 0x03F6;
-
-      ConfigInfo->BusInterruptLevel = 14;
-      ConfigInfo->BusInterruptVector = 14;
-      ConfigInfo->InterruptMode = LevelSensitive;
-
-      ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x01F0);
-      ConfigInfo->AccessRanges[0].RangeLength = 8;
-      ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
-
-      ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x03F6);
-      ConfigInfo->AccessRanges[1].RangeLength = 1;
-      ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
-
-      ConfigInfo->AtdiskPrimaryClaimed = TRUE;
-      ChannelFound = TRUE;
-      *Again = FALSE/*TRUE*/;
+      ChannelFound = AtapiClaimHwResources(DevExt,
+                                          ConfigInfo,
+                                          Isa,
+                                          0x1F0,
+                                          0x3F4,
+                                          0,
+                                          14);
+      *Again = TRUE;
     }
   else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
     {
       /* Primary channel already claimed: claim secondary channel */
       DPRINT("Secondary channel!\n");
 
-      DevExt->CommandPortBase = 0x0170;
-      DevExt->ControlPortBase = 0x0376;
-
-      ConfigInfo->BusInterruptLevel = 15;
-      ConfigInfo->BusInterruptVector = 15;
-      ConfigInfo->InterruptMode = LevelSensitive;
-
-      ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0170);
-      ConfigInfo->AccessRanges[0].RangeLength = 8;
-      ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
-
-      ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0376);
-      ConfigInfo->AccessRanges[1].RangeLength = 1;
-      ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
-
-      ConfigInfo->AtdiskSecondaryClaimed = TRUE;
-      ChannelFound = TRUE;
+      ChannelFound = AtapiClaimHwResources(DevExt,
+                                          ConfigInfo,
+                                          Isa,
+                                          0x170,
+                                          0x374,
+                                          0,
+                                          15);
       *Again = FALSE;
     }
   else
@@ -590,13 +656,16 @@ AtapiFindIsaBusController(PVOID DeviceExtension,
     {
       DeviceFound = AtapiFindDevices(DevExt,
                                     ConfigInfo);
+      DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
+      return(SP_RETURN_FOUND);
     }
-
-  DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
-  return(SP_RETURN_FOUND);
+  *Again = FALSE;
+  return SP_RETURN_NOT_FOUND;
 }
+#endif
 
 
+#ifdef ENABLE_NATIVE_PCI
 static ULONG STDCALL
 AtapiFindNativePciController(PVOID DeviceExtension,
                             PVOID HwContext,
@@ -606,15 +675,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
@@ -700,23 +883,36 @@ AtapiInterrupt(IN PVOID DeviceExtension)
   BOOLEAN IsAtapi;
   ULONG Retries;
   PUCHAR TargetAddress;
-  ULONG SectorSize;
   ULONG TransferSize;
 
   DPRINT("AtapiInterrupt() called!\n");
 
   DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
+
+  CommandPortBase = DevExt->CommandPortBase;
+  ControlPortBase = DevExt->ControlPortBase;
+
   if (DevExt->ExpectingInterrupt == FALSE)
     {
-      DPRINT("AtapiInterrupt(): Unexpected interrupt\n");
+      DeviceStatus = IDEReadStatus(CommandPortBase);
+      DPRINT("AtapiInterrupt(): Unexpected interrupt (port=%x)\n", CommandPortBase);
       return(FALSE);
     }
 
+  /* check if it was our irq */
+  if ((DeviceStatus = IDEReadAltStatus(ControlPortBase)) & IDE_SR_BUSY)
+  {
+     ScsiPortStallExecution(1);
+     if ((DeviceStatus = IDEReadAltStatus(ControlPortBase) & IDE_SR_BUSY))
+     {
+        DPRINT("AtapiInterrupt(): Unexpected interrupt (port=%x)\n", CommandPortBase);
+        return(FALSE);
+     }
+  }
+
   Srb = DevExt->CurrentSrb;
   DPRINT("Srb: %p\n", Srb);
 
-  CommandPortBase = DevExt->CommandPortBase;
-  ControlPortBase = DevExt->ControlPortBase;
   DPRINT("CommandPortBase: %lx  ControlPortBase: %lx\n", CommandPortBase, ControlPortBase);
 
   IsAtapi = DevExt->DeviceAtapi[Srb->TargetId];
@@ -727,25 +923,6 @@ AtapiInterrupt(IN PVOID DeviceExtension)
   DeviceStatus = IDEReadStatus(CommandPortBase);
   DPRINT("DeviceStatus: %x\n", DeviceStatus);
 
-  if (DeviceStatus & IDE_SR_BUSY)
-    {
-      /* Wait for BUSY to drop */
-      for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
-       {
-         DeviceStatus = IDEReadStatus(CommandPortBase);
-         if (!(DeviceStatus & IDE_SR_BUSY))
-           {
-             break;
-           }
-         ScsiPortStallExecution(10);
-       }
-      if (Retries >= IDE_MAX_BUSY_RETRIES)
-       {
-         DPRINT1("Drive is BUSY for too long\n");
-         /* FIXME: handle timeout */
-       }
-    }
-
   if ((DeviceStatus & IDE_SR_ERR) &&
       (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE))
     {
@@ -760,7 +937,7 @@ AtapiInterrupt(IN PVOID DeviceExtension)
          DPRINT("Read data\n");
 
          /* Update controller/device state variables */
-         TargetAddress = Srb->DataBuffer;
+         TargetAddress = DevExt->DataBuffer;
 
          if (IsAtapi)
            {
@@ -769,23 +946,27 @@ AtapiInterrupt(IN PVOID DeviceExtension)
            }
          else
            {
-             TransferSize = DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
+             TransferSize = DevExt->TransferSize[Srb->TargetId];
            }
 
          DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
          DPRINT("TransferSize: %lu\n", TransferSize);
 
-         if (Srb->DataTransferLength <= TransferSize)
+         if (DevExt->DataTransferLength <= TransferSize)
            {
-             Srb->DataTransferLength = 0;
+             if (!IsAtapi)
+             {
+                TransferSize = DevExt->DataTransferLength;
+             }
+             DevExt->DataTransferLength = 0;
              IsLastBlock = TRUE;
            }
          else
            {
-             Srb->DataTransferLength -= TransferSize;
+             DevExt->DataTransferLength -= TransferSize;
              IsLastBlock = FALSE;
            }
-         Srb->DataBuffer += TransferSize;
+         DevExt->DataBuffer += TransferSize;
          DPRINT("IsLastBlock == %s\n", (IsLastBlock) ? "TRUE" : "FALSE");
 
          /* Wait for DRQ assertion */
@@ -797,10 +978,18 @@ AtapiInterrupt(IN PVOID DeviceExtension)
            }
 
          /* Copy the block of data */
-         IDEReadBlock(CommandPortBase,
-                      TargetAddress,
-                      TransferSize);
-
+         if (DevExt->DWordIo[Srb->TargetId])
+         {
+            IDEReadBlock32(CommandPortBase,
+                           TargetAddress,
+                           TransferSize);
+         }
+         else
+         {
+            IDEReadBlock(CommandPortBase,
+                         TargetAddress,
+                         TransferSize);
+         }
          /* check DRQ */
          if (IsLastBlock)
            {
@@ -812,10 +1001,10 @@ AtapiInterrupt(IN PVOID DeviceExtension)
                }
 
              /* Check for data overrun */
-             if (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
+             while (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
                {
-                 /* FIXME: Handle error! */
-                 DPRINT1("AtapiInterrupt(): data overrun error!");
+                 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
+                 IDEReadWord(CommandPortBase);
                }
            }
 
@@ -825,39 +1014,47 @@ AtapiInterrupt(IN PVOID DeviceExtension)
        {
          DPRINT("Write data\n");
 
-         if (Srb->DataTransferLength == 0)
+         if (DevExt->DataTransferLength == 0)
            {
-
-             for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
-                  (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
-                  Retries++)
-               {
-                 KeStallExecutionProcessor(10);
-               }
-
              /* Check for data overrun */
-             if (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
+             if (DeviceStatus & IDE_SR_DRQ)
                {
                  /* FIXME: Handle error! */
-                 DPRINT1("AtapiInterrupt(): data overrun error!");
+                 /* This can occure if the irq is shared with an other and if the 
+                    ide controller has a write buffer. We have write the last sectors
+                    and the other device has a irq before ours. The isr is called but 
+                    we haven't a interrupt. The controller writes the sector buffer 
+                    and the status register shows DRQ because the write is not ended. */
+                 DPRINT("AtapiInterrupt(): data overrun error!\n");
                }
-
-             DevExt->ExpectingInterrupt = FALSE;
              IsLastBlock = TRUE;
            }
          else
            {
-             /* Update SRB data */
-             SectorSize = DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
-
-             TargetAddress = Srb->DataBuffer;
-             Srb->DataBuffer += SectorSize;
-             Srb->DataTransferLength -= SectorSize;
+             /* Update DevExt data */
+             TransferSize = DevExt->TransferSize[Srb->TargetId];
+             if (DevExt->DataTransferLength < TransferSize)
+             {
+                TransferSize = DevExt->DataTransferLength;
+             }
+                
+             TargetAddress = DevExt->DataBuffer;
+             DevExt->DataBuffer += TransferSize;
+             DevExt->DataTransferLength -= TransferSize;
 
              /* Write the sector */
-             IDEWriteBlock(CommandPortBase,
-                           TargetAddress,
-                           SectorSize);
+              if (DevExt->DWordIo[Srb->TargetId])
+             {
+                IDEWriteBlock32(CommandPortBase,
+                                TargetAddress,
+                                TransferSize);
+             }
+             else
+             {
+                IDEWriteBlock(CommandPortBase,
+                              TargetAddress,
+                              TransferSize);
+             }
            }
 
          Srb->SrbStatus = SRB_STATUS_SUCCESS;
@@ -897,11 +1094,6 @@ AtapiInterrupt(IN PVOID DeviceExtension)
   return(TRUE);
 }
 
-
-
-
-
-
 //  ----------------------------------------------------  Discardable statics
 
 
@@ -958,8 +1150,22 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
                           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);
+
+      if (Low != 0x55 || High != 0xaa)
+      {
+         DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber, CommandPortBase);
+        continue;
+      }
+
       IDEWriteCommand(CommandPortBase, IDE_CMD_RESET);
 
       for (Retries = 0; Retries < 20000; Retries++)
@@ -996,6 +1202,9 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
              DPRINT("  ATAPI drive found!\n");
              DeviceExtension->DevicePresent[UnitNumber] = TRUE;
              DeviceExtension->DeviceAtapi[UnitNumber] = TRUE;
+             DeviceExtension->TransferSize[UnitNumber] = DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
+              DeviceExtension->MultiSectorCommand[UnitNumber] = FALSE;
+              DeviceExtension->DWordIo[UnitNumber] = FALSE;
              DeviceFound = TRUE;
            }
          else
@@ -1014,6 +1223,20 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
              DPRINT("  IDE drive found!\n");
              DeviceExtension->DevicePresent[UnitNumber] = TRUE;
              DeviceExtension->DeviceAtapi[UnitNumber] = FALSE;
+             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->MultiSectorCommand[UnitNumber] = TRUE;
+             }
+             else
+             {
+                 DeviceExtension->MultiSectorCommand[UnitNumber] = FALSE;
+             }
+              DeviceExtension->DWordIo[UnitNumber] = DeviceExtension->DeviceParams[UnitNumber].DWordIo ? TRUE : FALSE;
              DeviceFound = TRUE;
            }
          else
@@ -1023,6 +1246,14 @@ AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
        }
     }
 
+  /* Reset pending interrupts */
+  IDEReadStatus(CommandPortBase);
+  /* Reenable interrupts */
+  IDEWriteDriveControl(ControlPortBase, 0);
+  ScsiPortStallExecution(500);
+  /* Return with drive 0 selected */
+  IDEWriteDriveHead(CommandPortBase, IDE_DH_FIXED);
+  ScsiPortStallExecution(500);
 
   DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound) ? "TRUE" : "FALSE");
 
@@ -1152,8 +1383,9 @@ AtapiIdentifyDevice(IN ULONG CommandPort,
          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("RWMultMax?:%04x  RWMult?:%02x  LBA:%d  DMA:%d  MinPIO:%d ns  MinDMA:%d ns\n",
+         (DrvParms->RWMultImplemented),
+        (DrvParms->RWMultCurrent) & 0xff,
          (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
          (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
          DrvParms->MinPIOTransTime,
@@ -1168,21 +1400,29 @@ AtapiIdentifyDevice(IN ULONG CommandPort,
          DrvParms->TMSectorCountLo,
          (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
 
-  DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
-  if (DrvParms->BytesPerSector == 0)
+  if (! Atapi && 0 != (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED))
     {
+      /* LBA ATA drives always have a sector size of 512 */
       DrvParms->BytesPerSector = 512;
     }
   else
     {
-      for (i = 15; i >= 0; i--)
-       {
-         if (DrvParms->BytesPerSector & (1 << i))
-           {
-             DrvParms->BytesPerSector = 1 << i;
-             break;
-           }
-       }
+      DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
+      if (DrvParms->BytesPerSector == 0)
+        {
+          DrvParms->BytesPerSector = 512;
+        }
+      else
+        {
+          for (i = 15; i >= 0; i--)
+            {
+              if (DrvParms->BytesPerSector & (1 << i))
+                {
+                  DrvParms->BytesPerSector = 1 << i;
+                  break;
+                }
+            }
+        }
     }
   DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
 
@@ -1229,7 +1469,6 @@ AtapiPolledRead(IN ULONG CommandPort,
   ULONG RetryCount;
   BOOLEAN Junk = FALSE;
   UCHAR Status;
-  UCHAR Control;
 
 //#if 0
   /* Wait for BUSY to clear */
@@ -1256,8 +1495,7 @@ AtapiPolledRead(IN ULONG CommandPort,
   ScsiPortStallExecution(500);
 
   /* Disable interrupts */
-  Control = IDEReadAltStatus(ControlPort);
-  IDEWriteDriveControl(ControlPort, Control | IDE_DC_nIEN);
+  IDEWriteDriveControl(ControlPort, IDE_DC_nIEN);
   ScsiPortStallExecution(500);
 
 #if 0
@@ -1318,7 +1556,10 @@ AtapiPolledRead(IN ULONG CommandPort,
        {
          if (Status & IDE_SR_ERR)
            {
-             IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
+             IDEWriteDriveControl(ControlPort, 0);
+             ScsiPortStallExecution(50);
+             IDEReadStatus(CommandPort);
+
              return(IDE_ER_ABRT);
            }
          if (Status & IDE_SR_DRQ)
@@ -1327,7 +1568,10 @@ AtapiPolledRead(IN ULONG CommandPort,
            }
          else
            {
-             IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
+             IDEWriteDriveControl(ControlPort, 0);
+             ScsiPortStallExecution(50);
+             IDEReadStatus(CommandPort);
+
              return(IDE_ER_ABRT);
            }
        }
@@ -1337,7 +1581,10 @@ AtapiPolledRead(IN ULONG CommandPort,
   /*  timed out  */
   if (RetryCount >= IDE_MAX_POLL_RETRIES)
     {
-      IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
+      IDEWriteDriveControl(ControlPort, 0);
+      ScsiPortStallExecution(50);
+      IDEReadStatus(CommandPort);
+
       return(IDE_ER_ABRT);
     }
 
@@ -1364,7 +1611,10 @@ AtapiPolledRead(IN ULONG CommandPort,
            {
              if (Status & IDE_SR_ERR)
                {
-                 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
+                 IDEWriteDriveControl(ControlPort, 0);
+                 ScsiPortStallExecution(50);
+                 IDEReadStatus(CommandPort);
+
                  return(IDE_ER_ABRT);
                }
              if (Status & IDE_SR_DRQ)
@@ -1383,7 +1633,10 @@ AtapiPolledRead(IN ULONG CommandPort,
                      DPRINT("Read %lu sectors of junk!\n",
                             SectorCount - SectorCnt);
                    }
-                 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
+                 IDEWriteDriveControl(ControlPort, 0);
+                 ScsiPortStallExecution(50);
+                 IDEReadStatus(CommandPort);
+
                  return(0);
                }
            }
@@ -1438,7 +1691,8 @@ AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
                        Srb));
 
   /* Set pointer to data buffer. */
-  DeviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
+  DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
+  DeviceExtension->DataTransferLength = Srb->DataTransferLength;
   DeviceExtension->CurrentSrb = Srb;
 
   /* Wait for BUSY to clear */
@@ -1485,10 +1739,10 @@ AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
     }
 #endif
 
-  if (Srb->DataTransferLength < 0x10000)
+  if (DeviceExtension->DataTransferLength < 0x10000)
     {
-      ByteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
-      ByteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8);
+      ByteCountLow = (UCHAR)(DeviceExtension->DataTransferLength & 0xFF);
+      ByteCountHigh = (UCHAR)(DeviceExtension->DataTransferLength >> 8);
     }
   else
     {
@@ -1504,7 +1758,7 @@ AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
   IDEWriteCylinderLow(DeviceExtension->CommandPortBase, ByteCountLow);
 
   /* Issue command to drive */
-  IDEWriteCommand(DeviceExtension->CommandPortBase, 0xA0); /* Packet command */
+  IDEWriteCommand(DeviceExtension->CommandPortBase, IDE_CMD_PACKET);
 
   /* Wait for DRQ to assert */
   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
@@ -1564,6 +1818,11 @@ AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
                                   Srb);
        break;
 
+      case SCSIOP_SYNCHRONIZE_CACHE:
+       SrbStatus = AtapiFlushCache(DeviceExtension,
+                                   Srb);
+       break;
+
       case SCSIOP_MODE_SENSE:
       case SCSIOP_TEST_UNIT_READY:
       case SCSIOP_VERIFY:
@@ -1827,11 +2086,11 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
 
   if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
     {
-      Command = IDE_CMD_READ;
+      Command = DeviceExtension->MultiSectorCommand[Srb->TargetId] ? IDE_CMD_READ_MULTIPLE : IDE_CMD_READ;
     }
   else
     {
-      Command = IDE_CMD_WRITE;
+      Command = DeviceExtension->MultiSectorCommand[Srb->TargetId] ? IDE_CMD_WRITE_MULTIPLE : IDE_CMD_WRITE;
     }
 
   if (DrvHead & IDE_DH_LBA)
@@ -1860,12 +2119,10 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
     }
 
   /* 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++)
@@ -1883,24 +2140,6 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
     {
       DPRINT ("Drive is BUSY for too long\n");
       return(SRB_STATUS_BUSY);
-#if 0
-      if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
-        {
-          DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
-          Irp = ControllerExtension->CurrentIrp;
-          Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
-          Irp->IoStatus.Information = 0;
-
-          return FALSE;
-        }
-      else
-        {
-          DPRINT ("Beginning drive reset sequence\n");
-          IDEBeginControllerReset(ControllerExtension);
-
-          return TRUE;
-        }
-#endif
     }
 
   /*  Select the desired drive  */
@@ -1924,30 +2163,9 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
     {
       DPRINT("Drive is BUSY for too long after drive select\n");
       return(SRB_STATUS_BUSY);
-#if 0
-      if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
-       {
-          DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
-          Irp = ControllerExtension->CurrentIrp;
-          Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
-          Irp->IoStatus.Information = 0;
-
-          return FALSE;
-       }
-      else
-        {
-          DPRINT("Beginning drive reset sequence\n");
-          IDEBeginControllerReset(ControllerExtension);
-
-          return TRUE;
-        }
-#endif
     }
 #endif
 
-  /* Indicate expecting an interrupt. */
-  DeviceExtension->ExpectingInterrupt = TRUE;
-
   /* Setup command parameters */
   IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
   IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount);
@@ -1960,10 +2178,10 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
   IDEWriteCommand(DeviceExtension->CommandPortBase, Command);
 
   /* Write data block */
-  if (Command == IDE_CMD_WRITE)
+  if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
     {
       PUCHAR TargetAddress;
-      ULONG SectorSize;
+      ULONG TransferSize;
 
       /* Wait for controller ready */
       for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
@@ -1975,40 +2193,39 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
            }
          KeStallExecutionProcessor(10);
        }
-      if (Retries >= IDE_MAX_BUSY_RETRIES)
+      if (Retries >= IDE_MAX_WRITE_RETRIES)
        {
-         DPRINT("Drive is BUSY for too long after sending write command\n");
+         DPRINT1("Drive is BUSY for too long after sending write command\n");
          return(SRB_STATUS_BUSY);
-#if 0
-          if (DeviceExtension->Retries++ > IDE_MAX_CMD_RETRIES)
-            {
-              Irp = ControllerExtension->CurrentIrp;
-              Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
-              Irp->IoStatus.Information = 0;
-
-              return FALSE;
-            }
-          else
-            {
-              IDEBeginControllerReset(ControllerExtension);
-
-              return TRUE;
-            }
-#endif
        }
 
-      /* Update SRB data */
-      SectorSize = DeviceExtension->DeviceParams[Srb->TargetId].BytesPerSector;
-      TargetAddress = Srb->DataBuffer;
-      Srb->DataBuffer += SectorSize;
-      Srb->DataTransferLength -= SectorSize;
+      /* Update DeviceExtension data */
+      TransferSize = DeviceExtension->TransferSize[Srb->TargetId];
+      if (DeviceExtension->DataTransferLength < TransferSize)
+      {
+        TransferSize = DeviceExtension->DataTransferLength;
+      }
+
+      TargetAddress = DeviceExtension->DataBuffer;
+      DeviceExtension->DataBuffer += TransferSize;
+      DeviceExtension->DataTransferLength -= TransferSize;
 
       /* Write data block */
-      IDEWriteBlock(DeviceExtension->CommandPortBase,
-                   TargetAddress,
-                   SectorSize);
+      if (DeviceExtension->DWordIo[Srb->TargetId])
+      {
+         IDEWriteBlock32(DeviceExtension->CommandPortBase,
+                        TargetAddress,
+                        TransferSize);
+      }
+      else
+      {
+         IDEWriteBlock(DeviceExtension->CommandPortBase,
+                      TargetAddress,
+                      TransferSize);
+      }
     }
-
+  /* Indicate expecting an interrupt. */
+  DeviceExtension->ExpectingInterrupt = TRUE;
 
   DPRINT("AtapiReadWrite() done!\n");
 
@@ -2017,6 +2234,94 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
 }
 
 
+static ULONG
+AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+               PSCSI_REQUEST_BLOCK Srb)
+{
+  ULONG Retries;
+  UCHAR Status;
+
+  DPRINT1("AtapiFlushCache() called!\n");
+
+  if (Srb->PathId != 0)
+    {
+      Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
+      return(SRB_STATUS_INVALID_PATH_ID);
+    }
+
+  if (Srb->TargetId > 1)
+    {
+      Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
+      return(SRB_STATUS_INVALID_TARGET_ID);
+    }
+
+  if (Srb->Lun != 0)
+    {
+      Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+      return(SRB_STATUS_INVALID_LUN);
+    }
+
+  if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
+    {
+      Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+      return(SRB_STATUS_NO_DEVICE);
+    }
+
+  DPRINT1("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
+        Srb->TargetId);
+
+  /* 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 */
+  IDEWriteCommand(DeviceExtension->CommandPortBase, IDE_CMD_FLUSH_CACHE);
+
+  /* Wait for controller ready */
+  for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
+    {
+      BYTE  Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+      if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
+       {
+         break;
+       }
+      KeStallExecutionProcessor(10);
+    }
+  if (Retries >= IDE_MAX_WRITE_RETRIES)
+    {
+      DPRINT1("Drive is BUSY for too long after sending write command\n");
+      return(SRB_STATUS_BUSY);
+    }
+
+  /* Indicate expecting an interrupt. */
+  DeviceExtension->ExpectingInterrupt = TRUE;
+
+  DPRINT1("AtapiFlushCache() done!\n");
+
+  /* Wait for interrupt. */
+  return(SRB_STATUS_PENDING);
+}
+
+
 static UCHAR
 AtapiErrorToScsi(PVOID DeviceExtension,
                 PSCSI_REQUEST_BLOCK Srb)