[UNIATA] Update to version 0.47a. CORE-15930
[reactos.git] / drivers / storage / ide / uniata / id_ata.cpp
index 9c53505..0a0c586 100644 (file)
@@ -1,12 +1,12 @@
 /*++
 
-Copyright (c) 2002-2012 Alexandr A. Telyatnikov (Alter)
+Copyright (c) 2002-2018 Alexandr A. Telyatnikov (Alter)
 
 Module Name:
     id_ata.cpp
 
 Abstract:
-    This is the miniport driver for ATA/ATAPI IDE controllers
+    This is the miniport driver for ATA/ATAPI IDE/SATA/AHCI controllers
     with Busmaster DMA and Serial ATA support
 
 Author:
@@ -37,8 +37,8 @@ Revision History:
     Some parts of code were taken from FreeBSD 4.3-6.1 ATA driver by
          Søren Schmidt, Copyright (c) 1998-2007
 
-    All parts of code are greatly changed/updated by
-         Alter, Copyright (c) 2002-2007:
+    All parts of code are significantly changed/updated by
+         Alter, Copyright (c) 2002-2014:
 
     1. Internal command queueing/reordering
     2. Drive identification
@@ -49,9 +49,12 @@ Revision History:
     7. XP support (binary compatibility)
     8. Serial ATA (SATA/SATA2/SATA3) support
     9. NT 3.51 support (binary compatibility)
+    10. AHCI support
 
     etc. (See todo.txt)
 
+Licence:
+    GPLv2
 
 --*/
 
@@ -68,8 +71,8 @@ WCHAR SavedRegPathBuffer[256];
 
 #endif //UNIATA_CORE
 
-UCHAR AtaCommands48[256];
-UCHAR AtaCommandFlags[256];
+//UCHAR AtaCommands48[256];
+//UCHAR AtaCommandFlags[256];
 
 ULONG  SkipRaids = 1;
 ULONG  ForceSimplex = 0;
@@ -83,23 +86,31 @@ ULONG  g_LogToDisplay = 0;
 
 ULONG  g_WaitBusyInISR = 1;
 
+ULONG  g_opt_WaitBusyResetCount = 10000; // 20000
 ULONG  g_opt_WaitBusyCount = 200; // 20000
 ULONG  g_opt_WaitBusyDelay = 10;  // 150
 ULONG  g_opt_WaitDrqDelay  = 10; // 100
 ULONG  g_opt_WaitBusyLongCount = 2000; // 2000
 ULONG  g_opt_WaitBusyLongDelay = 250;  // 250
-ULONG  g_opt_MaxIsrWait = 40; //
+ULONG  g_opt_MaxIsrWait = 40;
+
+ULONG  g_opt_DriveSelectNanoDelay = 0; // 400; // ns
+
 BOOLEAN g_opt_AtapiSendDisableIntr = 0; // 0
 BOOLEAN g_opt_AtapiDmaRawRead = 1; // 0
+BOOLEAN g_opt_AtapiNoDma = FALSE;
+BOOLEAN g_opt_BochsDmaReadWorkaround = FALSE;
 BOOLEAN hasPCI = FALSE;
 
 ULONG g_opt_VirtualMachine = 0; // Auto
 
 BOOLEAN InDriverEntry = TRUE;
+BOOLEAN g_Dump = FALSE;
 
 BOOLEAN g_opt_Verbose = 0;
 
 BOOLEAN WinVer_WDM_Model = FALSE;
+ULONG CPU_num = 1;
 
 //UCHAR EnableDma = FALSE;
 //UCHAR EnableReorder = FALSE;
@@ -267,12 +278,14 @@ AtapiWritePort##sz( \
         return; \
     } \
     if(res->Proc) {             \
-    } else  \
+        KdPrint(("PROC io write request @ ch %x, res* %x\n", chan, _port)); \
+        ASSERT(FALSE); /* We should never get here */ \
+    } \
     if(!res->MemIo) {             \
-        ScsiPortWritePort##_Type((_type*)(res->Addr), data); \
+        ScsiPortWritePort##_Type((_type*)(ULONGIO_PTR)(res->Addr), data); \
     } else {                                      \
         /*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \
-        ScsiPortWriteRegister##_Type((_type*)(res->Addr), data); \
+        ScsiPortWriteRegister##_Type((_type*)(ULONG_PTR)(res->Addr), data); \
     }                                                        \
     return;                                                  \
 }
@@ -302,12 +315,14 @@ AtapiWritePortEx##sz( \
         return; \
     } \
     if(res->Proc) {             \
-    } else  \
+        KdPrint(("PROC io write request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
+        ASSERT(FALSE); /* We should never get here */ \
+    } \
     if(!res->MemIo) {             \
-        ScsiPortWritePort##_Type((_type*)(res->Addr+offs), data); \
+        ScsiPortWritePort##_Type((_type*)(ULONGIO_PTR)(res->Addr+offs), data); \
     } else {                                      \
         /*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \
-        ScsiPortWriteRegister##_Type((_type*)(res->Addr+offs), data); \
+        ScsiPortWriteRegister##_Type((_type*)(ULONG_PTR)(res->Addr+offs), data); \
     }                                                        \
     return;                                                  \
 }
@@ -335,14 +350,15 @@ AtapiReadPort##sz( \
         return (_type)(-1); \
     } \
     if(res->Proc) {             \
-        return 0; \
-    } else  \
+        KdPrint(("PROC io read request @ ch %x, res* %x\n", chan, _port)); \
+        ASSERT(FALSE); /* We should never get here */ \
+    } \
     if(!res->MemIo) {             \
         /*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
-        return ScsiPortReadPort##_Type((_type*)(res->Addr)); \
+        return ScsiPortReadPort##_Type((_type*)(ULONGIO_PTR)(res->Addr)); \
     } else {                                      \
         /*KdPrint(("r_mem @ (%x) %x\n", _port, res->Addr));*/ \
-        return ScsiPortReadRegister##_Type((_type*)(res->Addr)); \
+        return ScsiPortReadRegister##_Type((_type*)(ULONG_PTR)(res->Addr)); \
     }                                                        \
 }
 
@@ -370,13 +386,14 @@ AtapiReadPortEx##sz( \
         return (_type)(-1); \
     } \
     if(res->Proc) {             \
-        return 0; \
-    } else  \
+        KdPrint(("PROC io read request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
+        ASSERT(FALSE); /* We should never get here */ \
+    } \
     if(!res->MemIo) {             \
-        return ScsiPortReadPort##_Type((_type*)(res->Addr+offs)); \
+        return ScsiPortReadPort##_Type((_type*)(ULONGIO_PTR)(res->Addr+offs)); \
     } else {                                      \
         /*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \
-        return ScsiPortReadRegister##_Type((_type*)(res->Addr+offs)); \
+        return ScsiPortReadRegister##_Type((_type*)(ULONG_PTR)(res->Addr+offs)); \
     }                                                        \
 }
 
@@ -418,11 +435,11 @@ AtapiReadBuffer##sz( \
     } \
     if(!res->MemIo) {             \
         /*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
-        ScsiPortReadPortBuffer##_Type((_type*)(res->Addr), (_type*)Buffer, Count); \
+        ScsiPortReadPortBuffer##_Type((_type*)(ULONGIO_PTR)(res->Addr), (_type*)Buffer, Count); \
         return; \
     }                                                        \
     while(Count) { \
-        (*((_type*)Buffer)) = ScsiPortReadRegister##_Type((_type*)(res->Addr)); \
+        (*((_type*)Buffer)) = ScsiPortReadRegister##_Type((_type*)(ULONG_PTR)(res->Addr)); \
         Count--; \
         Buffer = ((_type*)Buffer)+1; \
     } \
@@ -463,11 +480,11 @@ AtapiWriteBuffer##sz( \
     } \
     if(!res->MemIo) {             \
         /*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
-        ScsiPortWritePortBuffer##_Type((_type*)(res->Addr), (_type*)Buffer, Count); \
+        ScsiPortWritePortBuffer##_Type((_type*)(ULONGIO_PTR)(res->Addr), (_type*)Buffer, Count); \
         return; \
     }                                                        \
     while(Count) { \
-        ScsiPortWriteRegister##_Type((_type*)(res->Addr), *((_type*)Buffer)); \
+        ScsiPortWriteRegister##_Type((_type*)(ULONG_PTR)(res->Addr), *((_type*)Buffer)); \
         Count--; \
         Buffer = ((_type*)Buffer)+1; \
     } \
@@ -498,6 +515,7 @@ AtapiSuckPort2(
         if (statusByte & IDE_STATUS_DRQ) {
             // Suck out any remaining bytes and throw away.
             AtapiReadPort2(chan, IDX_IO1_i_Data);
+            UniataNanoSleep(PIO0_TIMING);
         } else {
             break;
         }
@@ -508,6 +526,81 @@ AtapiSuckPort2(
     return statusByte;
 } // AtapiSuckPort2()
 
+ULONG
+DDKFASTAPI
+AtapiSuckPortBuffer2(
+    IN PHW_CHANNEL chan,
+    IN PUSHORT Buffer,
+    IN ULONG Count
+    )
+{
+    UCHAR statusByte;
+    ULONG i;
+    USHORT data;
+    BOOLEAN retry = FALSE;
+
+    // Assume, proper drive is already seleted
+    WaitOnBusyLong(chan);
+    for (i = 0; i < Count; i++) {
+
+        GetStatus(chan, statusByte);
+        if (statusByte & IDE_STATUS_DRQ) {
+            // Suck out any remaining bytes and throw away.
+            data = AtapiReadPort2(chan, IDX_IO1_i_Data);
+            (*Buffer) = data;
+            Count--;
+            Buffer++;
+            UniataNanoSleep(PIO0_TIMING);
+            retry = FALSE;
+        } else {
+            if(i<Count && !retry) {
+                KdPrint2((PRINT_PREFIX "  wait...\n"));
+                WaitForDrq(chan);
+                retry = TRUE;
+            }
+            break;
+        }
+    }
+    if(i) {
+        KdPrint2((PRINT_PREFIX "AtapiSuckPortBuffer2: %#x words\n", i ));
+        if(i==Count) {
+            AtapiSuckPort2(chan);
+        }
+    }
+    return i;
+} // AtapiSuckPortBuffer2()
+
+UCHAR
+DDKFASTAPI
+SelectDrive(
+    IN PHW_CHANNEL   chan,
+    IN ULONG         DeviceNumber
+    )
+{
+    if(!chan) {
+        return 0;
+    }
+/*
+    if(chan->lun[DeviceNumber] &&
+       (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_ATAPI_CHANGER)) {
+        KdPrint3(("  Select %d\n", DeviceNumber));
+    }
+*/
+    if(chan->last_devsel == DeviceNumber) {
+        //KdPrint3(("  Selected %d\n", DeviceNumber));
+        return 1;
+    }
+    AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1); \
+    chan->last_devsel = DeviceNumber ? 1 : 0;
+    if(!g_opt_DriveSelectNanoDelay) {
+        //KdPrint3(("  Select %d\n", DeviceNumber));
+        return 2;
+    }
+    //KdPrint3(("  Select %d (%d ns)\n", DeviceNumber, g_opt_DriveSelectNanoDelay));
+    UniataNanoSleep(g_opt_DriveSelectNanoDelay);
+    return 2;
+} // end SelectDrive()
+
 UCHAR
 DDKFASTAPI
 WaitOnBusy(
@@ -700,14 +793,14 @@ VOID
 DDKFASTAPI
 AtapiSoftReset(
     IN PHW_CHANNEL   chan,
-    ULONG            DeviceNumber
+    IN ULONG         DeviceNumber
     )
 {
     //ULONG c = chan->lChannel;
     ULONG i = 30 * 1000;
     UCHAR dma_status = 0;
     KdPrint2((PRINT_PREFIX "AtapiSoftReset:\n"));
-    UCHAR statusByte2;
+    UCHAR statusByte0, statusByte2;
 
     if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
         UniataAhciSoftReset(chan->DeviceExtension, chan->lChannel, DeviceNumber);
@@ -719,24 +812,44 @@ AtapiSoftReset(
     SelectDrive(chan, DeviceNumber);
     if(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MANUAL_CHS) {
         // For ESDI/MFM
+        KdPrint2((PRINT_PREFIX "  ESDI/MFM\n"));
         AtapiStallExecution(10000);
         for (i = 0; i < 1000; i++) {
             AtapiStallExecution(999);
         }
+/*    } else
+    // Seems to be unnecessary, verified by KtP
+    if(!hasPCI) {
+        // original atapi.sys behavior for old ISA-only hardware
+        AtapiStallExecution(10000);
+        AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET);
+        for (i = 0; i < 1000; i++) {
+            AtapiStallExecution(999);
+        } */
     } else {
         AtapiStallExecution(500);
         GetBaseStatus(chan, statusByte2);
+        statusByte0 = statusByte2;
         AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET);
 
         // Do not wait for BUSY assertion if it was initially set, jump to
         // BUSY release wait loop
-        if(!(statusByte2 & IDE_STATUS_BUSY)) {
+        if(!(statusByte0 & IDE_STATUS_BUSY)) {
             // Wait for BUSY assertion, in some cases delay may occure
             // 100ms should be enough
-            i = 10*1000;
-            while (!(AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) &&
+            if(g_opt_VirtualMachine == VM_BOCHS) {
+                i = 100;
+            } else {
+                i = 10*1000;
+            }
+            statusByte2 = AtapiReadPort1(chan, IDX_IO1_i_Status);
+            while (!(statusByte2 & IDE_STATUS_BUSY) &&
                    i--)
             {
+                if(!(statusByte0 & IDE_STATUS_ERROR) && (statusByte2 & IDE_STATUS_ERROR)) {
+                    KdPrint2((PRINT_PREFIX "  Command aborted, statusByte2 %x:\n", statusByte2));
+                    break;
+                }
                 AtapiStallExecution(10);
             }
         }
@@ -751,8 +864,11 @@ AtapiSoftReset(
         {
             AtapiStallExecution(30);
         }
+        KdPrint2((PRINT_PREFIX " set DFLAGS_REINIT_DMA\n"));
+        chan->lun[DeviceNumber]->DeviceFlags |= DFLAGS_REINIT_DMA;
     }
 
+    chan->last_devsel = -1; // make sure proper drive would be selected
     SelectDrive(chan, DeviceNumber);
     WaitOnBusy(chan);
     GetBaseStatus(chan, statusByte2);
@@ -781,6 +897,22 @@ AtapiSoftReset(
 
 } // end AtapiSoftReset()
 
+VOID
+DDKFASTAPI
+AtapiHardReset(
+    IN struct _HW_CHANNEL*   chan,
+    IN BOOLEAN               DisableInterrupts,
+    IN ULONG                 Delay
+    )
+{
+    KdPrint2((PRINT_PREFIX "AtapiHardReset: %d, dis=%d\n", Delay, DisableInterrupts));
+    AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_RESET_CONTROLLER |
+                              (DisableInterrupts ? IDE_DC_DISABLE_INTERRUPTS : 0));
+    chan->last_devsel = -1;
+    AtapiStallExecution(Delay);
+    AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_REENABLE_CONTROLLER);
+} // end AtapiHardReset()
+
 /*
     Send command to device.
     Translate to 48-Lba form if required
@@ -935,7 +1067,7 @@ AtaCommand48(
                 AtapiStallExecution(100);
                 continue;
             } else
-            if(statusByte == IDE_STATUS_IDLE) {
+            if((statusByte & ~IDE_STATUS_INDEX) == IDE_STATUS_IDLE) {
                 break;
             } else {
                 //if(deviceExtension->HwFlags & UNIATA_SATA) {
@@ -963,16 +1095,20 @@ AtaCommand48(
             }
             KdPrint2((PRINT_PREFIX "  try to continue\n"));
             statusByte &= ~IDE_STATUS_ERROR;
+
+        } else {
+            //KdPrint2((PRINT_PREFIX "  send Status %#x\n", statusByte));
         }
         UniataExpectChannelInterrupt(chan, TRUE);
         // !!!!!
         InterlockedExchange(&(chan->CheckIntr),
                                       CHECK_INTR_IDLE);
-        statusByte = 0;
+
+        statusByte = IDE_STATUS_SUCCESS;
         break;
     }
 
-    KdPrint2((PRINT_PREFIX "  Status %#x\n", statusByte));
+    //KdPrint2((PRINT_PREFIX "  Status %#x\n", statusByte));
 
     return statusByte;
 } // end AtaCommand48()
@@ -1188,7 +1324,7 @@ AtapiTimerDpc(
 /*
     Wrapper for ScsiPort, that implements smart Dpc
     queueing. We need it to allow parallel functioning
-    of IDE channles with shared interrupt. Standard Dpc mechanism
+    of IDE channels with shared interrupt. Standard Dpc mechanism
     cancels previous Dpc request (if any), but we need Dpc queue.
 */
 VOID
@@ -1253,7 +1389,7 @@ AtapiQueueTimerDpc(
 
 #endif //UNIATA_CORE
 
-#if DBG
+#ifdef _DEBUG
 VOID
 NTAPI
 UniataDumpATARegs(
@@ -1274,6 +1410,9 @@ UniataDumpATARegs(
                    chan->RegTranslation[IDX_IO1+j].Addr,
                    statusByteAlt));
     }
+    if(!chan->RegTranslation[IDX_BM_IO].Addr) {
+        return;
+    }
     for(j=0; j<IDX_BM_IO_SZ-1; j++) {
         statusByteAlt = AtapiReadPort1(chan, IDX_BM_IO+j);
         KdPrint2((PRINT_PREFIX
@@ -1284,7 +1423,7 @@ UniataDumpATARegs(
     }
     return;
 } // end UniataDumpATARegs()
-#endif
+#endif //_DEBUG
 
 VOID
 NTAPI
@@ -1383,7 +1522,7 @@ IssueIdentify(
 
     if(use_ahci) {
         statusByte = WaitOnBusyLong(chan);
-#if DBG
+#ifdef _DEBUG
         if(!chan->AhciInternalAtaReq) {
             KdPrint2((PRINT_PREFIX "!AhciInternalAtaReq\n"));
         }
@@ -1394,6 +1533,13 @@ IssueIdentify(
         statusByte = WaitOnBusyLong(chan);
         // Check that the status register makes sense.
         GetBaseStatus(chan, statusByte);
+        /*
+        // unnecessary
+        if(!hasPCI) {
+            // original atapi.sys behavior for old ISA-only hardware
+            AtapiStallExecution(100);
+        }
+        */
     }
 
     if (Command == IDE_COMMAND_IDENTIFY) {
@@ -1507,6 +1653,10 @@ IssueIdentify(
         statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, Command, (j < 4) ? DEV_BSIZE : 0 /* cyl */, 0, 0, 0, 0, ATA_WAIT_INTR);
         // Clear interrupt
 
+        if (!statusByte) {
+            KdPrint2((PRINT_PREFIX "IssueIdentify: 0-status, not present\n"));
+            return FALSE;
+        } else
         if (statusByte & IDE_STATUS_DRQ) {
             // Read status to acknowledge any interrupts generated.
             KdPrint2((PRINT_PREFIX "IssueIdentify: IDE_STATUS_DRQ (%#x)\n", statusByte));
@@ -1591,10 +1741,24 @@ IssueIdentify(
         GetBaseStatus(chan, statusByte);
         KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte));
 
+#ifdef _DEBUG
+        if(atapiDev) {
+          j = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
+          KdPrint3((PRINT_PREFIX "IssueIdentify: iReason %x\n", j));
+
+          j =
+              AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow);
+
+          j |=
+              (USHORT)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8;
+          KdPrint3((PRINT_PREFIX "IssueIdentify: wCount %x\n", j));
+
+        }
+#endif //_DEBUG
+
         if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
 
             KdPrint2((PRINT_PREFIX "  use 16bit IO\n"));
-
             // ATI/SII chipsets with memory-mapped IO hangs when
             // I call ReadBuffer(), probably due to PCI burst/prefetch enabled
             // Unfortunately, I don't know yet how to workaround it except
@@ -1625,6 +1789,24 @@ IssueIdentify(
     KdPrint2((PRINT_PREFIX "Model: %20.20s\n", deviceExtension->FullIdentifyData.ModelNumber));
     KdPrint2((PRINT_PREFIX "FW:    %4.4s\n", deviceExtension->FullIdentifyData.FirmwareRevision));
     KdPrint2((PRINT_PREFIX "S/N:   %20.20s\n", deviceExtension->FullIdentifyData.SerialNumber));
+    if(g_opt_VirtualMachine == VM_AUTO) {
+        if((deviceExtension->FullIdentifyData.FirmwareRevision[0] == 0 ||
+           deviceExtension->FullIdentifyData.FirmwareRevision[0] == ' ') &&
+           (deviceExtension->FullIdentifyData.FirmwareRevision[1] == 0 ||
+           deviceExtension->FullIdentifyData.FirmwareRevision[1] == ' ')) {
+            // Check for BOCHS VM signature. If no additional PCI devices (e.g. VGA)
+            // are declared BOCHS looks like regular PC
+            if (!atapiDev && !AtapiStringCmp ((PCCHAR)(deviceExtension->FullIdentifyData.SerialNumber), "XBDH00", 6)) {
+                KdPrint2((PRINT_PREFIX "IssueIdentify: BOCHS HDD\n"));
+                g_opt_VirtualMachine = VM_BOCHS;
+            } else
+            if (atapiDev && !AtapiStringCmp ((PCCHAR)(deviceExtension->FullIdentifyData.SerialNumber), "XBDC00", 6)) {
+                KdPrint2((PRINT_PREFIX "IssueIdentify: BOCHS CD\n"));
+                g_opt_VirtualMachine = VM_BOCHS;
+            }
+        }
+    }
+
     KdPrint2((PRINT_PREFIX "Pio:   %x\n", deviceExtension->FullIdentifyData.PioCycleTimingMode));
     if(deviceExtension->FullIdentifyData.PioTimingsValid) {
         KdPrint2((PRINT_PREFIX "APio:  %x\n", deviceExtension->FullIdentifyData.AdvancedPIOModes));
@@ -1650,10 +1832,17 @@ IssueIdentify(
         deviceExtension->FullIdentifyData.VendorAcoustic,
         deviceExtension->FullIdentifyData.CurrentAcoustic
         ));
-    KdPrint2((PRINT_PREFIX "AdvPowerMode %d, cur %d\n",
+    KdPrint2((PRINT_PREFIX "AdvPowerMode %d\n",
         deviceExtension->FullIdentifyData.CfAdvPowerMode
         ));
 
+    KdPrint2((PRINT_PREFIX "PowerMngt %d/%d, APM %d/%d\n",
+        deviceExtension->FullIdentifyData.FeaturesEnabled.PowerMngt,
+        deviceExtension->FullIdentifyData.FeaturesSupport.PowerMngt,
+        deviceExtension->FullIdentifyData.FeaturesEnabled.APM,
+        deviceExtension->FullIdentifyData.FeaturesSupport.APM
+        ));
+
     // Check out a few capabilities / limitations of the device.
     if (deviceExtension->FullIdentifyData.RemovableStatus & 1) {
         // Determine if this drive supports the MSN functions.
@@ -1677,6 +1866,44 @@ IssueIdentify(
         ULONGLONG NativeNumOfSectors=0;
         ULONGLONG cylinders=0;
         ULONGLONG tmp_cylinders=0;
+
+        KdPrint2((PRINT_PREFIX "PhysLogSectorSize %#x, %#x, offset %#x\n", 
+                deviceExtension->FullIdentifyData.PhysLogSectorSize,
+                deviceExtension->FullIdentifyData.LargeSectorSize,
+                deviceExtension->FullIdentifyData.LogicalSectorOffset
+                ));
+
+        KdPrint2((PRINT_PREFIX "NV PM_Sup %d, PM_En %d, En %d, PM ver %#x ver %#x\n", 
+                deviceExtension->FullIdentifyData.NVCache_PM_Supported,
+                deviceExtension->FullIdentifyData.NVCache_PM_Enabled,
+                deviceExtension->FullIdentifyData.NVCache_Enabled,
+                deviceExtension->FullIdentifyData.NVCache_PM_Version,
+                deviceExtension->FullIdentifyData.NVCache_Version
+                ));
+
+        KdPrint2((PRINT_PREFIX "R-rate %d\n",
+                deviceExtension->FullIdentifyData.NominalMediaRotationRate
+                ));
+        KdPrint2((PRINT_PREFIX "WC %d/%d, LA %d/%d, WB %d/%d, RB %d/%d, Q %d/%d\n",
+                deviceExtension->FullIdentifyData.FeaturesEnabled.WriteCache,
+                deviceExtension->FullIdentifyData.FeaturesSupport.WriteCache,
+                deviceExtension->FullIdentifyData.FeaturesEnabled.LookAhead,
+                deviceExtension->FullIdentifyData.FeaturesSupport.LookAhead,
+                deviceExtension->FullIdentifyData.FeaturesEnabled.WriteBuffer,
+                deviceExtension->FullIdentifyData.FeaturesSupport.WriteBuffer,
+                deviceExtension->FullIdentifyData.FeaturesEnabled.ReadBuffer,
+                deviceExtension->FullIdentifyData.FeaturesSupport.ReadBuffer,
+                deviceExtension->FullIdentifyData.FeaturesEnabled.Queued,
+                deviceExtension->FullIdentifyData.FeaturesSupport.Queued
+                ));
+
+        KdPrint2((PRINT_PREFIX "Protected %d/%d status %#x, rev %#x\n",
+                deviceExtension->FullIdentifyData.FeaturesEnabled.Protected,
+                deviceExtension->FullIdentifyData.FeaturesSupport.Protected,
+                deviceExtension->FullIdentifyData.SecurityStatus,
+                deviceExtension->FullIdentifyData.MasterPasswdRevision
+                ));
+
         // Read very-old-style drive geometry
         KdPrint2((PRINT_PREFIX "CHS %#x:%#x:%#x\n", 
                 deviceExtension->FullIdentifyData.NumberOfCylinders,
@@ -1690,6 +1917,8 @@ IssueIdentify(
         // Check for HDDs > 8Gb
         if ((deviceExtension->FullIdentifyData.NumberOfCylinders == 0x3fff) &&
 /*            (deviceExtension->FullIdentifyData.TranslationFieldsValid) &&*/
+             deviceExtension->FullIdentifyData.NumberOfHeads &&
+             deviceExtension->FullIdentifyData.SectorsPerTrack &&
             (NumOfSectors < deviceExtension->FullIdentifyData.UserAddressableSectors)) {
             KdPrint2((PRINT_PREFIX "NumberOfCylinders == 0x3fff\n"));
             cylinders = 
@@ -1709,6 +1938,12 @@ IssueIdentify(
         }
         // Check for LBA mode
         KdPrint2((PRINT_PREFIX "SupportLba flag %#x\n", deviceExtension->FullIdentifyData.SupportLba));
+        KdPrint2((PRINT_PREFIX "SupportDMA flag %#x\n", deviceExtension->FullIdentifyData.SupportDma));
+        KdPrint2((PRINT_PREFIX "SoftReset %#x\n", deviceExtension->FullIdentifyData.SoftReset));
+        KdPrint2((PRINT_PREFIX "SupportIordy %#x, DisableIordy %#x\n",
+            deviceExtension->FullIdentifyData.SupportIordy,
+            deviceExtension->FullIdentifyData.DisableIordy
+            ));
         KdPrint2((PRINT_PREFIX "MajorRevision %#x\n", deviceExtension->FullIdentifyData.MajorRevision));
         KdPrint2((PRINT_PREFIX "UserAddressableSectors %#x\n", deviceExtension->FullIdentifyData.UserAddressableSectors));
         if ( deviceExtension->FullIdentifyData.SupportLba
@@ -1727,6 +1962,8 @@ IssueIdentify(
         if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
             if(deviceExtension->FullIdentifyData.FeaturesSupport.Address48 &&
                deviceExtension->FullIdentifyData.FeaturesEnabled.Address48 &&
+               deviceExtension->FullIdentifyData.NumberOfHeads &&
+               deviceExtension->FullIdentifyData.SectorsPerTrack &&
                (deviceExtension->FullIdentifyData.UserAddressableSectors48 > NumOfSectors)
                ) {
                 KdPrint2((PRINT_PREFIX "LBA48\n"));
@@ -1856,12 +2093,29 @@ IssueIdentify(
                 }
             }
 
+            if(NumOfSectors > ATA_MAX_IOLBA28) {
+              KdPrint2((PRINT_PREFIX "2TB threshold, force LBA64 WRITE requirement\n"));
+              LunExt->DeviceFlags |= DFLAGS_LBA32plus;
+            }
         } // if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED)
 
         // fill IdentifyData with bogus geometry
         KdPrint2((PRINT_PREFIX "requested LunExt->GeomType=%x\n", LunExt->opt_GeomType));
-        tmp_cylinders = NumOfSectors / (deviceExtension->FullIdentifyData.CurrentSectorsPerTrack *
-                                        deviceExtension->FullIdentifyData.NumberOfCurrentHeads);
+        if(deviceExtension->FullIdentifyData.CurrentSectorsPerTrack &&
+           deviceExtension->FullIdentifyData.NumberOfCurrentHeads) {
+          tmp_cylinders = NumOfSectors / (deviceExtension->FullIdentifyData.CurrentSectorsPerTrack *
+                                          deviceExtension->FullIdentifyData.NumberOfCurrentHeads);
+        } else
+        if(deviceExtension->FullIdentifyData.SectorsPerTrack &&
+           deviceExtension->FullIdentifyData.NumberOfHeads) {
+            KdPrint2((PRINT_PREFIX "Current C/H = %#I64x/%#I64x\n",
+                deviceExtension->FullIdentifyData.CurrentSectorsPerTrack,
+                deviceExtension->FullIdentifyData.NumberOfCurrentHeads));
+            tmp_cylinders = NumOfSectors / (deviceExtension->FullIdentifyData.SectorsPerTrack *
+                                            deviceExtension->FullIdentifyData.NumberOfHeads);
+        } else {
+            tmp_cylinders = 0;
+        }
         KdPrint2((PRINT_PREFIX "tmp_cylinders = %#I64x\n", tmp_cylinders));
         if((tmp_cylinders < 0xffff) || (LunExt->opt_GeomType == GEOM_ORIG)) {
             // ok, we can keep original values
@@ -1883,6 +2137,11 @@ IssueIdentify(
             }
         }
 
+        if(!deviceExtension->FullIdentifyData.SectorsPerTrack ||
+           !deviceExtension->FullIdentifyData.NumberOfHeads) {
+            KdPrint2((PRINT_PREFIX "Zero S/H -> Force Use GEOM_STD\n"));
+        }
+
         if(LunExt->opt_GeomType == GEOM_STD) {
             deviceExtension->FullIdentifyData.CurrentSectorsPerTrack =
             deviceExtension->FullIdentifyData.SectorsPerTrack = 63;
@@ -1944,12 +2203,27 @@ skip_lba_staff:
                   deviceExtension->FullIdentifyData.CurrentSectorsPerTrack
                   ));
 
-        if(NumOfSectors)
+        if(NumOfSectors) {
             LunExt->NumOfSectors = NumOfSectors;
-/*        if(deviceExtension->FullIdentifyData.MajorRevision &&
+        }
+        if(deviceExtension->FullIdentifyData.MajorRevision &&
            deviceExtension->FullIdentifyData.DoubleWordIo) {
             LunExt->DeviceFlags |= DFLAGS_DWORDIO_ENABLED;
-        }*/
+            KdPrint2((PRINT_PREFIX "IssueIdentify: DWORDIO supported\n"));
+        }
+    } else {
+        // ATAPI
+        if(deviceExtension->FullIdentifyData.MajorRevision &&
+           deviceExtension->FullIdentifyData.DoubleWordIo) {
+            LunExt->DeviceFlags |= DFLAGS_DWORDIO_ENABLED;
+            KdPrint2((PRINT_PREFIX "IssueIdentify: DFLAGS_DWORDIO_ENABLED.\n"));
+        }
+        if(deviceExtension->FullIdentifyData.AtapiDMA.DMADirRequired) {
+            KdPrint2((PRINT_PREFIX "DMADirRequired.\n"));
+        }
+        if(deviceExtension->FullIdentifyData.AtapiByteCount0) {
+            KdPrint2((PRINT_PREFIX "AtapiByteCount0=%x\n", deviceExtension->FullIdentifyData.AtapiByteCount0));
+        }
     }
 
     ScsiPortMoveMemory(&LunExt->IdentifyData,
@@ -1988,6 +2262,7 @@ skip_lba_staff:
             KdPrint2((PRINT_PREFIX "IssueIdentify: ATAPI drive type %#x.\n",
                 LunExt->IdentifyData.DeviceType));
         }
+        KdPrint2((PRINT_PREFIX "IssueIdentify: AtapiCmdSize %#x\n", deviceExtension->FullIdentifyData.AtapiCmdSize));
     } else {
         KdPrint2((PRINT_PREFIX "IssueIdentify: hard drive.\n"));
     }
@@ -2123,10 +2398,10 @@ AtapiResetController__(
     //ULONG RevID    =  deviceExtension->RevID;
     ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK;
     //UCHAR tmp8;
-    UCHAR tmp16;
+    USHORT tmp16;
 
     KdPrint2((PRINT_PREFIX "AtapiResetController: Reset IDE %#x/%#x @ %#x\n", VendorID, DeviceID, slotNumber));
-    KdPrint2((PRINT_PREFIX "simplexOnly %d\n", deviceExtension->simplexOnly));
+    KdPrint2((PRINT_PREFIX "simplexOnly %d, VM %x\n", deviceExtension->simplexOnly, g_opt_VirtualMachine));
 
     if(!deviceExtension->simplexOnly && (PathId != CHAN_NOT_SPECIFIED)) {
         // we shall reset both channels on SimplexOnly devices,
@@ -2140,18 +2415,33 @@ AtapiResetController__(
 
     for (; j < numberChannels; j++) {
 
-        KdPrint2((PRINT_PREFIX "AtapiResetController: Reset channel %d\n", j));
+        KdPrint2((PRINT_PREFIX "AtapiResetController: Reset lchannel %d[%d]\n", j, deviceExtension->Channel));
         chan = &(deviceExtension->chan[j]);
         MaxLuns = chan->NumberLuns;
-        KdPrint2((PRINT_PREFIX "  CompleteType %#x, Luns %d, chan %#x, sptr %#x\n", CompleteType, MaxLuns, chan, &chan));
+        // Save control flags
+        ChannelCtrlFlags = chan->ChannelCtrlFlags;
+        KdPrint2((PRINT_PREFIX "  CompleteType %#x, Luns %d, chan %#x, sptr %#x, flags %#x\n", CompleteType, MaxLuns, chan, &chan, ChannelCtrlFlags));
         //MaxLuns = (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE) ? 1 : 2;
         if(CompleteType != RESET_COMPLETE_NONE) {
 #ifndef UNIATA_CORE
             while((CurSrb = UniataGetCurRequest(chan))) {
 
+                PHW_LU_EXTENSION     LunExt;
                 PATA_REQ AtaReq = (PATA_REQ)(CurSrb->SrbExtension);
 
+                i = GET_CDEV(CurSrb);
+                KdPrint2((PRINT_PREFIX "  Lun %x\n", i));
+                LunExt = chan->lun[i];
+
                 KdPrint2((PRINT_PREFIX "AtapiResetController: pending SRB %#x, chan %#x\n", CurSrb, chan));
+                if(CurSrb->Cdb[0] == SCSIOP_MECHANISM_STATUS) {
+                    KdPrint2((PRINT_PREFIX "  was MechStatus\n"));
+
+                    if(!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED)) {
+                        LunExt->DeviceFlags |= DFLAGS_CHANGER_INITED;
+                        KdPrint2((PRINT_PREFIX "  set DFLAGS_CHANGER_INITED\n"));
+                    }
+                }
                 // Check and see if we are processing an internal srb
                 if (AtaReq->OriginalSrb) {
                     KdPrint2((PRINT_PREFIX "  restore original SRB %#x\n", AtaReq->OriginalSrb));
@@ -2169,7 +2459,7 @@ AtapiResetController__(
                 ASSERT(AtaReq->Srb == CurSrb);
                 if (CurSrb) {
                     // Complete outstanding request with SRB_STATUS_BUS_RESET.
-                    UCHAR PathId   = CurSrb->PathId;
+                    UCHAR CurPathId = CurSrb->PathId;
                     UCHAR TargetId = CurSrb->TargetId;
                     UCHAR Lun = CurSrb->Lun;
 
@@ -2179,7 +2469,7 @@ AtapiResetController__(
                     if (CurSrb->SenseInfoBuffer) {
 
                         PSENSE_DATA  senseBuffer = (PSENSE_DATA)CurSrb->SenseInfoBuffer;
-                        KdPrint2((PRINT_PREFIX "  senseBuffer %#x, chan %#x\n", senseBuffer, chan));
+                        KdPrint2((PRINT_PREFIX "  senseBuffer %#x, chan %#x, ReqFlags %#x\n", senseBuffer, chan, AtaReq->Flags));
 
                         senseBuffer->ErrorCode = 0x70;
                         senseBuffer->Valid     = 1;
@@ -2197,6 +2487,42 @@ AtapiResetController__(
                         }
                     }
 
+                    if(!ATAPI_DEVICE(chan, i) && AtaReq->bcount && AtaReq->retry < MAX_RETRIES) {
+                        KdPrint2((PRINT_PREFIX "Save IDE retry status %d\n", AtaReq->retry));
+                        LunExt->errLastLba = AtaReq->lba;
+                        LunExt->errBCount = AtaReq->bcount;
+                        LunExt->errRetry = AtaReq->retry+1;
+                        //KdPrint2((PRINT_PREFIX "AtaReq->Flags & REQ_FLAG_RW_MASK = %x (%x)\n", (AtaReq->Flags & REQ_FLAG_RW_MASK), REQ_FLAG_READ));
+                        //KdPrint2((PRINT_PREFIX "ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION = %x (%x)\n", ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE, CTRFLAGS_DMA_OPERATION));
+                        //KdPrint2((PRINT_PREFIX "g_opt_VirtualMachine = %x (%x)\n", g_opt_VirtualMachine, VM_BOCHS));
+                        if(((AtaReq->Flags & REQ_FLAG_RW_MASK) == REQ_FLAG_READ) &&
+                           (ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) &&
+                           (g_opt_VirtualMachine == VM_BOCHS)) {
+                            KdPrint2((PRINT_PREFIX "set CTRFLAGS_DMA_BEFORE_R on BOCHS\n"));
+                            g_opt_BochsDmaReadWorkaround = TRUE;
+                            g_opt_AtapiNoDma = TRUE;
+                        } else {
+                            KdPrint2((PRINT_PREFIX "do nothing\n"));
+                        }
+                    } else
+                    if(ATAPI_DEVICE(chan, i) && AtaReq->bcount && !AtaReq->retry) {
+                        KdPrint2((PRINT_PREFIX "Save ATAPI retry status %d\n", AtaReq->retry));
+                        LunExt->errLastLba = AtaReq->lba;
+                        LunExt->errBCount = AtaReq->bcount;
+                        LunExt->errRetry = AtaReq->retry+1;
+                        if(((AtaReq->Flags & REQ_FLAG_RW_MASK) == REQ_FLAG_READ) &&
+                           (ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) &&
+                           (g_opt_VirtualMachine == VM_BOCHS)) {
+                            KdPrint2((PRINT_PREFIX "set CTRFLAGS_DMA_BEFORE_R on BOCHS ATAPI\n"));
+                            //g_opt_BochsDmaReadWorkaround = TRUE;
+                            g_opt_AtapiNoDma = TRUE;
+                        } else {
+                            KdPrint2((PRINT_PREFIX "do nothing\n"));
+                        }
+                    } else {
+                        LunExt->errRetry = 0;
+                    }
+
                     // Clear request tracking fields.
                     AtaReq->WordsLeft = 0;
                     AtaReq->DataBuffer = NULL;
@@ -2210,7 +2536,7 @@ AtapiResetController__(
                     // Indicate ready for next request.
                     ScsiPortNotification(NextLuRequest,
                                          deviceExtension, 
-                                         PathId,
+                                         CurPathId,
                                          TargetId,
                                          Lun);
                 }
@@ -2220,12 +2546,10 @@ AtapiResetController__(
 #endif //UNIATA_CORE
         } // end if (!CompleteType != RESET_COMPLETE_NONE)
 
-        // Save control flags
-        ChannelCtrlFlags = chan->ChannelCtrlFlags;
         // Clear expecting interrupt flag.
         UniataExpectChannelInterrupt(chan, FALSE);
         chan->RDP = FALSE;
-        chan->ChannelCtrlFlags = 0;
+        chan->ChannelCtrlFlags = ChannelCtrlFlags & CTRFLAGS_PERMANENT;
         InterlockedExchange(&(chan->CheckIntr),
                                       CHECK_INTR_IDLE);
         
@@ -2243,6 +2567,7 @@ AtapiResetController__(
                 UniataAhciReset(HwDeviceExtension, j);
             } else {
                 KdPrint2((PRINT_PREFIX "  skip not implemented\n"));
+                continue;
             }
         } else {
             KdPrint2((PRINT_PREFIX "  ATA path, chan %#x\n", chan));
@@ -2302,12 +2627,55 @@ AtapiResetController__(
                     AtapiStallExecution(10000);
                 }
                 break; }
-            case ATA_SIS_ID:
+            case ATA_SIS_ID: {
+                KdPrint2((PRINT_PREFIX "  SIS\n"));
+                if(!(ChipFlags & UNIATA_SATA))
+                    goto default_reset;
+                break; }
+#if 0
             case ATA_NVIDIA_ID: {
-                KdPrint2((PRINT_PREFIX "  SIS/nVidia\n"));
+                KdPrint2((PRINT_PREFIX "  nVidia\n"));
                 if(!(ChipFlags & UNIATA_SATA))
                     goto default_reset;
                 break; }
+#else
+            case ATA_NVIDIA_ID: {
+                ULONG offs;
+                ULONG Channel = deviceExtension->Channel + j;
+                KdPrint2((PRINT_PREFIX "  nVidia\n"));
+                if(!(ChipFlags & UNIATA_SATA)) {
+                    goto default_reset;
+                }
+                offs = (ChipFlags & NV4OFF) ? 0x0440 : 0x0010;
+
+                KdPrint2((PRINT_PREFIX "  disable Phy intr, offs %#x, c %u\n", offs, Channel));
+                /* disable device and PHY state change interrupts */
+                if(ChipFlags & NVQ) {
+                    KdPrint2((PRINT_PREFIX "  NVQ, 32bits reg\n"));
+                    AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4, 
+                        AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4) & ((~(ULONG)0x0000000d) << (!Channel*16)) );
+                } else {
+                    AtapiWritePortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1, 
+                        AtapiReadPortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1) & ((~(UCHAR)0x0d) << (!Channel*4)) );
+                }
+                tmp16 = UniataSataPhyEnable(HwDeviceExtension, j, 0/* dev0*/, UNIATA_SATA_RESET_ENABLE);
+
+                KdPrint2((PRINT_PREFIX "  enable Phy intr, offs %#x\n", offs));
+                /* enable device and PHY state change interrupts */
+                if(ChipFlags & NVQ) {
+                    AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4, 
+                        AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4) | (((ULONG)0x0000000d) << (!Channel*16)) );
+                } else {
+                    AtapiWritePortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1, 
+                        AtapiReadPortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1) | (((UCHAR)0x0d) << (!Channel*4)) );
+                }
+
+                KdPrint2((PRINT_PREFIX "  dev status %#x\n", tmp16));
+                if(tmp16 != IDE_STATUS_WRONG) {
+                    goto default_reset;
+                }
+                break; }
+#endif //0
             case ATA_SILICON_IMAGE_ID: {
                 ULONG offset;
                 ULONG Channel = deviceExtension->Channel + j;
@@ -2336,9 +2704,10 @@ AtapiResetController__(
                     UniataSataClearErr(HwDeviceExtension, j, UNIATA_SATA_IGNORE_CONNECT, 0);
                 }
 default_reset:
-                KdPrint2((PRINT_PREFIX "  send reset\n"));
+/*
                 AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_DISABLE_INTERRUPTS |
                                                                         IDE_DC_RESET_CONTROLLER );
+                chan->last_devsel = -1;
                 KdPrint2((PRINT_PREFIX "  wait a little\n"));
                 AtapiStallExecution(10000);
                 // Disable interrupts
@@ -2349,6 +2718,13 @@ default_reset:
                 AtapiEnableInterrupts(deviceExtension, j);
                 KdPrint2((PRINT_PREFIX "  wait a little (2)\n"));
                 AtapiStallExecution(100000);
+*/
+                AtapiHardReset(chan, TRUE, 100000);
+                KdPrint2((PRINT_PREFIX "  disable intr\n"));
+                AtapiDisableInterrupts(deviceExtension, j);
+                AtapiStallExecution(100);
+                KdPrint2((PRINT_PREFIX "  re-enable intr\n"));
+                AtapiEnableInterrupts(deviceExtension, j);
                 KdPrint2((PRINT_PREFIX "  done\n"));
 
                 break;
@@ -2438,6 +2814,22 @@ default_reset:
 
                 GetStatus(chan, statusByte);
 
+                if(statusByte != IDE_STATUS_SUCCESS) {
+                    ULONG k;
+                    k = UniataAnybodyHome(deviceExtension, j, i);
+                    if(k == ATA_AT_HOME_HDD) {
+                        // device reset in progress, perform additional wait
+                        KdPrint2((PRINT_PREFIX "  long reset, wait up to 4.5 s\n"));
+                        k = 30 * 1000;
+                        while ((AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) &&
+                               k--)
+                        {
+                            AtapiStallExecution(150);
+                        }
+                        KdPrint2((PRINT_PREFIX " exit after %u loops\n", k));
+                        GetStatus(chan, statusByte);
+                    }
+                }
                 if(statusByte == IDE_STATUS_SUCCESS) {
 
                     IssueIdentify(HwDeviceExtension,
@@ -2473,6 +2865,7 @@ default_reset:
                 GetBaseStatus(chan, statusByte);
             }
             // force DMA mode reinit
+            KdPrint2((PRINT_PREFIX " set DFLAGS_REINIT_DMA\n"));
             chan->lun[i]->DeviceFlags |= DFLAGS_REINIT_DMA;
         }
 #endif //0
@@ -3038,30 +3431,32 @@ AtapiHwInitialize__(
                                         0, ATA_C_F_DIS_RCACHE, ATA_WAIT_BASE_READY);
                     LunExt->DeviceFlags &= ~DFLAGS_RCACHE_ENABLED;
                 }
-                if(LunExt->opt_WriteCacheEnable) {
-                    KdPrint2((PRINT_PREFIX "  Try Enable Write Cache\n"));
-                    // If supported & allowed, setup write cacheing
-                    statusByte = AtaCommand(deviceExtension, i, lChannel,
-                                        IDE_COMMAND_SET_FEATURES, 0, 0, 0,
-                                        0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY);
-                    // Check for errors.
-                    if (statusByte & IDE_STATUS_ERROR) {
-                        KdPrint2((PRINT_PREFIX 
-                                    "AtapiHwInitialize: Enable write cacheing on Device %d failed\n",
-                                    i));
-                        LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
+                if(LunExt->IdentifyData.FeaturesSupport.WriteCache) {
+                    if(LunExt->opt_WriteCacheEnable) {
+                        KdPrint2((PRINT_PREFIX "  Try Enable Write Cache\n"));
+                        // If supported & allowed, setup write cacheing
+                        statusByte = AtaCommand(deviceExtension, i, lChannel,
+                                            IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+                                            0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY);
+                        // Check for errors.
+                        if (statusByte & IDE_STATUS_ERROR) {
+                            KdPrint2((PRINT_PREFIX 
+                                        "AtapiHwInitialize: Enable write cacheing on Device %d failed\n",
+                                        i));
+                            LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
+                        } else {
+                            LunExt->DeviceFlags |= DFLAGS_WCACHE_ENABLED;
+                        }
                     } else {
-                        LunExt->DeviceFlags |= DFLAGS_WCACHE_ENABLED;
+                        KdPrint2((PRINT_PREFIX "  Disable Write Cache\n"));
+                        statusByte = AtaCommand(deviceExtension, i, lChannel,
+                                            IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+                                            0, ATA_C_F_DIS_WCACHE, ATA_WAIT_BASE_READY);
+                        LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
                     }
-                } else {
-                    KdPrint2((PRINT_PREFIX "  Disable Write Cache\n"));
-                    statusByte = AtaCommand(deviceExtension, i, lChannel,
-                                        IDE_COMMAND_SET_FEATURES, 0, 0, 0,
-                                        0, ATA_C_F_DIS_WCACHE, ATA_WAIT_BASE_READY);
-                    LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
                 }
 
-                if(LunExt->IdentifyData.FeaturesSupport.PowerMngt ||
+                if(/*LunExt->IdentifyData.FeaturesSupport.PowerMngt ||*/
                    LunExt->IdentifyData.FeaturesSupport.APM) {
 
                     if(LunExt->opt_AdvPowerMode) {
@@ -3458,7 +3853,7 @@ AtapiCallBack__(
         goto ReturnCallback;
     }
 
-#ifdef DBG
+#ifdef _DEBUG
     if (!IS_RDP((srb->Cdb[0]))) {
         KdPrint2((PRINT_PREFIX "AtapiCallBack: Invalid CDB marked as RDP - %#x\n", srb->Cdb[0]));
     }
@@ -3603,7 +3998,7 @@ AtapiInterrupt(
     ULONG hIS;
     ULONG checked;
 
-    KdPrint2((PRINT_PREFIX "Intr: VendorID+DeviceID/Rev %#x/%#x (ex %d)\n",
+    KdPrint2((PRINT_PREFIX "Intr: DeviceID+VendorID/Rev %#x/%#x (ex %d)\n",
         deviceExtension->DevID, deviceExtension->RevID, deviceExtension->ExpectingInterrupt ));
 
     if(deviceExtension->HwFlags & UNIATA_AHCI) {
@@ -3989,7 +4384,7 @@ AtapiEnableInterrupts(
             //SelectDrive(chan, 0);
             //GetBaseStatus(chan, statusByte);
             AtapiWritePort1(chan, IDX_IO2_o_Control,
-                                   IDE_DC_A_4BIT );
+                                   0 | IDE_DC_A_4BIT );
             //if(chan->NumberLuns) {
             //    SelectDrive(chan, 1);
             //    GetBaseStatus(chan, statusByte);
@@ -4000,8 +4395,13 @@ AtapiEnableInterrupts(
         }
         chan->ChannelCtrlFlags &= ~CTRFLAGS_INTR_DISABLED;
     } else {
-        AtapiWritePort1(chan, IDX_IO2_o_Control,
+        if(deviceExtension->HwFlags & UNIATA_AHCI) {
+            // keep interrupts disabled
+            UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0);
+        } else {
+            AtapiWritePort1(chan, IDX_IO2_o_Control,
                                IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ );
+        }
     }
     return;
 } // end AtapiEnableInterrupts()
@@ -4182,33 +4582,51 @@ AtapiCheckInterrupt__(
                 return INTERRUPT_REASON_IGNORE;
             }
             break;
-        case PRMIO:
-            status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x0040);
-            if(ChipFlags & PRSATA) {
-                pr_status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x006c);
-                AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x006c, pr_status & 0x000000ff);
+        case PRMIO: {
+            ULONG stat_reg = (ChipFlags & PRG2) ? 0x60 : 0x6c;
+            status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x40);
+            AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x40, status);
+
+            if(status & (1 << (Channel+1))) {
+                // our
+            } else {
+                KdPrint2((PRINT_PREFIX "  Promise mio unexpected\n"));
+                return INTERRUPT_REASON_IGNORE;
             }
+
+            if(!(ChipFlags & UNIATA_SATA))
+                break;
+
+            pr_status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),stat_reg);
+            AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),stat_reg, (pr_status & (0x11 << Channel)));
             if(pr_status & (0x11 << Channel)) {
                 // TODO: reset channel
                 KdPrint2((PRINT_PREFIX "  Promise mio unexpected + reset req\n"));
-                return INTERRUPT_REASON_IGNORE;
+                UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH, 0);
             }
             if(!(status & (0x01 << Channel))) {
-                KdPrint2((PRINT_PREFIX "  Promise mio unexpected\n"));
+                // Connect event
+                KdPrint2((PRINT_PREFIX "  Promise mio unexpected attach\n"));
+                UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH, 0);
+            }
+            if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
+                OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
+            } else {
                 return INTERRUPT_REASON_IGNORE;
             }
+
             AtapiWritePort4(chan, IDX_BM_DeviceSpecific0, 0x00000001);
-            break;
+            break; }
         }
         break; }
     case ATA_NVIDIA_ID: {
-        if(!(ChipFlags & UNIATA_SATA))
+        if(!(ChipFlags & UNIATA_SATA) || (ChipFlags & NVGEN))
             break;
 
         KdPrint2((PRINT_PREFIX "NVIDIA\n"));
 
         ULONG offs = (ChipFlags & NV4OFF) ? 0x0440 : 0x0010;
-        ULONG shift = Channel << ((ChipFlags & NVQ) ? 4 : 2);
+        ULONG shift = Channel * ((ChipFlags & NVQ) ? 4 : 16);
 
         /* get and clear interrupt status */
         if(ChipFlags & NVQ) {
@@ -4218,7 +4636,7 @@ AtapiCheckInterrupt__(
             pr_status = AtapiReadPortEx1(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs);
             AtapiWritePortEx1(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs, (0x0f << shift));
         }
-        KdPrint2((PRINT_PREFIX "  pr_status %x\n", pr_status));
+        KdPrint2((PRINT_PREFIX "  pr_status %x, shift %x\n", pr_status, shift));
 
         /* check for and handle connect events */
         if(((pr_status & (0x0cUL << shift)) == (0x04UL << shift)) ) {
@@ -4418,7 +4836,8 @@ skip_dma_stat_check:
             KdPrint2((PRINT_PREFIX "  expecting intr + BUSY (3), non ATAPI\n"));
             return INTERRUPT_REASON_IGNORE;
         }
-        if((statusByte & ~IDE_STATUS_DRQ) != (IDE_STATUS_BUSY | IDE_STATUS_DRDY | IDE_STATUS_DSC)) {
+        if((statusByte & ~(IDE_STATUS_DRQ | IDE_STATUS_INDEX)) !=
+           (IDE_STATUS_BUSY | IDE_STATUS_DRDY | IDE_STATUS_DSC)) {
             KdPrint3((PRINT_PREFIX "  unexpected status, seems it is not our\n"));
             return INTERRUPT_REASON_IGNORE;
         }
@@ -4533,9 +4952,9 @@ AtapiInterrupt__(
 
     BOOLEAN atapiDev = FALSE;
 
-#ifdef DBG
+#ifdef _DEBUG
     UCHAR Channel;
-#endif //DBG
+#endif //_DEBUG
     UCHAR lChannel;
     UCHAR DeviceNumber;
     BOOLEAN DmaTransfer = FALSE;
@@ -4551,6 +4970,7 @@ AtapiInterrupt__(
 //    BOOLEAN RestoreUseDpc = FALSE;
     BOOLEAN DataOverrun = FALSE;
     BOOLEAN NoStartIo = TRUE;
+    BOOLEAN NoRetry = FALSE;
 
     KdPrint2((PRINT_PREFIX "AtapiInterrupt:\n"));
     if(InDpc) {
@@ -4567,11 +4987,11 @@ AtapiInterrupt__(
 
     lChannel = c;
 
-#ifdef DBG
+#ifdef _DEBUG
     Channel = (UCHAR)(deviceExtension->Channel + lChannel);
 
     KdPrint2((PRINT_PREFIX "  cntrlr %#x:%d, irql %#x, c %d\n", deviceExtension->DevIndex, Channel, KeGetCurrentIrql(), c));
-#endif //DBG
+#endif //_DEBUG
 
     if((chan->ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) ||
        (AtaReq && (AtaReq->Flags & REQ_FLAG_DMA_OPERATION)) ||
@@ -4643,7 +5063,7 @@ AtapiInterrupt__(
         return TRUE;
     }
 
-    if(!DmaTransfer && !atapiDev) {
+    if((!DmaTransfer && !atapiDev) || deviceExtension->DriverMustPoll) {
         KdPrint2((PRINT_PREFIX "  service PIO HDD\n"));
         UseDpc = FALSE;
     }
@@ -4763,12 +5183,30 @@ ServiceInterrupt:
         statusByte = (UCHAR)(AtaReq->ahci.in_status & IDE_STATUS_MASK);
 
         if(chan->AhciLastIS & ~(ATA_AHCI_P_IX_DHR | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_SDB)) {
-            KdPrint3((PRINT_PREFIX "Err intr (%#x)\n", chan->AhciLastIS & ~(ATA_AHCI_P_IX_DHR | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_SDB)));
+            KdPrint3((PRINT_PREFIX "Err intr (%#x), SE (%#x)\n",
+                chan->AhciLastIS & ~(ATA_AHCI_P_IX_DHR | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_SDB),
+                chan->AhciLastSError));
             if(chan->AhciLastIS & ~ATA_AHCI_P_IX_OF) {
-                //KdPrint3((PRINT_PREFIX "Err mask (%#x)\n", chan->AhciLastIS & ~ATA_AHCI_P_IX_OF));
-                // We have some other error except Overflow
-                // Just signal ERROR, operation will be aborted in ERROR branch.
-                statusByte |= IDE_STATUS_ERROR;
+
+                if((chan->AhciLastIS == ATA_AHCI_P_IX_INF) &&
+                   !(statusByte & IDE_STATUS_ERROR) &&
+                   !chan->AhciLastSError &&
+                   srb && (srb->SrbFlags & SRB_FLAGS_DATA_IN)
+                   ) {
+                  KdPrint3((PRINT_PREFIX "ATA_AHCI_P_IX_INF on READ, assume underflow\n"));
+                  // continue processing in regular way
+                } else {
+
+                  //KdPrint3((PRINT_PREFIX "Err mask (%#x)\n", chan->AhciLastIS & ~ATA_AHCI_P_IX_OF));
+                  // We have some other error except Overflow
+                  // Just signal ERROR, operation will be aborted in ERROR branch.
+                  statusByte |= IDE_STATUS_ERROR;
+                  AtaReq->ahci.in_serror = chan->AhciLastSError;
+                  if(chan->AhciLastSError & (ATA_SE_HANDSHAKE_ERR | ATA_SE_LINKSEQ_ERR | ATA_SE_TRANSPORT_ERR | ATA_SE_UNKNOWN_FIS)) {
+                      KdPrint2((PRINT_PREFIX "Unrecoverable\n"));
+                      NoRetry = TRUE;
+                  }
+                }
             } else {
                 // We have only Overflow. Abort operation and continue
 #ifdef _DEBUG
@@ -4960,6 +5398,13 @@ try_dpc_wait:
             UniataDumpAhciPortRegs(chan);
 #endif
             UniataAhciStatus(HwDeviceExtension, lChannel, DEVNUM_NOT_SPECIFIED);
+            if(NoRetry) {
+                AtaReq->retry += MAX_RETRIES;
+                if(!error && (statusByte & IDE_STATUS_ERROR)) {
+                    KdPrint2((PRINT_PREFIX "AtapiInterrupt: force error status\n"));
+                    error |= IDE_STATUS_ERROR;
+                }
+            }
 #ifdef _DEBUG
             UniataDumpAhciPortRegs(chan);
 #endif
@@ -4980,7 +5425,9 @@ try_dpc_wait:
             KdPrint2((PRINT_PREFIX "  Bad Lba unknown\n"));
         }
 
-
+        if(deviceExtension->HwFlags & UNIATA_AHCI) {
+            KdPrint2((PRINT_PREFIX "  no wait ready after error\n"));
+        } else
         if(!atapiDev) {
             KdPrint2((PRINT_PREFIX "  wait 100 ready after IDE error\n"));
             AtapiStallExecution(100);
@@ -5012,11 +5459,14 @@ continue_err:
 #endif //IO_STATISTICS
                 if(DmaTransfer /*&&
                    (error & IDE_ERROR_ICRC)*/) {
+                    KdPrint2((PRINT_PREFIX "Errors in DMA mode\n"));
                     if(AtaReq->retry < MAX_RETRIES) {
 //fallback_pio:
-                        AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
-                        AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
-//                        LunExt->DeviceFlags |= DFLAGS_FORCE_DOWNRATE;
+                        if(!(deviceExtension->HwFlags & UNIATA_AHCI)) {
+                            //AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
+                            // Downrate will happen in AtapiDmaReinit(), try UDMA-2 for HDD only
+                            AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
+                        }
                         AtaReq->ReqState = REQ_STATE_QUEUED;
                         goto reenqueue_req;
                     }
@@ -5031,10 +5481,20 @@ continue_err:
             interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
             KdPrint3((PRINT_PREFIX "AtapiInterrupt: ATAPI Error, int reason %x\n", interruptReason));
 
+            if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
+                if(deviceExtension->HwFlags & UNIATA_AHCI) {
+                    // Do nothing here
+                } else
+                if(deviceExtension->HwFlags & UNIATA_SATA) {
+                    UniataSataClearErr(HwDeviceExtension, lChannel, UNIATA_SATA_IGNORE_CONNECT, 0);
+                }
+            }
+
             if(DmaTransfer && (chan->lun[DeviceNumber]->TransferMode > ATA_UDMA2) &&
                ((error >> 4) == SCSI_SENSE_HARDWARE_ERROR)) {
                 if(AtaReq->retry < MAX_RETRIES) {
 //fallback_pio:
+                    // Downrate will happen in AtapiDmaReinit(), use PIO immediately for ATAPI
                     AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
                     AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
 //                        LunExt->DeviceFlags |= DFLAGS_FORCE_DOWNRATE;
@@ -5071,7 +5531,7 @@ continue_err:
               LunExt->BlockIoCount
               ));
         LunExt->RecoverCount[AtaReq->retry]++;
-        if(LunExt->RecoverCount[AtaReq->retry] >= chan->lun[DeviceNumber]->BlockIoCount/3 ||
+        if(LunExt->RecoverCount[AtaReq->retry] >= LunExt->BlockIoCount/3 ||
            (deviceExtension->HwFlags & UNIATA_NO80CHK)
            ) {
 #else
@@ -5143,6 +5603,7 @@ continue_PIO:
 
         } else {
 
+            KdPrint2((PRINT_PREFIX "AtapiInterrupt: !DRQ, !BUSY, WordsLeft %#x\n", AtaReq->WordsLeft));
             if (AtaReq->WordsLeft) {
 
                 // Funky behaviour seen with PCI IDE (not all, just one).
@@ -5208,13 +5669,16 @@ IntrPrepareResetController:
         chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
         goto CompleteRequest;
     } else
-    if (interruptReason == ATAPI_IR_COD_Cmd && (statusByte & IDE_STATUS_DRQ)) {
+    if ((interruptReason == ATAPI_IR_COD_Cmd) && (statusByte & IDE_STATUS_DRQ)) {
+        if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
+            AtapiDmaDBPreSync(HwDeviceExtension, chan, srb);
+        }
         // Write the packet.
         KdPrint3((PRINT_PREFIX "AtapiInterrupt: Writing Atapi packet.\n"));
         // Send CDB to device.
         WriteBuffer(chan, (PUSHORT)srb->Cdb, 
                           LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
-                          0);
+                          /*0*/ PIO0_TIMING);
         AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
 
         if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
@@ -5224,7 +5688,7 @@ IntrPrepareResetController:
 
         goto ReturnEnableIntr;
 
-    } else if (interruptReason == ATAPI_IR_IO_toDev && (statusByte & IDE_STATUS_DRQ)) {
+    } else if ((interruptReason == ATAPI_IR_IO_toDev) && (statusByte & IDE_STATUS_DRQ)) {
 
         // Write the data.
         if (atapiDev) {
@@ -5296,7 +5760,8 @@ IntrPrepareResetController:
 
            statusByte = WaitOnBusy(chan);
 
-           if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
+            if (/*atapiDev || */ !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/
+                || (wordCount & 1)) {
 
                WriteBuffer(chan,
                            AtaReq->DataBuffer,
@@ -5318,6 +5783,19 @@ IntrPrepareResetController:
 
             // Fail this request.
             status = SRB_STATUS_ERROR;
+            if(!wordCount && atapiDev && (srb->Cdb[0] != SCSIOP_REQUEST_SENSE)) {
+                // some devices feel bad after incorrect commands and may need reset
+                KdPrint2((PRINT_PREFIX 
+                          "AtapiInterrupt: Try ATAPI reset\n"));
+
+                AtapiDisableInterrupts(deviceExtension, lChannel);
+                AtapiSoftReset(chan, DeviceNumber);
+                AtapiEnableInterrupts(deviceExtension, lChannel);
+                status = SRB_STATUS_BUS_RESET;
+                AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
+
+//                goto IntrPrepareResetController;
+            }
             goto CompleteRequest;
         }
         // Advance data buffer pointer and bytes left.
@@ -5333,18 +5811,24 @@ IntrPrepareResetController:
 
     } else if (interruptReason == ATAPI_IR_IO_toHost && (statusByte & IDE_STATUS_DRQ)) {
 
+continue_read_drq:
 
         if (atapiDev) {
 
             // Pick up bytes to transfer and convert to words.
             wordCount =
-                AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow) |
-                (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8);
+                (ULONG)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow) |
+                ((ULONG)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8);
 
             // Convert bytes to words.
-            wordCount >>= 1;
-            KdPrint2((PRINT_PREFIX "AtapiInterrupt: get R wordCount %#x\n", wordCount));
-
+            KdPrint2((PRINT_PREFIX "AtapiInterrupt: get R byteCount %#x\n", wordCount));
+            wordCount >>= 1;            
+            /*
+                When ATAPI 64k PIO read is requested we may have 0xfffe byte 
+                count reported for 0x10000 bytes in single interrupt.
+                It is not allowed to read entire 64k block with DwordIo intead of 
+                wait for last word.
+            */
             if (wordCount != AtaReq->WordsLeft) {
                 KdPrint2((PRINT_PREFIX 
                            "AtapiInterrupt: %d words requested; %d words xferred\n",
@@ -5398,7 +5882,25 @@ IntrPrepareResetController:
 
             statusByte = WaitOnBusy(chan);
 
-            if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
+            if(wordCount&1 && atapiDev && (g_opt_VirtualMachine == VM_BOCHS)) {
+                KdPrint2((PRINT_PREFIX 
+                          "IdeIntr: unaligned ATAPI %#x Words\n", wordCount));
+            } else
+            if(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) {
+                KdPrint2((PRINT_PREFIX 
+                          "IdeIntr: pre-Read %#x Dwords\n", wordCount/2));
+
+                ReadBuffer2(chan,
+                           (PULONG)(AtaReq->DataBuffer),
+                           wordCount / 2,
+                           UniataGetPioTiming(LunExt));
+                // Advance data buffer pointer and bytes left.
+                AtaReq->DataBuffer += wordCount & ~1;
+                AtaReq->WordsLeft -= wordCount & ~1;
+                AtaReq->WordsTransfered += wordCount & ~1;
+                wordCount &= 1;
+            }
+            if (wordCount) {
                 KdPrint2((PRINT_PREFIX 
                            "IdeIntr: Read %#x words\n", wordCount));
 
@@ -5406,40 +5908,33 @@ IntrPrepareResetController:
                           AtaReq->DataBuffer,
                           wordCount,
                           UniataGetPioTiming(LunExt));
-                KdPrint2(("IdeIntr: PIO Read AtaReq->DataBuffer %#x, srb->DataBuffer %#x\n", AtaReq->DataBuffer, (srb ? srb->DataBuffer : (void*)-1) ));
-                //KdDump(AtaReq->DataBuffer, wordCount*2);
-                if(srb && atapiDev && srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
-                    KdDump(AtaReq->DataBuffer, wordCount*2);
-                }
+            }
+
+            KdPrint2(("IdeIntr: PIO Read AtaReq->DataBuffer %#x, srb->DataBuffer %#x\n", AtaReq->DataBuffer, (srb ? srb->DataBuffer : (void*)-1) ));
+            //KdDump(AtaReq->DataBuffer, wordCount*2);
+            if(srb && atapiDev && srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
+                KdDump(AtaReq->DataBuffer, wordCount*2);
+            }
 
+            GetBaseStatus(chan, statusByte);
+            KdPrint2((PRINT_PREFIX "  status re-check %#x\n", statusByte));
+
+            if(DataOverrun) {
+                KdPrint2((PRINT_PREFIX "  DataOverrun\n"));
+                AtapiSuckPort2(chan);
                 GetBaseStatus(chan, statusByte);
-                KdPrint2((PRINT_PREFIX "  status re-check %#x\n", statusByte));
+            }
 
-                if(DataOverrun) {
-                    KdPrint2((PRINT_PREFIX "  DataOverrun\n"));
-                    AtapiSuckPort2(chan);
+            if(statusByte & IDE_STATUS_BUSY) {
+                for (i = 0; i < 2; i++) {
+                    AtapiStallExecution(10);
                     GetBaseStatus(chan, statusByte);
-                }
-
-                if(statusByte & IDE_STATUS_BUSY) {
-                    for (i = 0; i < 2; i++) {
-                        AtapiStallExecution(10);
-                        GetBaseStatus(chan, statusByte);
-                        if (!(statusByte & IDE_STATUS_BUSY)) {
-                            break;
-                        }
+                    if (!(statusByte & IDE_STATUS_BUSY)) {
+                        break;
                     }
                 }
-
-            } else {
-                KdPrint2((PRINT_PREFIX 
-                          "IdeIntr: Read %#x Dwords\n", wordCount/2));
-
-                ReadBuffer2(chan,
-                           (PULONG)(AtaReq->DataBuffer),
-                           wordCount / 2,
-                           UniataGetPioTiming(LunExt));
             }
+
         } else {
 
             KdPrint3((PRINT_PREFIX 
@@ -5451,7 +5946,7 @@ IntrPrepareResetController:
             status = SRB_STATUS_ERROR;
             goto CompleteRequest;
         }
-
+//continue_atapi_pio_read:
         // Advance data buffer pointer and bytes left.
         AtaReq->DataBuffer += wordCount;
         AtaReq->WordsLeft -= wordCount;
@@ -5463,23 +5958,35 @@ IntrPrepareResetController:
             KdPrint2((PRINT_PREFIX "AtapiInterrupt: all transferred, AtaReq->WordsLeft == 0\n"));
             if (atapiDev) {
 
-                // Work around to make many atapi devices return correct sector size
-                // of 2048. Also certain devices will have sector count == 0x00, check
-                // for that also.
-                if ((srb->Cdb[0] == SCSIOP_READ_CAPACITY) &&
-                    (LunExt->IdentifyData.DeviceType == ATAPI_TYPE_CDROM)) {
+                if(LunExt->IdentifyData.DeviceType == ATAPI_TYPE_CDROM) {
 
-                    AtaReq->DataBuffer -= wordCount;
-                    if (AtaReq->DataBuffer[0] == 0x00) {
+                    // Work around to make many atapi devices return correct sector size
+                    // of 2048. Also certain devices will have sector count == 0x00, check
+                    // for that also.
+                    if (srb->Cdb[0] == SCSIOP_READ_CAPACITY) {
 
-                        *((ULONG *) &(AtaReq->DataBuffer[0])) = 0xFFFFFF7F;
+                        AtaReq->DataBuffer -= AtaReq->WordsTransfered;
+                        if (AtaReq->DataBuffer[0] == 0x00) {
+                            *((ULONG *) &(AtaReq->DataBuffer[0])) = 0xFFFFFF7F;
+                        }
 
+                        *((ULONG *) &(AtaReq->DataBuffer[2])) = 0x00080000;
+                        AtaReq->DataBuffer += AtaReq->WordsTransfered;
                     }
+#ifndef UNIATA_INIT_CHANGERS
+                    else
+                    if (srb->Cdb[0] == SCSIOP_MECHANISM_STATUS) {
 
-                    *((ULONG *) &(AtaReq->DataBuffer[2])) = 0x00080000;
-                    AtaReq->DataBuffer += wordCount;
+                        KdPrint3((PRINT_PREFIX "AtapiInterrupt: SCSIOP_MECHANISM_STATUS status %#x\n", status));
+                        // Bingo!!
+                        AtapiHwInitializeChanger (HwDeviceExtension,
+                                                  srb,
+                                                  (PMECHANICAL_STATUS_INFORMATION_HEADER) srb->DataBuffer);
+                        LunExt->DeviceFlags |= DFLAGS_CHANGER_INITED;
+                        KdPrint2((PRINT_PREFIX "  set DFLAGS_CHANGER_INITED\n"));
+                    }
+#endif // UNIATA_INIT_CHANGERS
                 }
-
                 GetStatus(chan, statusByte);
                 if(!(statusByte & IDE_STATUS_BUSY)) {
                     // Assume command is completed if BUSY is cleared
@@ -5522,6 +6029,12 @@ IntrPrepareResetController:
                     status = SRB_STATUS_SUCCESS;
                     goto CompleteRequest;
                 }
+            } else {
+                if(!atapiDev && !DataOverrun && (srb->SrbFlags & SRB_FLAGS_DATA_IN) &&
+                    ((statusByte & ~IDE_STATUS_INDEX) == (IDE_STATUS_IDLE | IDE_STATUS_DRQ))) {
+                    KdPrint2((PRINT_PREFIX "  HDD read data ready \n"));
+                    goto continue_read_drq;
+                }
             }
         }
 
@@ -5530,7 +6043,7 @@ IntrPrepareResetController:
     } else if (interruptReason == (ATAPI_IR_IO_toHost | ATAPI_IR_COD_Cmd) && !(statusByte & IDE_STATUS_DRQ)) {
 
         KdPrint2((PRINT_PREFIX "AtapiInterrupt: interruptReason = CompleteRequest\n"));
-        // Command complete. We exactly know this because os IReason.
+        // Command complete. We exactly know this because of IReason.
 
         if(DmaTransfer) {
             KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest, was DmaTransfer\n"));
@@ -5544,6 +6057,9 @@ IntrPrepareResetController:
             AtaReq->DataBuffer += wordCount;
             AtaReq->WordsLeft -= wordCount;
             AtaReq->WordsTransfered += wordCount;
+
+            KdPrint2((PRINT_PREFIX "AtapiInterrupt: wordCount %#x, WordsTransfered %#x\n", wordCount, AtaReq->WordsTransfered));
+
         }
         //if (AtaReq->WordsLeft) {
         //    status = SRB_STATUS_DATA_OVERRUN;
@@ -5571,7 +6087,7 @@ IntrPrepareResetController:
             }
 
             KdPrint(("--\n"));
-            KdPrint2(("VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
+            KdPrint2(("DeviceID+VendorID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
             KdPrint2(("P:T:D=%d:%d:%d\n",
                                       Srb->PathId,
                                       Srb->TargetId,
@@ -5616,7 +6132,8 @@ CompleteRequest:
 
             KdPrint2((PRINT_PREFIX "AtapiInterrupt: OriginalSrb != NULL\n"));
             if (srb->Cdb[0] == SCSIOP_MECHANISM_STATUS) {
-
+#ifdef UNIATA_INIT_CHANGERS
+                // We can get here only when UNIATA_INIT_CHANGERS is defined
                 KdPrint3((PRINT_PREFIX "AtapiInterrupt: SCSIOP_MECHANISM_STATUS status %#x\n", status));
                 if (status == SRB_STATUS_SUCCESS) {
                     // Bingo!!
@@ -5657,11 +6174,16 @@ CompleteRequest:
                     AtapiDisableInterrupts(HwDeviceExtension, c);
                 }
 */
-
+#else 
+                KdPrint((PRINT_PREFIX "AtapiInterrupt: ERROR: internal SCSIOP_MECHANISM_STATUS !!!!\n"));
+                ASSERT(FALSE);
+#endif // UNIATA_INIT_CHANGERS
             } else { // srb->Cdb[0] == SCSIOP_REQUEST_SENSE)
 
                 PSENSE_DATA senseData = (PSENSE_DATA) srb->DataBuffer;
-
+#ifdef __REACTOS__
+                (void)senseData;
+#endif
                 KdPrint3((PRINT_PREFIX "AtapiInterrupt: ATAPI command status %#x\n", status));
                 if (status == SRB_STATUS_DATA_OVERRUN) {
                     // Check to see if we at least get mininum number of bytes
@@ -5673,7 +6195,9 @@ CompleteRequest:
 
                 if (status == SRB_STATUS_SUCCESS) {
 #ifndef UNIATA_CORE
+#ifdef UNIATA_INIT_CHANGERS
                     if ((senseData->SenseKey != SCSI_SENSE_ILLEGAL_REQUEST) &&
+                        FALSE &&
                         chan->MechStatusRetryCount) {
 
                         KdPrint3((PRINT_PREFIX "AtapiInterrupt: MechStatusRetryCount %#x\n", chan->MechStatusRetryCount));
@@ -5682,14 +6206,9 @@ CompleteRequest:
                         srb = AtaReq->Srb = BuildMechanismStatusSrb (
                                                               HwDeviceExtension,
                                                               AtaReq->OriginalSrb);
-                    } else {
-
-                        // last request was illegal.  No point trying again.
-                        // Do-nothing call ?
-                        AtapiHwInitializeChanger (HwDeviceExtension,
-                                                  srb,
-                                                  (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
-
+                    } else
+#endif // UNIATA_INIT_CHANGERS
+                    {
                         // Get ready to issue the original srb
                         srb = AtaReq->Srb = AtaReq->OriginalSrb;
                         AtaReq->OriginalSrb = NULL;
@@ -5727,11 +6246,6 @@ CompleteRequest:
             KdPrint3((PRINT_PREFIX "AtapiInterrupt: Error. complete OriginalSrb\n"));
 
             if (AtaReq->OriginalSrb) {
-                KdPrint2((PRINT_PREFIX "AtapiInterrupt: call AtapiHwInitializeChanger()\n"));
-                // Do-nothing call ?
-                AtapiHwInitializeChanger (HwDeviceExtension,
-                                          srb,
-                                          (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
                 srb = AtaReq->Srb = AtaReq->OriginalSrb;
                 AtaReq->OriginalSrb = NULL;
             }
@@ -6043,6 +6557,15 @@ reenqueue_req:
                     interruptReason,
                     statusByte));
 
+        if(g_opt_VirtualMachine == VM_QEMU) {
+            if(interruptReason == ATAPI_IR_IO_toDev && !(statusByte & IDE_STATUS_DRQ) && !DmaTransfer) {
+                statusByte = WaitForDrq(chan);
+                if(statusByte & IDE_STATUS_DRQ) {
+                    goto continue_PIO;
+                }
+            }
+        }
+
         if(OldReqState == REQ_STATE_DPC_WAIT_BUSY0 &&
            AtaReq->WordsLeft == 0) {
             KdPrint2((PRINT_PREFIX "AtapiInterrupt: pending WAIT_BUSY0. Complete.\n"));
@@ -6257,6 +6780,7 @@ UniAtaCalculateLBARegs(
     ULONG                tmp;
 
     if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
+        (*max_bcount) = 0;
         if(LunExt->LimitedTransferMode >= ATA_DMA) {
             if(LunExt->DeviceExtension) {
                 (*max_bcount) = LunExt->DeviceExtension->MaximumDmaTransferLength / DEV_BSIZE;
@@ -6280,7 +6804,6 @@ UniAtaCalculateLBARegs(
         KdPrint2((PRINT_PREFIX "UniAtaCalculateLBARegs: C:H:S=%#x:%#x:%#x, max_bc %#x\n",
             cylinder, drvSelect, sectorNumber, (*max_bcount)));
     }
-        (*max_bcount) = 0;
 
     return (ULONG)(sectorNumber&0xff) | (((ULONG)cylinder&0xffff)<<8) | (((ULONG)drvSelect&0xf)<<24);
 } // end UniAtaCalculateLBARegs()
@@ -6346,7 +6869,7 @@ IdeReadWrite(
     //ULONG                ldev = GET_LDEV(Srb);
     UCHAR                DeviceNumber = GET_CDEV(Srb);;
     ULONGLONG            startingSector=0;
-    ULONG                max_bcount;
+    ULONG                max_bcount = 0;
     ULONG                wordCount = 0;
     UCHAR                statusByte,statusByte2;
     UCHAR                cmd;
@@ -6388,13 +6911,23 @@ IdeReadWrite(
             AtaReq->TransferLength = Srb->DataTransferLength;
             // Set up 1st block.
             switch(Srb->Cdb[0]) {
-            case SCSIOP_READ:
             case SCSIOP_WRITE:
+                if(LunExt->DeviceFlags & DFLAGS_LBA32plus) {
+                  KdPrint2((PRINT_PREFIX "Attention: SCSIOP_WRITE on 2TB\n"));
+                  //return SRB_STATUS_ERROR;
+                }
+                // FALLTHROUGH
+            case SCSIOP_READ:
                 MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA);
                 MOV_SWP_DW2DD(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
                 break;
-            case SCSIOP_READ12:
             case SCSIOP_WRITE12:
+                if(LunExt->DeviceFlags & DFLAGS_LBA32plus) {
+                  KdPrint2((PRINT_PREFIX "Attention: SCSIOP_WRITE12 on 2TB\n"));
+                  //return SRB_STATUS_ERROR;
+                }
+                // FALLTHROUGH
+            case SCSIOP_READ12:
                 MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB12READWRITE.LBA);
                 MOV_DD_SWP(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB12READWRITE.NumOfBlocks);
                 break;
@@ -6423,6 +6956,18 @@ IdeReadWrite(
                    AtaReq->bcount));
 
         AtaReq->lba = lba;
+        if(LunExt->errRetry &&
+           lba == LunExt->errLastLba &&
+           /* AtaReq->bcount && */ // errRetry can be set only for non-zero bcount
+           AtaReq->bcount == LunExt->errBCount) {
+            KdPrint3((PRINT_PREFIX "IdeReadWrite: Retry after BUS_RESET %d @%#I64x (%#x)\n",
+                LunExt->errRetry, LunExt->errLastLba, LunExt->errBCount));
+            if(AtaReq->retry < MAX_RETRIES) {
+                AtaReq->retry = LunExt->errRetry;
+                AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
+            }
+            LunExt->errRetry = 0;
+        }
 
         // assume best case here
         // we cannot reinit Dma until previous request is completed
@@ -6548,21 +7093,36 @@ IdeReadWrite(
 
     if ((Srb->SrbFlags & SRB_FLAGS_DATA_IN) ||
         use_dma) {
+        if(use_dma) {
+            AtapiDmaDBPreSync(HwDeviceExtension, chan, Srb);
+            if(g_opt_BochsDmaReadWorkaround &&
+               (Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
+                KdPrint2((PRINT_PREFIX "CTRFLAGS_DMA_BEFORE_R on BOCHS\n"));
+                AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
+            }
+        }
         statusByte2 = AtaCommand48(deviceExtension, DeviceNumber, lChannel,
                      cmd, lba,
                      (USHORT)(AtaReq->bcount),
 //                     (UCHAR)((wordCount*2 + DEV_BSIZE-1) / DEV_BSIZE),
                      0, ATA_IMMEDIATE);
-        if(statusByte2 != IDE_STATUS_WRONG) {
+/*        if(statusByte2 != IDE_STATUS_WRONG) {
             GetStatus(chan, statusByte2);
-        }
+        }*/
         if(statusByte2 & IDE_STATUS_ERROR) {
+            // Unfortunately, we cannot handle errors in such a way in real life (except known bad blocks).
+            // Because some devices doesn't reset ERR from previous command immediately after getting new one.
+            // On the other hand we cannot wait here because of possible timeout condition
             statusByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
             KdPrint2((PRINT_PREFIX "IdeReadWrite: status %#x, error %#x\n", statusByte2, statusByte));
             return SRB_STATUS_ERROR;
         }
         if(use_dma) {
-            AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
+           if(!g_opt_BochsDmaReadWorkaround ||
+              !(Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
+                //GetStatus(chan, statusByte2);
+                AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
+            }
         }
         return SRB_STATUS_PENDING;
     }
@@ -6604,7 +7164,7 @@ IdeReadWrite(
                                   CHECK_INTR_IDLE);
 
     // Write next DEV_BSIZE/2*N words.
-    if (!(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED)) {
+    if (!(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) || (wordCount & 1)) {
         KdPrint2((PRINT_PREFIX 
                    "IdeReadWrite: Write %#x words\n", wordCount));
 
@@ -6627,6 +7187,7 @@ IdeReadWrite(
     // Adjust buffer address and words left count.
     AtaReq->WordsLeft -= wordCount;
     AtaReq->DataBuffer += wordCount;
+    AtaReq->WordsTransfered += wordCount;
 
     // Wait for interrupt.
     return SRB_STATUS_PENDING;
@@ -6679,7 +7240,7 @@ IdeVerify(
     }
 
     KdPrint2((PRINT_PREFIX 
-                "IdeVerify: Total sectors %#x\n",
+                "IdeVerify: Total sectors %#I64x\n",
                 sectors));
 
     // Get starting sector number from CDB.
@@ -6743,6 +7304,7 @@ IdeVerify(
 
     if(!(statusByte & IDE_STATUS_ERROR)) {
         // Wait for interrupt.
+        UniataExpectChannelInterrupt(chan, TRUE);
         return SRB_STATUS_PENDING;
     }
     return SRB_STATUS_ERROR;
@@ -6780,10 +7342,11 @@ AtapiSendCommand(
     ULONG                DeviceNumber = GET_CDEV(Srb);
     ULONG flags;
     UCHAR statusByte,statusByte0,byteCountLow,byteCountHigh;
+    UCHAR interruptReason;
     BOOLEAN use_dma = FALSE;
     BOOLEAN dma_reinited = FALSE;
     BOOLEAN retried = FALSE;
-    ULONG                fis_size;
+    ULONG                fis_size, i;
     UCHAR FeatureReg=0;
 
     LunExt = chan->lun[DeviceNumber];
@@ -6811,7 +7374,7 @@ AtapiSendCommand(
         }
 
         KdPrint(("--\n"));
-        KdPrint2(("VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
+        KdPrint2(("DeviceID+VendorID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
         KdPrint2(("P:T:D=%d:%d:%d\n",
                                   Srb->PathId,
                                   Srb->TargetId,
@@ -6883,25 +7446,42 @@ AtapiSendCommand(
         case SCSIOP_WRITE16:
             // all right
             break;
+        case SCSIOP_READ_CD:
+        case SCSIOP_READ_CD_MSF:
+            if(deviceExtension->opt_AtapiDmaRawRead) {
+                // all right
+                break;
+            }
+            /* FALL THROUGH */
         default:
             KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_BUSY\n"));
             return SRB_STATUS_BUSY;
         }
         //
+#ifdef UNIATA_INIT_CHANGERS
         if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED) &&
             !AtaReq->OriginalSrb) {
             KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_BUSY (2)\n"));
             return SRB_STATUS_BUSY;
         }
+#endif // UNIATA_INIT_CHANGERS
     }
 
 #ifndef UNIATA_CORE
+    // standard atapi.sys claims:
+
     // We need to know how many platters our atapi cd-rom device might have.
     // Before anyone tries to send a srb to our target for the first time,
     // we must "secretly" send down a separate mechanism status srb in order to
     // initialize our device extension changer data.  That's how we know how
     // many platters our target has.
 
+    // BUT!
+    // some devices freeze (sometimes) forever on this command
+    // Let CD-ROM driver send this command itself, if it find it necessary
+    // We shall just parse output (if any)
+
+#ifdef UNIATA_INIT_CHANGERS
     if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED) &&
         !AtaReq->OriginalSrb) {
 
@@ -6939,17 +7519,12 @@ AtapiSendCommand(
             }
 
             // failed again ? should not get here
-
             AtaReq->Srb = AtaReq->OriginalSrb;
             AtaReq->OriginalSrb = NULL;
-
-            KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiHwInitializeChanger()\n"));
-            // Do-nothing call ?
-            AtapiHwInitializeChanger (HwDeviceExtension, Srb,
-                                      (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
             // fall out
         }
     }
+#endif // UNIATA_INIT_CHANGERS
 #endif //UNIATA_CORE
 
     if((CmdAction & CMD_ACTION_PREPARE) &&
@@ -7017,6 +7592,10 @@ GetLba2:
         }
 
         // check if DMA read/write
+        if(g_opt_AtapiNoDma) {
+            KdPrint2((PRINT_PREFIX "AtapiSendCommand: CTRFLAGS_DMA_BEFORE_R => no dma\n"));
+            use_dma = FALSE;
+        } else
         if(deviceExtension->HwFlags & UNIATA_AHCI) {
             KdPrint2((PRINT_PREFIX "AtapiSendCommand: force use dma (ahci)\n"));
             use_dma = TRUE;
@@ -7030,8 +7609,9 @@ GetLba2:
         if(Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
             KdPrint2((PRINT_PREFIX "AtapiSendCommand: SCSIOP_REQUEST_SENSE, no DMA setup\n"));
         } else
-        if(AtaReq->TransferLength) {
-            // try use DMA
+        if(AtaReq->TransferLength && !(AtaReq->TransferLength & 0x0f)) {
+            KdPrint2((PRINT_PREFIX "AtapiSendCommand: try DMA setup\n"));
+            // try use DMA if TransferLength is 16-byte aligned
             switch(Srb->Cdb[0]) {
             case SCSIOP_WRITE:
             case SCSIOP_WRITE12:
@@ -7062,6 +7642,7 @@ call_dma_setup:
                 }
                 break;
             case SCSIOP_READ_CD:
+            case SCSIOP_READ_CD_MSF:
                 if(deviceExtension->opt_AtapiDmaRawRead)
                     goto call_dma_setup;
                 break;
@@ -7100,7 +7681,7 @@ setup_dma:
                 }
             }
         } else {
-            KdPrint2((PRINT_PREFIX "AtapiSendCommand: zero transfer, no DMA setup\n"));
+            KdPrint2((PRINT_PREFIX "AtapiSendCommand: zero/unaligned transfer %x, no DMA setup\n", AtaReq->TransferLength));
         }
 
 
@@ -7122,9 +7703,11 @@ setup_dma:
                 AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
             } else {
                 FeatureReg |= ATA_F_DMA;
-                if(LunExt->IdentifyData.AtapiDMA.DMADirRequired &&
-                   (Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
-                    FeatureReg |= ATA_F_DMAREAD;
+                if(LunExt->IdentifyData.AtapiDMA.DMADirRequired) {
+                    if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+                        KdPrint2((PRINT_PREFIX "Set DMADir.\n"));
+                        FeatureReg |= ATA_F_DMAREAD;
+                    }
                 }
             }
 
@@ -7315,9 +7898,8 @@ retry:
         }
 */
         if (statusByte & IDE_STATUS_DRQ) {
+            KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ still asserted. Status (%#x)\n", statusByte));
 make_reset:
-            KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ still asserted.Status (%#x)\n", statusByte));
-
             AtapiDisableInterrupts(deviceExtension, lChannel);
 
             AtapiSoftReset(chan, DeviceNumber);
@@ -7384,29 +7966,25 @@ make_reset:
 
     if(use_dma) {
         FeatureReg |= ATA_F_DMA;
-        if(LunExt->IdentifyData.AtapiDMA.DMADirRequired &&
-           (Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
-            FeatureReg |= ATA_F_DMAREAD;
+        if(LunExt->IdentifyData.AtapiDMA.DMADirRequired) {
+            if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+                FeatureReg |= ATA_F_DMAREAD;
+            }
         }
     }
 
-    AtapiWritePort1(chan, IDX_IO1_o_Feature, FeatureReg);
-
     // Write transfer byte count to registers.
-    byteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
-    byteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8);
-
     if (Srb->DataTransferLength >= 0x10000) {
         byteCountLow = byteCountHigh = 0xFF;
+    } else {
+        byteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
+        byteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8);
     }
 
-    AtapiWritePort1(chan, IDX_ATAPI_IO1_o_ByteCountLow, byteCountLow);
-    AtapiWritePort1(chan, IDX_ATAPI_IO1_o_ByteCountHigh, byteCountHigh);
+    KdPrint3((PRINT_PREFIX "AtapiSendCommand: F:%#x, CntHL:%#x:%#x.\n", FeatureReg, byteCountHigh, byteCountLow));
 
     if (flags & DFLAGS_INT_DRQ) {
-
         // This device interrupts when ready to receive the packet.
-
         KdPrint3((PRINT_PREFIX "AtapiSendCommand: Wait for int. to send packet. Status (%#x)\n",
                    statusByte));
 
@@ -7414,43 +7992,51 @@ make_reset:
         AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_CMD_INTR;
         InterlockedExchange(&(chan->CheckIntr),
                                       CHECK_INTR_IDLE);
+        // inform driver that packet command must be sent in ISR
+        flags |= DFLAGS_INT_DRQ;
+    } else {
+        // This device quickly sets DRQ when ready to receive the packet.
+        KdPrint2((PRINT_PREFIX "AtapiSendCommand: Poll for int. to send packet. Status (%#x)\n",
+                   statusByte));
 
-        // Write ATAPI packet command.
-        AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET);
-
-        KdPrint3((PRINT_PREFIX "AtapiSendCommand: return SRB_STATUS_PENDING (DRQ)\n"));
-        return SRB_STATUS_PENDING;
+        UniataExpectChannelInterrupt(chan, TRUE);
+        AtaReq->ReqState = REQ_STATE_ATAPI_DO_NOTHING_INTR;
+        InterlockedExchange(&(chan->CheckIntr),
+                                      CHECK_INTR_IDLE);
 
+        if(g_opt_AtapiSendDisableIntr) {
+            AtapiDisableInterrupts(deviceExtension, lChannel);
+        }
+        // remember status. Later we may check if error appeared after cmd packet 
+        statusByte0 = statusByte;
     }
 
-    // This device quickly sets DRQ when ready to receive the packet.
-
-    KdPrint2((PRINT_PREFIX "AtapiSendCommand: Poll for int. to send packet. Status (%#x)\n",
-               statusByte));
-
-    UniataExpectChannelInterrupt(chan, TRUE);
-    AtaReq->ReqState = REQ_STATE_ATAPI_DO_NOTHING_INTR;
-    InterlockedExchange(&(chan->CheckIntr),
-                                  CHECK_INTR_IDLE);
+    // must be already selected, experimental for ROS BUG-9119
+    //AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_2 : IDE_DRIVE_1) );
+    AtapiWritePort1(chan, IDX_IO2_o_Control , 0);
+    AtapiWritePort1(chan, IDX_ATAPI_IO1_o_Feature /*IDX_IO1_o_Feature*/, FeatureReg);
+    //AtapiWritePort1(chan, IDX_ATAPI_IO1_o_Unused0, 0);  // experimental for ROS BUG-9119
+    //AtapiWritePort1(chan, IDX_ATAPI_IO1_o_Unused1, 0);  // experimental for ROS BUG-9119
+    AtapiWritePort1(chan, IDX_ATAPI_IO1_o_ByteCountLow, byteCountLow);
+    AtapiWritePort1(chan, IDX_ATAPI_IO1_o_ByteCountHigh, byteCountHigh);
+    // Write ATAPI packet command.
+    AtapiWritePort1(chan, IDX_ATAPI_IO1_o_Command /*IDX_IO1_o_Command*/, IDE_COMMAND_ATAPI_PACKET);
 
-    if(g_opt_AtapiSendDisableIntr) {
-        AtapiDisableInterrupts(deviceExtension, lChannel);
+    if (flags & DFLAGS_INT_DRQ) {
+        // Wait for interrupt and send PACKET there
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: return SRB_STATUS_PENDING (DRQ)\n"));
+        return SRB_STATUS_PENDING;
     }
-    // remember status. Later we may check if error appeared after cmd packet 
-    statusByte0 = statusByte;
-
-    // Write ATAPI packet command.
-    AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET);
 
-    // Wait for DRQ.
     WaitOnBusy(chan);
+/*
+    // Wait for DRQ.
     statusByte = WaitForDrq(chan);
 
     // Need to read status register and clear interrupt (if any)
     GetBaseStatus(chan, statusByte);
 
     if (!(statusByte & IDE_STATUS_DRQ)) {
-
         if(g_opt_AtapiSendDisableIntr) {
             AtapiEnableInterrupts(deviceExtension, lChannel);
         }
@@ -7458,29 +8044,69 @@ make_reset:
         AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
         return SRB_STATUS_ERROR;
     }
-
+*/
     GetStatus(chan, statusByte);
     KdPrint3((PRINT_PREFIX "AtapiSendCommand: status (%#x)\n", statusByte));
 
-    // Send CDB to device.
-    statusByte = WaitOnBaseBusy(chan);
+    //statusByte = WaitOnBaseBusy(chan);
 
     // Indicate expecting an interrupt and wait for it.
     UniataExpectChannelInterrupt(chan, TRUE);
-    InterlockedExchange(&(chan->CheckIntr),
-                                  CHECK_INTR_IDLE);
-    AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
 
+    for(i=0; i<5000; i++) {
+        if(g_opt_AtapiSendDisableIntr) {
+            GetStatus(chan, statusByte);
+        } else {
+            GetBaseStatus(chan, statusByte);
+        }
+        interruptReason = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason);
+        //KdPrint3((PRINT_PREFIX "AtapiSendCommand: iReason %x (%d)\n", interruptReason, i));
+        if(((interruptReason & ATAPI_IR_COD) == ATAPI_IR_COD_Cmd) &&
+           (((statusByte & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)) == IDE_STATUS_DRQ))) {
+            break;
+        }
+        AtapiStallExecution(g_opt_WaitDrqDelay*2);
+#ifdef _DEBUG
+//        KdPrint3((PRINT_PREFIX "AtapiSendCommand: wait CoD, status (%#x)\n", interruptReason));
+#endif // _DEBUG
+    }
+    if(((interruptReason & ATAPI_IR_COD) != ATAPI_IR_COD_Cmd) ||
+       (((statusByte & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)) != IDE_STATUS_DRQ)) ) {
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: no CoD raised, abort cmd\n"));
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: iReason %x (%d)\n", interruptReason, i));
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: status (%#x)\n", statusByte));
+        if(g_opt_AtapiSendDisableIntr) {
+            AtapiEnableInterrupts(deviceExtension, lChannel);
+        }
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ+CoD never asserted\n"));
+        statusByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: Err on cmd: (%#x)\n", statusByte));
+        if(statusByte >> 4) {
+            GetBaseStatus(chan, statusByte);
+            AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
+            return MapError(deviceExtension, Srb);
+        }
+        goto make_reset;
+//        AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
+//        return SRB_STATUS_ERROR;
+    } else {
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: ready for packet, status %#x, i=%d\n", interruptReason, i));
+    }
+    // clear interrupt
     GetBaseStatus(chan, statusByte);
 
+    if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
+        AtapiDmaDBPreSync(HwDeviceExtension, chan, Srb);
+    }
     if(g_opt_AtapiSendDisableIntr) {
         AtapiEnableInterrupts(deviceExtension, lChannel);
     }
 
+    // Send CDB to device.
     WriteBuffer(chan,
                 (PUSHORT)Srb->Cdb,
                 LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
-                0);
+                /*0*/ PIO0_TIMING);
 
     GetStatus(chan, statusByte);
     KdPrint3((PRINT_PREFIX "AtapiSendCommand: cmd status (%#x)\n", statusByte));
@@ -7488,7 +8114,6 @@ make_reset:
     // When we operate in DMA mode, we should not start transfer when there is an error on entry
     // Interrupt may never come in such case.
     if(statusByte & IDE_STATUS_ERROR) {
-        UCHAR interruptReason;
 
         GetBaseStatus(chan, statusByte);
         KdPrint3((PRINT_PREFIX "AtapiSendCommand: Error on cmd: (%#x)\n", statusByte));
@@ -7502,8 +8127,11 @@ make_reset:
         AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
         return MapError(deviceExtension, Srb);
     }
-/*    if(statusByte & IDE_STATUS_DSC) {
-        KdPrint3((PRINT_PREFIX "AtapiSendCommand: DSC on cmd: (%#x)\n", statusByte));
+    if(statusByte & IDE_STATUS_DRQ) {
+        // Some devices require this. If error condition is not checked in such a way,
+        // device may not operate correctly and would be treated as failed
+        // (and finally invisible for OS)
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ on cmd: (%#x)\n", statusByte));
         // Read the error reg. to clear it and fail this request.
         statusByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
         KdPrint3((PRINT_PREFIX "AtapiSendCommand: Err on cmd: (%#x)\n", statusByte));
@@ -7513,11 +8141,15 @@ make_reset:
             return MapError(deviceExtension, Srb);
         }
     }
-*/
+
     if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
         AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
     }
 
+    InterlockedExchange(&(chan->CheckIntr),
+                                  CHECK_INTR_IDLE);
+    AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
+
     KdPrint3((PRINT_PREFIX "AtapiSendCommand: ExpectingInterrupt (%#x)\n", chan->ExpectingInterrupt));
 
     KdPrint2((PRINT_PREFIX "AtapiSendCommand: return SRB_STATUS_PENDING (3)\n"));
@@ -7782,7 +8414,11 @@ default_no_prep:
             } else {
                 RtlZeroMemory(modeData, sizeof(MODE_POWER_CONDITION_PAGE));
                 modeData->PageCode = MODE_PAGE_POWER_CONDITION;
+#ifdef __REACTOS__
+                modeData->PageLength = sizeof(MODE_POWER_CONDITION_PAGE)-sizeof(MODE_PARAMETER_HEADER);
+#else
                 modeData->PageLength = sizeof(MODE_PAGE_POWER_CONDITION)-sizeof(MODE_PARAMETER_HEADER);
+#endif
                 modeData->Byte3.Fields.Idle = LunExt->PowerState <= StartStop_Power_Idle;
                 modeData->Byte3.Fields.Standby = LunExt->PowerState == StartStop_Power_Standby;
                 Srb->DataTransferLength = sizeof(MODE_POWER_CONDITION_PAGE);
@@ -8216,6 +8852,9 @@ invalid_cdb:
 
             AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, regs->bDriveHeadReg);
             AtapiStallExecution(10);
+            if(use_dma) {
+                AtapiDmaDBPreSync(HwDeviceExtension, chan, Srb);
+            }
 
             if((regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) == 0) {      // execute ATA command
                 AtapiWritePort1(chan, IDX_IO1_o_Feature,      regs->bFeaturesReg);
@@ -8650,7 +9289,7 @@ AtapiStartIo__(
         KdPrint2((PRINT_PREFIX 
                    "** AtapiStartIo: Function %#x, PATH:LUN:TID = %#x:%#x:%#x\n",
                    Srb->Function, Srb->PathId, Srb->Lun, Srb->TargetId));
-        KdPrint2((PRINT_PREFIX "   VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
+        KdPrint2((PRINT_PREFIX "   DeviceID+VendorID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
 
         if(lChannel == deviceExtension->NumberChannels &&
            !Srb->Lun && !Srb->TargetId &&
@@ -9724,7 +10363,7 @@ complete_req:
 
 } // end AtapiStartIo__()
 
-
+#if 0
 void
 NTAPI
 UniataInitAtaCommands()
@@ -9761,7 +10400,7 @@ UniataInitAtaCommands()
         case IDE_COMMAND_WRITE_LOG_DMA48:
         case IDE_COMMAND_TRUSTED_RCV_DMA:
         case IDE_COMMAND_TRUSTED_SEND_DMA:
-        case IDE_COMMAND_DATA_SET_MGMT:
+        case IDE_COMMAND_DATA_SET_MGMT: // TRIM
             //KdPrint2((PRINT_PREFIX "DMA "));
             flags |= ATA_CMD_FLAG_DMA;
         }
@@ -9889,6 +10528,7 @@ UniataInitAtaCommands()
         AtaCommandFlags[i] = flags;
     }
 } // end UniataInitAtaCommands()
+#endif
 
 /*++
 
@@ -9915,7 +10555,7 @@ DriverEntry(
 {
     HW_INITIALIZATION_DATA_COMMON hwInitializationData;
     ULONG                  adapterCount;
-    ULONG                  i, c, alt;
+    ULONG                  i, c, alt, pref_alt;
     ULONG                  statusToReturn, newStatus;
     PUNICODE_STRING        RegistryPath = (PUNICODE_STRING)Argument2;
     BOOLEAN                ReEnter = FALSE;
@@ -9927,16 +10567,60 @@ DriverEntry(
     PCONFIGURATION_INFORMATION GlobalConfig = IoGetConfigurationInformation();
     BOOLEAN PrimaryClaimed   = FALSE;
     BOOLEAN SecondaryClaimed = FALSE;
+    BOOLEAN IgnoreIsaCompatiblePci = FALSE;
+    BOOLEAN IgnoreNativePci = FALSE;
 
     LARGE_INTEGER t0, t1;
 
-    Connect_DbgPrint();
     KdPrint2((PRINT_PREFIX "%s", (PCCHAR)ver_string));
     //a = (WCHAR)strlen(ver_string);
 
-    g_opt_Verbose = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"PrintLogo", 0);
-    if(g_opt_Verbose) {
-        _PrintNtConsole("Universal ATA driver v 0." UNIATA_VER_STR "\n");
+    statusToReturn = 0xffffffff;
+
+    // Zero out structure.
+    RtlZeroMemory(((PCHAR)&hwInitializationData), sizeof(hwInitializationData));
+
+    // Set size of hwInitializationData.
+    hwInitializationData.comm.HwInitializationDataSize =
+      sizeof(hwInitializationData.comm) +
+//      sizeof(hwInitializationData.nt4) +
+      ((WinVer_Id() <= WinVer_NT) ? 0 : sizeof(hwInitializationData.w2k));
+    KdPrint(("HwInitializationDataSize = %x\n", hwInitializationData.comm.HwInitializationDataSize));
+
+    // Set entry points.
+    hwInitializationData.comm.HwInitialize = (PHW_INITIALIZE)AtapiHwInitialize;
+    hwInitializationData.comm.HwResetBus = (PHW_RESET_BUS)AtapiResetController;
+    hwInitializationData.comm.HwStartIo = (PHW_STARTIO)AtapiStartIo;
+    hwInitializationData.comm.HwInterrupt = (PHW_INTERRUPT)AtapiInterrupt;
+
+    // Specify size of extensions.
+    hwInitializationData.comm.DeviceExtensionSize     = sizeof(HW_DEVICE_EXTENSION);
+    hwInitializationData.comm.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION);
+    hwInitializationData.comm.SrbExtensionSize        = sizeof(ATA_REQ);
+
+    // Indicate PIO device.
+    hwInitializationData.comm.MapBuffers = TRUE;
+
+    // Request and parse arument string.
+    KdPrint2((PRINT_PREFIX "\n\nUniATA: parse ArgumentString\n"));
+    // Zero out structure.
+    hwInitializationData.comm.NumberOfAccessRanges = 2;
+    hwInitializationData.comm.HwFindAdapter = AtapiReadArgumentString;
+    ScsiPortInitialize(DriverObject,
+                                    Argument2,
+                                    &hwInitializationData.comm,
+                                    &adapterCount);
+
+    if(!g_Dump) {
+        Connect_DbgPrint();
+        g_opt_Verbose = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"PrintLogo", 0);
+        if(g_opt_Verbose) {
+            _PrintNtConsole("Universal ATA driver v 0." UNIATA_VER_STR "\n");
+        }
+        IgnoreIsaCompatiblePci = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreIsaCompatiblePci", IgnoreIsaCompatiblePci) ? TRUE : FALSE;
+        IgnoreNativePci = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreNativePci", IgnoreNativePci) ? TRUE : FALSE;
+    } else {
+        KdPrint(("crashdump mode\n"));
     }
 
     if(!SavedDriverObject) {
@@ -9946,6 +10630,7 @@ DriverEntry(
         MajorVersion=0x04;
         MinorVersion=0x01;
         BuildNumber=1;
+        CPU_num = KeNumberProcessors;
 #else
         // we are here for the 1st time
         // init CrossNT and get OS version
@@ -9954,8 +10639,9 @@ DriverEntry(
             //HalDisplayString((PUCHAR)"DbgPrnHkInitialize: CrNtInit failed\n");
             return status;
         }
+        CPU_num = *KeNumberProcessors;
 #endif // USE_REACTOS_DDK
-        KdPrint(("UniATA Init: OS ver %x.%x (%d), %d CPU(s)\n", MajorVersion, MinorVersion, BuildNumber, KeNumberProcessors));
+        KdPrint(("UniATA Init: OS ver %x.%x (%d), %d CPU(s)\n", MajorVersion, MinorVersion, BuildNumber, CPU_num));
 
         KeQuerySystemTime(&t0);
         do {
@@ -9979,7 +10665,8 @@ DriverEntry(
 
     if(!ReEnter) {
         // init ATA command translation table
-        UniataInitAtaCommands();
+        //UniataInitAtaCommands();
+
         // get registry path to settings
         RtlCopyMemory(&SavedRegPath, RegistryPath, sizeof(UNICODE_STRING));
         SavedRegPath.Buffer = (PWCHAR)&SavedRegPathBuffer;
@@ -10006,31 +10693,6 @@ DriverEntry(
     g_LogToDisplay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"LogToDisplay", 0);
 #endif //_DEBUG
 
-    statusToReturn = 0xffffffff;
-
-    // Zero out structure.
-    RtlZeroMemory(((PCHAR)&hwInitializationData), sizeof(hwInitializationData));
-
-    // Set size of hwInitializationData.
-    hwInitializationData.comm.HwInitializationDataSize =
-      sizeof(hwInitializationData.comm) +
-//      sizeof(hwInitializationData.nt4) +
-      ((WinVer_Id() <= WinVer_NT) ? 0 : sizeof(hwInitializationData.w2k));
-    KdPrint(("HwInitializationDataSize = %x\n", hwInitializationData.comm.HwInitializationDataSize));
-
-    // Set entry points.
-    hwInitializationData.comm.HwInitialize = (PHW_INITIALIZE)AtapiHwInitialize;
-    hwInitializationData.comm.HwResetBus = (PHW_RESET_BUS)AtapiResetController;
-    hwInitializationData.comm.HwStartIo = (PHW_STARTIO)AtapiStartIo;
-    hwInitializationData.comm.HwInterrupt = (PHW_INTERRUPT)AtapiInterrupt;
-
-    // Specify size of extensions.
-    hwInitializationData.comm.DeviceExtensionSize     = sizeof(HW_DEVICE_EXTENSION);
-    hwInitializationData.comm.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION);
-    hwInitializationData.comm.SrbExtensionSize        = sizeof(ATA_REQ);
-
-    // Indicate PIO device.
-    hwInitializationData.comm.MapBuffers = TRUE;
     // Set PnP-specific API
     if(WinVer_Id() > WinVer_NT) {
         KdPrint(("set NeedPhysicalAddresses = TRUE\n"));
@@ -10039,8 +10701,7 @@ DriverEntry(
         hwInitializationData.w2k.HwAdapterControl = (PHW_ADAPTER_CONTROL)AtapiAdapterControl;
     }
 
-    KdPrint2((PRINT_PREFIX "\n\nATAPI IDE enum supported BusMaster Devices\n"));
-
+    KdPrint2((PRINT_PREFIX "\n\nUniATA init... (%d)\n", ReEnter));
     if(!ReEnter) {
 
         g_opt_VirtualMachine = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"VirtualMachineType", g_opt_VirtualMachine);
@@ -10051,7 +10712,11 @@ DriverEntry(
             g_opt_VirtualMachine = VM_VBOX;
         }
         // Pre-scan PCI bus, also check if we are under VM
-        UniataEnumBusMasterController(DriverObject, Argument2);
+        // But do not perform scan if PCI bus is claimed as unused
+        if(!IgnoreIsaCompatiblePci || !IgnoreNativePci) {
+            KdPrint2((PRINT_PREFIX "\nATAPI IDE enum supported PCI BusMaster Devices\n"));
+            UniataEnumBusMasterController(DriverObject, Argument2);
+        }
 
         switch(g_opt_VirtualMachine) {
         case VM_VBOX:
@@ -10062,19 +10727,30 @@ DriverEntry(
             g_opt_WaitDrqDelay  = 100;
             g_opt_WaitBusyLongCount = 20000;
             g_opt_MaxIsrWait = 200;
-            g_opt_AtapiSendDisableIntr = 0;
+            g_opt_AtapiSendDisableIntr = FALSE;
             g_opt_AtapiDmaRawRead = FALSE;
             break;
+        case VM_BOCHS:
+            KdPrint2((PRINT_PREFIX "adjust options for Bochs\n"));
+            g_opt_AtapiNoDma = TRUE;
         }
 
         if(!hasPCI) {
             KdPrint2((PRINT_PREFIX "old slow machine, adjust timings\n"));
-            // old slow machine, adjust timings
+            // old slow machine, adjust timings (us)
+            g_opt_WaitBusyResetCount = 20000;
             g_opt_WaitBusyCount = 20000;
             g_opt_WaitBusyDelay = 150;
             g_opt_WaitDrqDelay  = 100;
             g_opt_WaitBusyLongCount = 20000;
             g_opt_MaxIsrWait = 200;
+            g_opt_DriveSelectNanoDelay = 400;
+        }
+        if(g_opt_VirtualMachine > VM_NONE) {
+            g_opt_DriveSelectNanoDelay = 0;
+        }
+        if(CPU_num > 1) {
+            g_opt_AtapiSendDisableIntr = TRUE;
         }
 
         g_opt_WaitBusyCount = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyCount", g_opt_WaitBusyCount); // 200 vs 20000
@@ -10082,10 +10758,12 @@ DriverEntry(
         g_opt_WaitDrqDelay  = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitDrqDelay",  g_opt_WaitDrqDelay);  // 10 vs 100
         g_opt_WaitBusyLongCount = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyLongCount", g_opt_WaitBusyLongCount); // 2000 vs 20000
         g_opt_WaitBusyLongDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyLongDelay", g_opt_WaitBusyLongDelay); // 250 vs 250
-        g_opt_AtapiSendDisableIntr = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiSendDisableIntr",  g_opt_AtapiSendDisableIntr);  // 1 vs 0
-        g_opt_AtapiDmaRawRead      = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiDmaRawRead",       g_opt_AtapiDmaRawRead);       // 1 vs 0
-        g_opt_MaxIsrWait    = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"MaxIsrWait",       g_opt_MaxIsrWait);       // 40 vs xxx
-    }
+        g_opt_AtapiSendDisableIntr = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiSendDisableIntr",  g_opt_AtapiSendDisableIntr) ? TRUE : FALSE;  // 1 vs 0
+        g_opt_AtapiDmaRawRead      = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiDmaRawRead",       g_opt_AtapiDmaRawRead) ? TRUE : FALSE;       // 1 vs 0
+        g_opt_AtapiNoDma    = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiNoDma", g_opt_AtapiNoDma) ? TRUE : FALSE;       // 1 vs 0
+        g_opt_MaxIsrWait    = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"MaxIsrWait", g_opt_MaxIsrWait);       // 40 vs xxx
+        g_opt_DriveSelectNanoDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"DriveSelectNanoDelay", g_opt_DriveSelectNanoDelay);
+    } // end !re-enter
 
     // Look for legacy ISA-bridged PCI IDE controller (onboard)
     KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: Look for legacy ISA-bridged PCI IDE controller (onboard)\n"));
@@ -10096,7 +10774,7 @@ DriverEntry(
             KdPrint2((PRINT_PREFIX "!BMList[i].MasterDev\n"));
             break;
         }
-        if(AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreIsaCompatiblePci", 0)) {
+        if(IgnoreIsaCompatiblePci) {
             break;
         }
         if(ReEnter) {
@@ -10114,10 +10792,33 @@ DriverEntry(
             PrimaryClaimed = TRUE;
         if(GlobalConfig->AtDiskSecondaryAddressClaimed)
             SecondaryClaimed = TRUE;
+        pref_alt = 0;
 
-        if(!WinVer_WDM_Model && !PrimaryClaimed && !SecondaryClaimed &&
+        if(!WinVer_WDM_Model && !PrimaryClaimed && !SecondaryClaimed && !g_Dump &&
             !(BMList[i].ChanInitOk & 0x80)) {
-            newStatus = UniataClaimLegacyPCIIDE(i);
+            
+            // We just want to claim our PCI device in compatible mode, since we shall not
+            // tell system that we use it inside HwInitialize
+            // Even more, we shall cheat system, that work with ISA
+            // Note: this call may (but not 'must' or 'can') cause IO resource
+            // reallocation and switch to native mode if HAL supports this
+            newStatus = (ULONG)UniataClaimLegacyPCIIDE(i);
+            // Special check for NT3.51/NT4 (not ReactOS !!!)
+            if(((NTSTATUS)newStatus == STATUS_CONFLICTING_ADDRESSES) &&
+               //(BMList[i].ChanInitOk & 0x40) &&
+               /*CPU_num > 1 &&*/
+               (WinVer_Id() <= WinVer_NT)) {
+                // Some NT3/4 SMP (but not only) HALs cannot reallocate IO resources of
+                // BusMaster PCI controller
+                // Since nobody claimed Primary/Secondary yet, try init and claim them
+                // However it is not 100% safe way, especially under ReactOS, which doesn't resolve
+                // conflicts yet.
+                // We relay on ScsiPort internal checks
+                KdPrint2((PRINT_PREFIX "Can't acquire PCI part of BusMaster on SMP NT3/4 system, try init anyway.\n"));
+                newStatus = STATUS_SUCCESS;
+                // Prefer alternative init method (try to change Isa -> PCI in ConfigInfo first)
+                pref_alt = 1;
+            }
             if(newStatus != STATUS_SUCCESS) {
                 KdPrint2((PRINT_PREFIX "Can't acquire PCI part of BusMaster, try as pure ISA later.\n"));
                 break;
@@ -10128,11 +10829,10 @@ DriverEntry(
             _PrintNtConsole("Init standard Dual-channel PCI ATA controller:");
         }
 
-
         for(alt = 0; alt < (ULONG)(WinVer_WDM_Model ? 1 : 2) ; alt++) {
 
             for(c=0; c<2; c++) {
-
+                // check is channel is manually excluded
                 if(AtapiRegCheckDevValue(NULL, c, DEVNUM_NOT_SPECIFIED, L"IgnoreIsaCompatiblePci", 0)) {
                     break;
                 }
@@ -10176,7 +10876,7 @@ DriverEntry(
                 newStatus = ScsiPortInitialize(DriverObject,
                                                Argument2,
                                                &hwInitializationData.comm,
-                                               (PVOID)(i | (alt ? 0x80000000 : 0)));
+                                               UlongToPtr(i | ((alt ^ pref_alt) ? 0x80000000 : 0)));
                 KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
                 if (newStatus < statusToReturn) {
                     statusToReturn = newStatus;
@@ -10241,7 +10941,7 @@ DriverEntry(
     KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: i %d, BMListLen %d\n", i, BMListLen));
     for (; i <BMListLen; i++) {
 
-        if(AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreNativePci", 0)) {
+        if(IgnoreNativePci) {
             break;
         }
 /*        if(BMList[i].MasterDev)
@@ -10271,7 +10971,7 @@ DriverEntry(
         newStatus = ScsiPortInitialize(DriverObject,
                                        Argument2,
                                        &hwInitializationData.comm,
-                                       (PVOID)i);
+                                       UlongToPtr(i));
         KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
         if(newStatus == (ULONG)STATUS_DEVICE_DOES_NOT_EXIST && BMList[i].NeedAltInit) {
             // Note: this is actually a BUG in scsiport.sys
@@ -10284,7 +10984,7 @@ DriverEntry(
             newStatus = ScsiPortInitialize(DriverObject,
                                            Argument2,
                                            &hwInitializationData.comm,
-                                           (PVOID)(i | 0x80000000));
+                                           UlongToPtr(i | 0x80000000));
             KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x (2)\n", newStatus));
         }
         if (newStatus < statusToReturn)
@@ -10323,7 +11023,7 @@ DriverEntry(
 
     // Indicate 2 access ranges and reset FindAdapter.
     hwInitializationData.comm.NumberOfAccessRanges = 2;
-    hwInitializationData.comm.HwFindAdapter = AtapiFindController;
+    hwInitializationData.comm.HwFindAdapter = AtapiFindIsaController;
 
     if(!AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreIsa", 0)) {
         // Indicate ISA bustype.
@@ -10546,6 +11246,7 @@ AtapiRegCheckDevValue(
     IN ULONG VendorID;
     IN ULONG DeviceID;
     IN ULONG SlotNumber;
+    IN ULONG HwFlags;
 
     ULONG val = Default;
 
@@ -10555,16 +11256,38 @@ AtapiRegCheckDevValue(
         VendorID   =  deviceExtension->DevID        & 0xffff;
         DeviceID   = (deviceExtension->DevID >> 16) & 0xffff;
         SlotNumber = deviceExtension->slotNumber;
+        HwFlags    = deviceExtension->HwFlags;
     } else {
         VendorID   = 0xffff;
         DeviceID   = 0xffff;
         SlotNumber = 0xffffffff;
+        HwFlags    = 0;
     }
 
     val = AtapiRegCheckDevLunValue(
         HwDeviceExtension, L"Parameters", chan, dev, Name, val);
 
     if(deviceExtension) {
+
+        if(HwFlags & UNIATA_SATA) {
+            swprintf(namev, L"\\SATA");
+            swprintf(namex, L"Parameters%s", namev);
+            val = AtapiRegCheckDevLunValue(
+                HwDeviceExtension, namex, chan, dev, Name, val);
+        }
+        if(HwFlags & UNIATA_AHCI) {
+            swprintf(namev, L"\\AHCI");
+            swprintf(namex, L"Parameters%s", namev);
+            val = AtapiRegCheckDevLunValue(
+                HwDeviceExtension, namex, chan, dev, Name, val);
+        }
+        if(!(HwFlags & (UNIATA_SATA | UNIATA_AHCI))) {
+            swprintf(namev, L"\\PATA");
+            swprintf(namex, L"Parameters%s", namev);
+            val = AtapiRegCheckDevLunValue(
+                HwDeviceExtension, namex, chan, dev, Name, val);
+        }
+
         if(deviceExtension->AdapterInterfaceType == PCIBus) {
             // PCI
             swprintf(namev, L"\\IDE_%d", deviceExtension->DevIndex);
@@ -10666,13 +11389,17 @@ AtapiRegCheckParameterValue(
 
     UNICODE_STRING    paramPath;
 
+    if(g_Dump) {
+        goto failed;
+    }
+
     // <SavedRegPath>\<PathSuffix> -> <Name>
 //    KdPrint(( "AtapiCheckRegValue: %ws -> %ws\n", PathSuffix, Name));
 //    KdPrint(( "AtapiCheckRegValue: RegistryPath %ws\n", RegistryPath->Buffer));
 
     paramPath.Length = 0;
-    paramPath.MaximumLength = (USHORT)(RegistryPath->Length +
-        (wcslen(PathSuffix)+2)*sizeof(WCHAR));
+    paramPath.MaximumLength = RegistryPath->Length +
+        (wcslen(PathSuffix)+2)*sizeof(WCHAR);
     paramPath.Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, paramPath.MaximumLength);
     if(!paramPath.Buffer) {
         KdPrint(("AtapiCheckRegValue: couldn't allocate paramPath\n"));
@@ -10703,6 +11430,7 @@ AtapiRegCheckParameterValue(
     ExFreePool(paramPath.Buffer);
 
     if(!NT_SUCCESS(status)) {
+failed:
         doRun = Default;
     }