[UNIATA] Update to version 0.47a. CORE-15930
[reactos.git] / drivers / storage / ide / uniata / id_ata.cpp
index 92defcb..0a0c586 100644 (file)
@@ -1,12 +1,12 @@
 /*++
 
-Copyright (c) 2002-2011 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
@@ -47,11 +47,14 @@ Revision History:
     5. W2k support (binary compatibility)
     6. HDD hot swap under NT4
     7. XP support (binary compatibility)
-    8. Serial ATA (SATA/SATA2) support
+    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,19 +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
-BOOLEAN g_opt_AtapiSendDisableIntr = 1; // 0
+ULONG  g_opt_WaitBusyLongCount = 2000; // 2000
+ULONG  g_opt_WaitBusyLongDelay = 250;  // 250
+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;
@@ -117,6 +132,14 @@ AtapiHwInitialize__(
     IN ULONG lChannel
     );
 
+VOID
+NTAPI
+UniataUserDeviceReset(
+    PHW_DEVICE_EXTENSION deviceExtension,
+    PHW_LU_EXTENSION LunExt,
+    ULONG lChannel
+    );
+
 #define RESET_COMPLETE_CURRENT  0x00
 #define RESET_COMPLETE_ALL      0x01
 #define RESET_COMPLETE_NONE     0x02
@@ -255,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;                                                  \
 }
@@ -290,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;                                                  \
 }
@@ -323,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)); \
     }                                                        \
 }
 
@@ -358,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)); \
     }                                                        \
 }
 
@@ -406,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; \
     } \
@@ -451,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; \
     } \
@@ -478,6 +507,7 @@ AtapiSuckPort2(
     UCHAR statusByte;
     ULONG i;
 
+    // Assume, proper drive is already seleted
     WaitOnBusyLong(chan);
     for (i = 0; i < 0x10000; i++) {
 
@@ -485,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;
         }
@@ -495,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(
@@ -503,10 +609,12 @@ WaitOnBusy(
 {
     ULONG i;
     UCHAR Status;
-    for (i=0; i<200; i++) {
-        GetStatus(chan, Status);
+
+    GetStatus(chan, Status);
+    for (i=0; i<g_opt_WaitBusyCount; i++) {
         if (Status & IDE_STATUS_BUSY) {
-            AtapiStallExecution(10);
+            AtapiStallExecution(g_opt_WaitBusyDelay);
+            GetStatus(chan, Status);
             continue;
         } else {
             break;
@@ -527,10 +635,10 @@ WaitOnBusyLong(
     Status = WaitOnBusy(chan);
     if(!(Status & IDE_STATUS_BUSY))
         return Status;
-    for (i=0; i<2000; i++) {
+    for (i=0; i<g_opt_WaitBusyLongCount; i++) {
         GetStatus(chan, Status);
         if (Status & IDE_STATUS_BUSY) {
-            AtapiStallExecution(250);
+            AtapiStallExecution(g_opt_WaitBusyLongDelay);
             continue;
         } else {
             break;
@@ -546,7 +654,7 @@ WaitOnBaseBusy(
     )
 {
     ULONG i;
-    UCHAR Status = 0xff;
+    UCHAR Status = IDE_STATUS_WRONG;
     for (i=0; i<g_opt_WaitBusyCount; i++) {
         GetBaseStatus(chan, Status);
         if (Status & IDE_STATUS_BUSY) {
@@ -592,8 +700,8 @@ UniataIsIdle(
 {
     UCHAR Status2;
 
-    if(Status == 0xff) {
-        return 0xff;
+    if(Status == IDE_STATUS_WRONG) {
+        return IDE_STATUS_WRONG;
     }
     if(Status & IDE_STATUS_BUSY) {
         return Status;
@@ -625,7 +733,7 @@ WaitForIdleLong(
     for (i=0; i<20000; i++) {
         GetStatus(chan, Status);
         Status2 = UniataIsIdle(chan->DeviceExtension, Status);
-        if(Status2 == 0xff) {
+        if(Status2 == IDE_STATUS_WRONG) {
             // no drive ?
             break;
         } else
@@ -685,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);
@@ -702,19 +810,65 @@ AtapiSoftReset(
     GetBaseStatus(chan, statusByte2);
     KdPrint2((PRINT_PREFIX "  statusByte2 %x:\n", statusByte2));
     SelectDrive(chan, DeviceNumber);
-    AtapiStallExecution(500);
-    AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET);
-
-    // ReactOS modification: Already stop looping when we know that the drive has finished resetting.
-    // Not all controllers clear the IDE_STATUS_BUSY flag (e.g. not the VMware one), so ensure that
-    // the maximum waiting time (30 * i = 0.9 seconds) does not exceed the one of the original
-    // implementation. (which is around 1 second)
-    while ((AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) &&
-           i--)
-    {
-        AtapiStallExecution(30);
+    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(!(statusByte0 & IDE_STATUS_BUSY)) {
+            // Wait for BUSY assertion, in some cases delay may occure
+            // 100ms should be enough
+            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);
+            }
+        }
+
+        i = 30 * 1000;
+        // ReactOS modification: Already stop looping when we know that the drive has finished resetting.
+        // Not all controllers clear the IDE_STATUS_BUSY flag (e.g. not the VMware one), so ensure that
+        // the maximum waiting time (30 * i = 0.9 seconds) does not exceed the one of the original
+        // implementation. (which is around 1 second)
+        while ((AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) &&
+               i--)
+        {
+            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);
@@ -743,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
@@ -757,10 +927,10 @@ AtaCommand48(
     IN ULONGLONG lba,
     IN USHORT count,
     IN USHORT feature,
-    IN ULONG flags
+    IN ULONG wait_flags
     )
 {
-    PHW_CHANNEL          chan = &deviceExtension->chan[lChannel];
+    PHW_CHANNEL          chan = &(deviceExtension->chan[lChannel]);
     UCHAR                statusByte;
     ULONG i;
     PUCHAR plba;
@@ -769,27 +939,23 @@ AtaCommand48(
                  deviceExtension->DevIndex, deviceExtension->Channel, DeviceNumber, command, lba, count, feature ));
 
     if(deviceExtension->HwFlags & UNIATA_AHCI) {
-        PIDE_AHCI_CMD  AHCI_CMD = &(chan->AhciCtlBlock->cmd);
+        //PIDE_AHCI_CMD  AHCI_CMD = &(chan->AhciCtlBlock->cmd);
 
         KdPrint3(("  (ahci)\n"));
 
-        RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis));
+        statusByte = UniataAhciSendPIOCommand(deviceExtension, lChannel, DeviceNumber,
+            (PSCSI_REQUEST_BLOCK)NULL,
+            NULL,
+            0,
+            command,
+            lba, count,
+            feature,
+            0 /* ahci flags */ ,
+            wait_flags,
+            1000 /* timeout 1 sec */
+            );
 
-        if(!UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
-               &(AHCI_CMD->cfis[0]),
-                command,
-                lba,
-                count,
-                feature,
-                ATA_IMMEDIATE
-                )) {
-            return 0xff;
-        }
-        if(UniataAhciSendCommand(deviceExtension, lChannel, DeviceNumber, 0, 3000) == 0xff) {
-            KdPrint2(("  timeout\n"));
-            return 0xff;
-        }
-        return IDE_STATUS_IDLE;
+        return statusByte;
     }
 
     SelectDrive(chan, DeviceNumber);
@@ -806,7 +972,7 @@ AtaCommand48(
     // and not cleared after SELECT
 
     //>>>>>> NV: 2006/08/03
-    if((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) &&
+    if(((AtaCommandFlags[command] & (ATA_CMD_FLAG_LBAIOsupp|ATA_CMD_FLAG_FUA)) == ATA_CMD_FLAG_LBAIOsupp) &&
        CheckIfBadBlock(chan->lun[DeviceNumber], lba, count)) {
         KdPrint3((PRINT_PREFIX ": artificial bad block, lba %#I64x count %#x\n", lba, count));
         return IDE_STATUS_ERROR;
@@ -868,7 +1034,7 @@ AtaCommand48(
     // write command code to device
     AtapiWritePort1(chan, IDX_IO1_o_Command, command);
 
-    switch (flags) {
+    switch (wait_flags) {
     case ATA_WAIT_INTR:
 
         // caller requested wait for interrupt
@@ -890,7 +1056,7 @@ AtaCommand48(
 
             GetStatus(chan, statusByte);
             statusByte = UniataIsIdle(deviceExtension, statusByte);
-            if(statusByte == 0xff) {
+            if(statusByte == IDE_STATUS_WRONG) {
                 // no drive ?
                 break;
             } else
@@ -901,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) {
@@ -929,16 +1095,20 @@ AtaCommand48(
             }
             KdPrint2((PRINT_PREFIX "  try to continue\n"));
             statusByte &= ~IDE_STATUS_ERROR;
+
+        } else {
+            //KdPrint2((PRINT_PREFIX "  send Status %#x\n", statusByte));
         }
-        chan->ExpectingInterrupt = TRUE;
+        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()
@@ -959,37 +1129,28 @@ AtaCommand(
     IN UCHAR sector,
     IN UCHAR count,
     IN UCHAR feature,
-    IN ULONG flags
+    IN ULONG wait_flags
     )
 {
     if(!(deviceExtension->HwFlags & UNIATA_AHCI)) {
         return AtaCommand48(deviceExtension, DeviceNumber, lChannel,
                             command,
                             (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
-                            count, feature, flags);
+                            count, feature, wait_flags);
     } else {
-        PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
-        PIDE_AHCI_CMD  AHCI_CMD = &(chan->AhciCtlBlock->cmd);
-
-        KdPrint3(("AtaCommand(ahci)\n"));
+        return UniataAhciSendPIOCommand(deviceExtension, lChannel, DeviceNumber,
+            (PSCSI_REQUEST_BLOCK)NULL,
+            NULL,
+            0,
+            command,
+            (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
+            count,
+            feature,
+            0 /* ahci flags */ ,
+            wait_flags,
+            1000 /* timeout 1 sec */
+            );
 
-        RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis));
-
-        if(!UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
-               &(AHCI_CMD->cfis[0]),
-                command,
-                (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
-                count,
-                feature,
-                ATA_IMMEDIATE
-                )) {
-            return 0xff;
-        }
-        if(UniataAhciSendCommand(deviceExtension, lChannel, DeviceNumber, 0, 3000) == 0xff) {
-            KdPrint2(("  timeout\n"));
-            return 0xff;
-        }
-        return IDE_STATUS_IDLE;
     }
 } // end AtaCommand()
 
@@ -1026,7 +1187,7 @@ AtaPioMode(PIDENTIFY_DATA2 ident)
         return 1;
     if (ident->PioCycleTimingMode == 0)
         return 0;
-    return -1;
+    return IOMODE_NOT_SPECIFIED;
 } // end AtaPioMode()
 
 LONG
@@ -1039,7 +1200,7 @@ AtaWmode(PIDENTIFY_DATA2 ident)
         return 1;
     if (ident->MultiWordDMASupport & 0x01)
         return 0;
-    return -1;
+    return IOMODE_NOT_SPECIFIED;
 } // end AtaWmode()
 
 LONG
@@ -1047,7 +1208,7 @@ NTAPI
 AtaUmode(PIDENTIFY_DATA2 ident)
 {
     if (!ident->UdmaModesValid)
-        return -1;
+        return IOMODE_NOT_SPECIFIED;
     if (ident->UltraDMASupport & 0x40)
         return 6;
     if (ident->UltraDMASupport & 0x20)
@@ -1062,9 +1223,27 @@ AtaUmode(PIDENTIFY_DATA2 ident)
         return 1;
     if (ident->UltraDMASupport & 0x01)
         return 0;
-    return -1;
+    return IOMODE_NOT_SPECIFIED;
 } // end AtaUmode()
 
+LONG
+NTAPI
+AtaSAmode(PIDENTIFY_DATA2 ident) {
+    if(!ident->SataCapabilities || 
+       ident->SataCapabilities == 0xffff) {
+        return IOMODE_NOT_SPECIFIED;
+    }
+    if(ident->SataCapabilities & ATA_SATA_GEN3) {
+        return ATA_SA600;
+    } else
+    if(ident->SataCapabilities & ATA_SATA_GEN2) {
+        return ATA_SA300;
+    } else
+    if(ident->SataCapabilities & ATA_SATA_GEN1) {
+        return ATA_SA150;
+    }
+    return IOMODE_NOT_SPECIFIED;
+} // end AtaSAmode()
 
 #ifndef UNIATA_CORE
 
@@ -1089,7 +1268,7 @@ AtapiTimerDpc(
         KdPrint2((PRINT_PREFIX "AtapiTimerDpc: no items\n"));
         return;
     }
-    chan = &deviceExtension->chan[lChannel];
+    chan = &(deviceExtension->chan[lChannel]);
 
     while(TRUE) {
 
@@ -1145,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
@@ -1178,13 +1357,13 @@ AtapiQueueTimerDpc(
     chan = prev_chan = NULL;
     while(i != CHAN_NOT_SPECIFIED) {
         prev_chan = chan;
-        chan = &deviceExtension->chan[i];
+        chan = &(deviceExtension->chan[i]);
         if(chan->DpcTime > time.QuadPart) {
             break;
         }
         i = chan->NextDpcChan;
     }
-    chan = &deviceExtension->chan[lChannel];
+    chan = &(deviceExtension->chan[lChannel]);
     if(!prev_chan) {
         deviceExtension->FirstDpcChan = lChannel;
     } else {
@@ -1210,6 +1389,7 @@ AtapiQueueTimerDpc(
 
 #endif //UNIATA_CORE
 
+#ifdef _DEBUG
 VOID
 NTAPI
 UniataDumpATARegs(
@@ -1230,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
@@ -1240,6 +1423,43 @@ UniataDumpATARegs(
     }
     return;
 } // end UniataDumpATARegs()
+#endif //_DEBUG
+
+VOID
+NTAPI
+UniataSnapAtaRegs(
+    IN PHW_CHANNEL chan,
+    IN ULONG DeviceNumber,
+ IN OUT PIDEREGS_EX regs
+    )
+{
+    if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
+        // AHCI
+        UniataAhciSnapAtaRegs(chan, DeviceNumber, regs);
+    } else {
+        // SATA/PATA, assume drive is selected
+        ULONG                j;
+        UCHAR                statusByteAlt;
+
+        if((regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) == 0) {
+            for(j=IDX_IO1_i_Error; j<=IDX_IO1_i_Status; j++) {
+                statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
+                ((PUCHAR)regs)[j-1] = statusByteAlt;
+            }
+            regs->bOpFlags = 0;
+        } else {
+            regs->bDriveHeadReg    = AtapiReadPort1(chan, IDX_IO1_i_DriveSelect);
+            for(j=IDX_IO1_i_Error; j<IDX_IO1_i_DriveSelect; j++) {
+                statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
+                ((PUCHAR)regs)[j-1] = statusByteAlt;
+                statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
+                ((PUCHAR)regs)[j+8-1] = statusByteAlt;
+            }
+            regs->bCommandReg      = AtapiReadPort1(chan, IDX_IO1_i_Status);
+        }
+    }
+    return;
+} // end UniataSnapAtaRegs()
 
 /*++
 
@@ -1269,16 +1489,20 @@ IssueIdentify(
     )
 {
     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
-    PHW_CHANNEL          chan = &deviceExtension->chan[lChannel];
+    PHW_CHANNEL          chan = &(deviceExtension->chan[lChannel]);
     ULONG                waitCount = 50000;
     ULONG                j;
     UCHAR                statusByte;
-    UCHAR                statusByte2;
+    //UCHAR                statusByte2;
     UCHAR                signatureLow,
                          signatureHigh;
     BOOLEAN              atapiDev = FALSE;
+    BOOLEAN              use_ahci = FALSE;
     PHW_LU_EXTENSION     LunExt = chan->lun[DeviceNumber];
 
+    use_ahci = UniataIsSATARangeAvailable(deviceExtension, lChannel) &&
+        (deviceExtension->HwFlags & UNIATA_AHCI);
+
     if(chan->ChannelCtrlFlags & CTRFLAGS_AHCI_PM) {
         if(chan->PmLunMap & (1 << DeviceNumber)) {
             // OK
@@ -1296,16 +1520,26 @@ IssueIdentify(
         return FALSE;
     }
 
-    if(deviceExtension->HwFlags & UNIATA_AHCI) {
+    if(use_ahci) {
         statusByte = WaitOnBusyLong(chan);
+#ifdef _DEBUG
+        if(!chan->AhciInternalAtaReq) {
+            KdPrint2((PRINT_PREFIX "!AhciInternalAtaReq\n"));
+        }
+#endif
     } else {
         SelectDrive(chan, DeviceNumber);
         AtapiStallExecution(10);
         statusByte = WaitOnBusyLong(chan);
         // Check that the status register makes sense.
-        GetBaseStatus(chan, statusByte2);
-
-        UniataDumpATARegs(chan);
+        GetBaseStatus(chan, statusByte);
+        /*
+        // unnecessary
+        if(!hasPCI) {
+            // original atapi.sys behavior for old ISA-only hardware
+            AtapiStallExecution(100);
+        }
+        */
     }
 
     if (Command == IDE_COMMAND_IDENTIFY) {
@@ -1341,13 +1575,17 @@ IssueIdentify(
                     // Wait for Busy to drop.
                     AtapiStallExecution(100);
                     GetStatus(chan, statusByte);
+                    if(statusByte == IDE_STATUS_WRONG) {
+                        KdPrint2((PRINT_PREFIX "IssueIdentify: IDE_STATUS_WRONG (dev %d)\n", DeviceNumber));
+                        return FALSE;
+                    }
 
                 } while ((statusByte & IDE_STATUS_BUSY) && waitCount--);
-                GetBaseStatus(chan, statusByte2);
+                GetBaseStatus(chan, statusByte);
 
                 SelectDrive(chan, DeviceNumber);
             } else {
-                GetBaseStatus(chan, statusByte2);
+                GetBaseStatus(chan, statusByte);
             }
             // Another check for signature, to deal with one model Atapi that doesn't assert signature after
             // a soft reset.
@@ -1370,6 +1608,9 @@ IssueIdentify(
         }
     } else {
         KdPrint2((PRINT_PREFIX "IssueIdentify: Checking for ATAPI. Status (%#x)\n", statusByte));
+        if(statusByte == IDE_STATUS_WRONG) {
+            return FALSE;
+        }
         //if(!(deviceExtension->HwFlags & UNIATA_SATA)) {
         if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
             statusByte = WaitForIdleLong(chan);
@@ -1379,6 +1620,26 @@ IssueIdentify(
     }
 
 //    if(deviceExtension->HwFlags & UNIATA_SATA) {
+    if(use_ahci) {
+        statusByte = UniataAhciSendPIOCommand(HwDeviceExtension, lChannel, DeviceNumber,
+            (PSCSI_REQUEST_BLOCK)NULL,
+            (PUCHAR)(&deviceExtension->FullIdentifyData),
+            DEV_BSIZE,
+            Command,
+            0, 0,
+            0,
+            0 /* ahci flags */ ,
+            ATA_WAIT_INTR,
+            1000 /* timeout 1 sec */
+            );
+        j = 9; // AHCI is rather different, skip loop at all
+    } else
+    if(LunExt->DeviceFlags & DFLAGS_MANUAL_CHS) {
+        j = 9; // don't send IDENTIFY, assume it is not supported
+        KdPrint2((PRINT_PREFIX "IssueIdentify: Manual CHS\n"));
+        RtlZeroMemory(&(deviceExtension->FullIdentifyData), sizeof(deviceExtension->FullIdentifyData));
+        RtlCopyMemory(&(deviceExtension->FullIdentifyData), &(LunExt->IdentifyData), sizeof(LunExt->IdentifyData));
+    } else
     if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
         j = 4; // skip old-style checks
     } else {
@@ -1386,9 +1647,16 @@ IssueIdentify(
     }
     for (; j < 4*2; j++) {
         // Send IDENTIFY command.
-        statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, Command, 0, 0, 0, (j >= 4) ? 0x200 : 0, 0, ATA_WAIT_INTR);
+
+        // Load CylinderHigh and CylinderLow with number bytes to transfer for old devices, use 0 for newer.
+        
+        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));
@@ -1425,7 +1693,7 @@ IssueIdentify(
                     break;
                 }
             }
-            // Device didn't respond correctly. It will be given one more chances.
+            // Device didn't respond correctly. It will be given one more chance.
             KdPrint2((PRINT_PREFIX "IssueIdentify: DRQ never asserted (%#x). Error reg (%#x)\n",
                         statusByte, AtapiReadPort1(chan, IDX_IO1_i_Error)));
             GetBaseStatus(chan, statusByte);
@@ -1446,65 +1714,71 @@ IssueIdentify(
         return FALSE;
     }
 
-    KdPrint2((PRINT_PREFIX "IssueIdentify: Status before read words %#x\n", statusByte));
-    // Suck out 256 words. After waiting for one model that asserts busy
-    // after receiving the Packet Identify command.
-    statusByte = WaitForDrq(chan);
-    statusByte = WaitOnBusyLong(chan);
-        KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
+    if(use_ahci) {
+        // everything should already be done by controller
+    } else
+    if(LunExt->DeviceFlags & DFLAGS_MANUAL_CHS) {
+        j = 9; // don't send IDENTIFY, assume it is not supported
+        KdPrint2((PRINT_PREFIX "IssueIdentify: Manual CHS (2)\n"));
+        statusByte = WaitForDrq(chan);
+        statusByte = WaitOnBusyLong(chan);
+            KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
+        GetBaseStatus(chan, statusByte);
+    } else {
 
-    if (!(statusByte & IDE_STATUS_DRQ)) {
-        KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (2) (%#x)\n", statusByte));
+        KdPrint2((PRINT_PREFIX "IssueIdentify: Status before read words %#x\n", statusByte));
+        // Suck out 256 words. After waiting for one model that asserts busy
+        // after receiving the Packet Identify command.
+        statusByte = WaitForDrq(chan);
+        statusByte = WaitOnBusyLong(chan);
+            KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
+
+        if (!(statusByte & IDE_STATUS_DRQ)) {
+            KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (2) (%#x)\n", statusByte));
+            GetBaseStatus(chan, statusByte);
+            return FALSE;
+        }
         GetBaseStatus(chan, statusByte);
-        return FALSE;
-    }
-    GetBaseStatus(chan, statusByte);
-    KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte));
+        KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte));
 
-    if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
+#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));
 
-        KdPrint2((PRINT_PREFIX "  use 16bit IO\n"));
-#if 0
-        USHORT w;
-        ULONG i;
-        // 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 the way you see below.
-        KdPrint2((PRINT_PREFIX 
-                   "  IO_%#x (%#x), %s:\n",
-                   IDX_IO1_i_Data,
-                   chan->RegTranslation[IDX_IO1_i_Data].Addr,
-                   chan->RegTranslation[IDX_IO1_i_Data].MemIo ? "Mem" : "IO"));
-        for(i=0; i<256; i++) {
-/*
-            KdPrint2((PRINT_PREFIX 
-                       "  IO_%#x (%#x):\n",
-                       IDX_IO1_i_Data,
-                       chan->RegTranslation[IDX_IO1_i_Data].Addr));
-*/
-            w = AtapiReadPort2(chan, IDX_IO1_i_Data);
-            KdPrint2((PRINT_PREFIX 
-                       "    %x\n", w));
-            AtapiStallExecution(1);
-            ((PUSHORT)&deviceExtension->FullIdentifyData)[i] = w;
         }
-#else
-        ReadBuffer(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256, PIO0_TIMING);
-#endif
-        // Work around for some IDE and one model Atapi that will present more than
-        // 256 bytes for the Identify data.
-        KdPrint2((PRINT_PREFIX "IssueIdentify: suck data port\n", statusByte));
-        statusByte = AtapiSuckPort2(chan);
-    } else {
-        KdPrint2((PRINT_PREFIX "  use 32bit IO\n"));
-        ReadBuffer2(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256/2, PIO0_TIMING);
-    }
+#endif //_DEBUG
 
-    KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
-    statusByte = WaitForDrq(chan);
-    KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
-    GetBaseStatus(chan, statusByte);
+        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
+            // spacifying manual delay in the way you see below.
+            ReadBuffer(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256, PIO0_TIMING);
+
+            // Work around for some IDE and one model Atapi that will present more than
+            // 256 bytes for the Identify data.
+            KdPrint2((PRINT_PREFIX "IssueIdentify: suck data port\n", statusByte));
+            statusByte = AtapiSuckPort2(chan);
+        } else {
+            KdPrint2((PRINT_PREFIX "  use 32bit IO\n"));
+            ReadBuffer2(chan, (PULONG)&deviceExtension->FullIdentifyData, 256/2, PIO0_TIMING);
+        }
 
+        KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
+        statusByte = WaitForDrq(chan);
+        KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
+        GetBaseStatus(chan, statusByte);
+    }
     KdPrint2((PRINT_PREFIX "IssueIdentify: Status after read words %#x\n", statusByte));
 
     if(NoSetup) {
@@ -1515,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));
@@ -1522,9 +1814,34 @@ IssueIdentify(
     KdPrint2((PRINT_PREFIX "SWDMA: %x\n", deviceExtension->FullIdentifyData.SingleWordDMAActive));
     KdPrint2((PRINT_PREFIX "MWDMA: %x\n", deviceExtension->FullIdentifyData.MultiWordDMAActive));
     if(deviceExtension->FullIdentifyData.UdmaModesValid) {
-        KdPrint2((PRINT_PREFIX "UDMA:  %x\n", deviceExtension->FullIdentifyData.UltraDMAActive));
+        KdPrint2((PRINT_PREFIX "UDMA:  %x/%x\n", deviceExtension->FullIdentifyData.UltraDMAActive, deviceExtension->FullIdentifyData.UltraDMASupport));
     }
     KdPrint2((PRINT_PREFIX "SATA:  %x\n", deviceExtension->FullIdentifyData.SataEnable));
+    KdPrint2((PRINT_PREFIX "SATA support: %x, CAPs %#x\n",
+        deviceExtension->FullIdentifyData.SataSupport,
+        deviceExtension->FullIdentifyData.SataCapabilities));
+
+    LunExt->LimitedTransferMode =
+    LunExt->OrigTransferMode =
+        (UCHAR)ata_cur_mode_from_ident(&(deviceExtension->FullIdentifyData), IDENT_MODE_MAX);
+    LunExt->TransferMode =
+        (UCHAR)ata_cur_mode_from_ident(&(deviceExtension->FullIdentifyData), IDENT_MODE_ACTIVE);
+
+    KdPrint2((PRINT_PREFIX "OrigTransferMode: %x, Active: %x\n", LunExt->OrigTransferMode, LunExt->TransferMode));
+    KdPrint2((PRINT_PREFIX "Accoustic %d, cur %d\n",
+        deviceExtension->FullIdentifyData.VendorAcoustic,
+        deviceExtension->FullIdentifyData.CurrentAcoustic
+        ));
+    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) {
@@ -1534,6 +1851,10 @@ IssueIdentify(
                     deviceExtension->FullIdentifyData.RemovableStatus));
         LunExt->DeviceFlags |= DFLAGS_REMOVABLE_DRIVE;
     }
+    if(use_ahci) {
+        // AHCI doesn't recommend using PIO and multiblock
+        LunExt->MaximumBlockXfer = 0;
+    } else
     if (deviceExtension->FullIdentifyData.MaximumBlockTransfer) {
         // Determine max. block transfer for this device.
         LunExt->MaximumBlockXfer =
@@ -1545,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,
@@ -1558,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 = 
@@ -1577,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
@@ -1595,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"));
@@ -1626,21 +1995,24 @@ IssueIdentify(
                              IDE_COMMAND_READ_NATIVE_SIZE48, 0, 0, 0, ATA_WAIT_READY);
 
                 if(!(statusByte & IDE_STATUS_ERROR)) {
-                    NativeNumOfSectors = (ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
-                                        ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow)  << 8) |
-                                        ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) ;
-
-                    AtapiWritePort1(chan, IDX_IO2_o_Control,
-                                           IDE_DC_USE_HOB );
-
-                    KdPrint2((PRINT_PREFIX "Read high order bytes\n"));
-                    NativeNumOfSectors |=
-                                        ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber)  << 24 );
-                    hNativeNumOfSectors= 
-                                         (ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) |
-                                        ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 8) ;
-                    ((PULONG)&NativeNumOfSectors)[1] = hNativeNumOfSectors;
-
+                    if(use_ahci) {
+                        NativeNumOfSectors = chan->AhciInternalAtaReq->ahci.in_lba;
+                    } else {
+                        NativeNumOfSectors = (ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
+                                            ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow)  << 8) |
+                                            ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) ;
+
+                        AtapiWritePort1(chan, IDX_IO2_o_Control,
+                                               IDE_DC_USE_HOB );
+
+                        KdPrint2((PRINT_PREFIX "Read high order bytes\n"));
+                        NativeNumOfSectors |=
+                                            (ULONG)((ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber)  << 24 );
+                        hNativeNumOfSectors= 
+                                             (ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) |
+                                            ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 8) ;
+                        ((PULONG)&NativeNumOfSectors)[1] = hNativeNumOfSectors;
+                    }
                     KdPrint2((PRINT_PREFIX "NativeNumOfSectors %#I64x\n", NativeNumOfSectors));
 
                     // Some drives report LBA48 capability while has capacity below 128Gb
@@ -1654,13 +2026,17 @@ IssueIdentify(
                                      IDE_COMMAND_READ_NATIVE_SIZE48, 0, 0, 0, ATA_WAIT_READY);
 
                         if(!(statusByte & IDE_STATUS_ERROR)) {
-                            NativeNumOfSectors = (ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
+                            if(use_ahci) {
+                                NativeNumOfSectors = chan->AhciInternalAtaReq->ahci.in_lba;
+                            } else {
+                                NativeNumOfSectors = (ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
                                                 ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber)  << 24) |
                                                 ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow)  << 8 ) |
                                                 ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow)  << 32) |
                                                 ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) |
                                                 ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 40) 
                                                 ;
+                            }
                         }
 
                         if((NativeNumOfSectors & 0xffffff) == ((NativeNumOfSectors >> 24) & 0xffffff)) {
@@ -1681,7 +2057,7 @@ IssueIdentify(
                             NumOfSectors = NativeNumOfSectors;
                         }
                     }
-                }
+                } // !error
             }
     
             if(NumOfSectors < 0x2100000 /*&& NumOfSectors > 31*1000*1000*/) {
@@ -1693,11 +2069,14 @@ IssueIdentify(
                              0, IDE_USE_LBA, 0, 0, 0, ATA_WAIT_READY);
 
                 if(!(statusByte & IDE_STATUS_ERROR)) {
-                    NativeNumOfSectors = (ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
-                                        ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) << 8) |
-                                        ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) |
-                                       (((ULONG)AtapiReadPort1(chan, IDX_IO1_i_DriveSelect) & 0xf) << 24);
-
+                    if(use_ahci) {
+                        NativeNumOfSectors = chan->AhciInternalAtaReq->ahci.in_lba;
+                    } else {
+                        NativeNumOfSectors = (ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
+                                            ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) << 8) |
+                                            ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) |
+                                           (((ULONG)AtapiReadPort1(chan, IDX_IO1_i_DriveSelect) & 0xf) << 24);
+                    }
                     KdPrint2((PRINT_PREFIX "NativeNumOfSectors %#I64x\n", NativeNumOfSectors));
 
                     if(NativeNumOfSectors > NumOfSectors) {
@@ -1714,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
@@ -1740,7 +2136,11 @@ IssueIdentify(
                 }
             }
         }
-        KdPrint2((PRINT_PREFIX "final LunExt->opt_GeomType=%x\n", LunExt->opt_GeomType));
+
+        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 =
@@ -1803,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,
@@ -1847,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"));
     }
@@ -1924,7 +2340,9 @@ UniataForgetDevice(
     PHW_LU_EXTENSION   LunExt
     )
 {
+    // keep only DFLAGS_HIDDEN flag
     LunExt->DeviceFlags &= DFLAGS_HIDDEN;
+    LunExt->AtapiReadyWaitDelay = 0;
 } // end UniataForgetDevice()
 
 
@@ -1932,6 +2350,7 @@ UniataForgetDevice(
 
 Routine Description:
     Reset IDE controller and/or Atapi device.
+    ->HwResetBus
 
 Arguments:
     HwDeviceExtension - HBA miniport driver's adapter data storage
@@ -1948,11 +2367,10 @@ AtapiResetController(
     IN ULONG PathId
     )
 {
-    KdPrint2((PRINT_PREFIX "AtapiResetController()\n"));
+    KdPrint2((PRINT_PREFIX "AtapiResetController(%x)\n", PathId));
     return AtapiResetController__(HwDeviceExtension, PathId, RESET_COMPLETE_ALL);
 } // end AtapiResetController()
 
-
 BOOLEAN
 NTAPI
 AtapiResetController__(
@@ -1980,9 +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, VM %x\n", deviceExtension->simplexOnly, g_opt_VirtualMachine));
 
     if(!deviceExtension->simplexOnly && (PathId != CHAN_NOT_SPECIFIED)) {
         // we shall reset both channels on SimplexOnly devices,
@@ -1996,22 +2415,38 @@ AtapiResetController__(
 
     for (; j < numberChannels; j++) {
 
-        KdPrint2((PRINT_PREFIX "AtapiResetController: Reset channel %d\n", j));
-        chan = &deviceExtension->chan[j];
-        KdPrint2((PRINT_PREFIX "  CompleteType %#x\n", CompleteType));
-        //MaxLuns = (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE) ? 1 : 2;
+        KdPrint2((PRINT_PREFIX "AtapiResetController: Reset lchannel %d[%d]\n", j, deviceExtension->Channel));
+        chan = &(deviceExtension->chan[j]);
         MaxLuns = chan->NumberLuns;
+        // 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);
 
-                KdPrint2((PRINT_PREFIX "AtapiResetController: pending SRB %#x\n", CurSrb));
+                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));
                     AtaReq->Srb = AtaReq->OriginalSrb;
+                    CurSrb->SrbExtension = NULL;
                     AtaReq->OriginalSrb = NULL;
                     // NOTE: internal SRB doesn't get to SRB queue !!!
                     CurSrb = AtaReq->Srb;
@@ -2024,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;
 
@@ -2034,6 +2469,7 @@ AtapiResetController__(
                     if (CurSrb->SenseInfoBuffer) {
 
                         PSENSE_DATA  senseBuffer = (PSENSE_DATA)CurSrb->SenseInfoBuffer;
+                        KdPrint2((PRINT_PREFIX "  senseBuffer %#x, chan %#x, ReqFlags %#x\n", senseBuffer, chan, AtaReq->Flags));
 
                         senseBuffer->ErrorCode = 0x70;
                         senseBuffer->Valid     = 1;
@@ -2051,10 +2487,47 @@ 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;
                     AtaReq->TransferLength = 0;
+                    KdPrint2((PRINT_PREFIX "chan %#x\n", chan));
 
                     ScsiPortNotification(RequestComplete,
                                          deviceExtension,
@@ -2063,7 +2536,7 @@ AtapiResetController__(
                     // Indicate ready for next request.
                     ScsiPortNotification(NextLuRequest,
                                          deviceExtension, 
-                                         PathId,
+                                         CurPathId,
                                          TargetId,
                                          Lun);
                 }
@@ -2073,30 +2546,42 @@ AtapiResetController__(
 #endif //UNIATA_CORE
         } // end if (!CompleteType != RESET_COMPLETE_NONE)
 
-        // Save control flags
-        ChannelCtrlFlags = chan->ChannelCtrlFlags;
         // Clear expecting interrupt flag.
-        chan->ExpectingInterrupt = FALSE;
+        UniataExpectChannelInterrupt(chan, FALSE);
         chan->RDP = FALSE;
-        chan->ChannelCtrlFlags = 0;
+        chan->ChannelCtrlFlags = ChannelCtrlFlags & CTRFLAGS_PERMANENT;
         InterlockedExchange(&(chan->CheckIntr),
                                       CHECK_INTR_IDLE);
         
+        for (i = 0; i < MaxLuns; i++) {
+            chan->lun[i]->PowerState = 0;
+        }
         // Reset controller
         if(ChipFlags & UNIATA_AHCI) {
             KdPrint2((PRINT_PREFIX "  AHCI path\n"));
-            UniataAhciReset(HwDeviceExtension, j);
+            if(UniataAhciChanImplemented(deviceExtension, j)) {
+#ifdef _DEBUG
+                UniataDumpAhciPortRegs(chan);
+#endif
+                AtapiDisableInterrupts(deviceExtension, j);
+                UniataAhciReset(HwDeviceExtension, j);
+            } else {
+                KdPrint2((PRINT_PREFIX "  skip not implemented\n"));
+                continue;
+            }
         } else {
-            KdPrint2((PRINT_PREFIX "  ATA path\n"));
+            KdPrint2((PRINT_PREFIX "  ATA path, chan %#x\n", chan));
             KdPrint2((PRINT_PREFIX "  disable intr (0)\n"));
             AtapiDisableInterrupts(deviceExtension, j);
             KdPrint2((PRINT_PREFIX "  done\n"));
             switch(VendorID) {
             case ATA_INTEL_ID: {
                 ULONG mask;
+                ULONG pshift;
                 ULONG timeout;
-                if(!(ChipFlags & UNIATA_SATA))
+                if(!(ChipFlags & UNIATA_SATA)) {
                     goto default_reset;
+                }
                 if(!UniataIsSATARangeAvailable(deviceExtension, j)) {
                     goto default_reset;
                 }
@@ -2117,7 +2602,7 @@ AtapiResetController__(
 #else
                 mask = 1 << chan->lun[0]->SATA_lun_map;
                 if (MaxLuns > 1) {
-                       mask |= (1 << chan->lun[1]->SATA_lun_map);
+                    mask |= (1 << chan->lun[1]->SATA_lun_map);
                 }
 #endif
                 ChangePciConfig2(0x92, a & ~mask);
@@ -2126,26 +2611,71 @@ AtapiResetController__(
                 timeout = 100;
 
                 /* Wait up to 1 sec for "connect well". */
-                if (ChipFlags & (I6CH | I6CH2))
-                    mask = mask << 8;
-                else
-                    mask = mask << 4;
-
+                if (ChipFlags & (I6CH | I6CH2)) {
+                    pshift = 8;
+                } else {
+                    pshift = 4;
+                }
                 while (timeout--) {
-                    AtapiStallExecution(10000);
                     GetPciConfig2(0x92, tmp16);
-                    if ((tmp16 & mask) == mask) {
-                        AtapiStallExecution(10000);
-                        break;
+                    if (((tmp16 >> pshift) & mask) == mask) {
+                        GetBaseStatus(chan, statusByte);
+                        if(statusByte != IDE_STATUS_WRONG) {
+                            break;
+                        }
                     }
+                    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;
@@ -2174,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
@@ -2187,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;
@@ -2207,11 +2745,14 @@ default_reset:
 
         // all these shall be performed inside AtapiHwInitialize__() ?
 #if 1
-        KdPrint2((PRINT_PREFIX "  process connected devices\n"));
+        KdPrint2((PRINT_PREFIX "  process connected devices 0 - %d\n", MaxLuns-1));
         // Do special processing for ATAPI and IDE disk devices.
         for (i = 0; i < MaxLuns; i++) {
 
             // Check if device present.
+            KdPrint2((PRINT_PREFIX "  Chan %#x\n", chan));
+            KdPrint2((PRINT_PREFIX "  Lun %#x\n", i));
+            KdPrint2((PRINT_PREFIX "  Lun ptr %#x\n", chan->lun[i]));
             if (!(chan->lun[i]->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
                 if(ChipFlags & UNIATA_AHCI) {
                     // everything is done in UniataAhciReset()
@@ -2235,7 +2776,7 @@ default_reset:
 
                     if(!IssueIdentify(HwDeviceExtension,
                                   i, j,
-                             (chan->lun[i]->DeviceFlags & DFLAGS_ATAPI_DEVICE) ?
+                             ATAPI_DEVICE(chan, i) ?
                                   IDE_COMMAND_ATAPI_IDENTIFY : IDE_COMMAND_IDENTIFY,
                                   FALSE)) {
                         KdPrint2((PRINT_PREFIX "  identify failed !\n"));
@@ -2254,14 +2795,14 @@ default_reset:
             AtapiStallExecution(10);
             statusByte = WaitOnBusyLong(chan);
             statusByte = UniataIsIdle(deviceExtension, statusByte);
-            if(statusByte == 0xff) {
+            if(statusByte == IDE_STATUS_WRONG) {
                 KdPrint2((PRINT_PREFIX 
                            "no drive, status %#x\n",
                            statusByte));
                 UniataForgetDevice(chan->lun[i]);
             } else
             // Check for ATAPI disk.
-            if (chan->lun[i]->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
+            if (ATAPI_DEVICE(chan, i)) {
                 // Issue soft reset and issue identify.
                 GetStatus(chan, statusByte);
                 KdPrint2((PRINT_PREFIX "AtapiResetController: Status before Atapi reset (%#x).\n",
@@ -2273,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,
@@ -2308,11 +2865,12 @@ 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
 
-        // Enable interrupts, note, the we can have here recursive disable
+        // Enable interrupts, note, we can have here recursive disable
         AtapiStallExecution(10);
         KdPrint2((PRINT_PREFIX "AtapiResetController: deviceExtension->chan[%d].DisableIntr %d -> 1\n",
             j,
@@ -2353,7 +2911,7 @@ MapError(
     ULONG lChannel = GET_CHANNEL(Srb);
     PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
 //    ULONG i;
-    UCHAR errorByte;
+    UCHAR errorByte = 0;
     UCHAR srbStatus = SRB_STATUS_SUCCESS;
     UCHAR scsiStatus;
     ULONG DeviceNumber = GET_CDEV(Srb);
@@ -2361,7 +2919,15 @@ MapError(
 
     // Read the error register.
 
-    errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
+    if(deviceExtension->HwFlags & UNIATA_AHCI) {
+        PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
+        if(AtaReq) {
+            errorByte = AtaReq->ahci.in_error;
+        } else {
+        }
+    } else {
+        errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
+    }
     KdPrint2((PRINT_PREFIX 
                "MapError: Error register is %#x\n",
                errorByte));
@@ -2680,7 +3246,7 @@ MapError(
             UCHAR statusByte;
 
             if (LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT &&
-                 !(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
+                 !(LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_MANUAL_CHS))) {
 
                 statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_SET_MULTIPLE, 0, 0, 0, 0, 0, ATA_WAIT_BASE_READY);
 
@@ -2718,6 +3284,7 @@ Routine Description:
 
 Arguments:
     HwDeviceExtension - HBA miniport driver's adapter data storage
+    ->HwInitialize
 
 Return Value:
     TRUE - if initialization successful.
@@ -2739,6 +3306,11 @@ AtapiHwInitialize(
     if(WinVer_WDM_Model) {
         AtapiResetController__(HwDeviceExtension, CHAN_NOT_SPECIFIED, RESET_COMPLETE_ALL);
     }
+    if(deviceExtension->MasterDev) {
+        KdPrint2((PRINT_PREFIX "  mark chan %d of master controller [%x] as inited\n",
+            deviceExtension->Channel, deviceExtension->DevIndex));
+        BMList[deviceExtension->DevIndex].ChanInitOk |= 0x01 << deviceExtension->Channel;
+    }
 
     /* do extra chipset specific setups */
     AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, CHAN_NOT_SPECIFIED);
@@ -2769,6 +3341,11 @@ AtapiHwInitialize__(
 //    ULONG tmp32;
     ULONG PreferedMode = 0xffffffff;
 
+    if((deviceExtension->HwFlags & UNIATA_AHCI) &&
+       !UniataAhciChanImplemented(deviceExtension, lChannel)) {
+        return;
+    }
+
     AtapiChipInit(deviceExtension, DEVNUM_NOT_SPECIFIED, lChannel);
     FindDevices(deviceExtension, 0, lChannel);
 
@@ -2785,7 +3362,7 @@ AtapiHwInitialize__(
         AtapiDisableInterrupts(deviceExtension, lChannel);
         AtapiStallExecution(1);
 
-        if (!(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
+        if (!(LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_MANUAL_CHS))) {
 
             KdPrint2((PRINT_PREFIX "AtapiHwInitialize: IDE branch\n"));
             // Enable media status notification
@@ -2809,7 +3386,7 @@ AtapiHwInitialize__(
 
                 statusByte = AtaCommand(deviceExtension, i, lChannel,
                                     IDE_COMMAND_SET_MULTIPLE, 0, 0, 0,
-                                    LunExt->MaximumBlockXfer, 0, ATA_WAIT_BASE_READY);
+                                    0, 0, ATA_WAIT_BASE_READY);
 
                 if (statusByte & IDE_STATUS_ERROR) {
                     // Read the error register.
@@ -2854,34 +3431,92 @@ 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
+                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 {
+                        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 ||*/
+                   LunExt->IdentifyData.FeaturesSupport.APM) {
+
+                    if(LunExt->opt_AdvPowerMode) {
+                        KdPrint2((PRINT_PREFIX "  Try Enable Adv. Power Mgmt\n"));
+                        // setup APM
+                        statusByte = AtaCommand(deviceExtension, i, lChannel,
+                                            IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+                                            LunExt->opt_AdvPowerMode, ATA_C_F_ENAB_APM, ATA_WAIT_BASE_READY);
+                        // Check for errors.
+                        if (statusByte & IDE_STATUS_ERROR) {
+                            KdPrint2((PRINT_PREFIX 
+                                        "AtapiHwInitialize: Enable APM on Device %d failed\n",
+                                        i));
+                        }
+                    } else {
+                        KdPrint2((PRINT_PREFIX "  Disable Adv. Power Mgmt\n"));
+                        statusByte = AtaCommand(deviceExtension, i, lChannel,
+                                            IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+                                            0, ATA_C_F_DIS_APM, ATA_WAIT_BASE_READY);
+                    }
+                }
+                if(LunExt->IdentifyData.FeaturesSupport.AutoAcoustic) {
+                    if(LunExt->opt_AcousticMode) {
+                        KdPrint2((PRINT_PREFIX "  Try Enable Acoustic Mgmt\n"));
+                        // setup acoustic mgmt
+                        statusByte = AtaCommand(deviceExtension, i, lChannel,
+                                            IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+                                            LunExt->opt_AcousticMode, ATA_C_F_ENAB_ACOUSTIC, ATA_WAIT_BASE_READY);
+                        // Check for errors.
+                        if (statusByte & IDE_STATUS_ERROR) {
+                            KdPrint2((PRINT_PREFIX 
+                                        "AtapiHwInitialize: Enable Acoustic Mgmt on Device %d failed\n",
+                                        i));
+                        }
+                    } else {
+                        KdPrint2((PRINT_PREFIX "  Disable Acoustic Mgmt\n"));
+                        statusByte = AtaCommand(deviceExtension, i, lChannel,
+                                            IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+                                            0, ATA_C_F_DIS_ACOUSTIC, ATA_WAIT_BASE_READY);
+                    }
+                }
+                if(LunExt->IdentifyData.FeaturesSupport.Standby) {
+                    KdPrint2((PRINT_PREFIX "  Try init standby timer: %d\n"));
+                    // setup standby timer
                     statusByte = AtaCommand(deviceExtension, i, lChannel,
-                                        IDE_COMMAND_SET_FEATURES, 0, 0, 0,
-                                        0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY);
+                                        IDE_COMMAND_IDLE, 0, 0, 0,
+                                        LunExt->opt_StandbyTimer, 0, ATA_WAIT_BASE_READY);
                     // Check for errors.
                     if (statusByte & IDE_STATUS_ERROR) {
                         KdPrint2((PRINT_PREFIX 
-                                    "AtapiHwInitialize: Enable write cacheing on Device %d failed\n",
+                                    "AtapiHwInitialize: standby timer on Device %d failed\n",
                                     i));
-                        LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
-                    } else {
-                        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_ENAB_WCACHE, ATA_WAIT_BASE_READY);
-                    LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
                 }
             }
 
         } else if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED)){
 
             ULONG j;
-            BOOLEAN isSanyo = FALSE;
+            //BOOLEAN isSanyo = FALSE;
             CCHAR vendorId[26];
 
             KdPrint2((PRINT_PREFIX "AtapiHwInitialize: ATAPI/Changer branch\n"));
@@ -2902,13 +3537,13 @@ AtapiHwInitialize__(
                     // acting like 1) a multi-lun device and 2) building the 'special' TUR's.
                     LunExt->DeviceFlags |= (DFLAGS_CHANGER_INITED | DFLAGS_SANYO_ATAPI_CHANGER);
                     LunExt->DiscsPresent = 3;
-                    isSanyo = TRUE;
+                    //isSanyo = TRUE;
                 }
             }
         }
 
         PreferedMode = LunExt->opt_MaxTransferMode;
-        if(PreferedMode == 0xffffffff) {
+        if((PreferedMode == 0xffffffff) || (PreferedMode > chan->MaxTransferMode)) {
             KdPrint2((PRINT_PREFIX "MaxTransferMode (overriden): %#x\n", chan->MaxTransferMode));
             PreferedMode = chan->MaxTransferMode;
         }
@@ -2919,14 +3554,12 @@ AtapiHwInitialize__(
         }
 
         KdPrint2((PRINT_PREFIX "  try mode %#x\n", PreferedMode));
-        LunExt->OrigTransferMode =
         LunExt->LimitedTransferMode =
         LunExt->TransferMode =
             (CHAR)PreferedMode;
 
         AtapiDmaInit__(deviceExtension, LunExt);
 
-        LunExt->OrigTransferMode =
         LunExt->LimitedTransferMode =
             LunExt->TransferMode;
         KdPrint2((PRINT_PREFIX "Using %#x mode\n", LunExt->TransferMode));
@@ -2951,9 +3584,12 @@ AtapiHwInitialize__(
             // 10000 * 100us = 1000,000us = 1000ms = 1s
             waitCount = 10000;
             GetStatus(chan, statusByte);
+            if(statusByte == IDE_STATUS_WRONG) {
+                waitCount = 0;
+            }
             while ((statusByte & IDE_STATUS_BUSY) && waitCount) {
 
-                KdPrint2((PRINT_PREFIX "Wait for ATAPI (status %x\n)", statusByte));
+                KdPrint2((PRINT_PREFIX "Wait for ATAPI (status %x)\n", statusByte));
                 // Wait for Busy to drop.
                 AtapiStallExecution(100);
                 GetStatus(chan, statusByte);
@@ -2961,10 +3597,12 @@ AtapiHwInitialize__(
             }
 
             // 5000 * 100us = 500,000us = 500ms = 0.5s
-            waitCount = 5000;
-            do {
-                AtapiStallExecution(100);
-            } while (waitCount--);
+            if(statusByte != IDE_STATUS_WRONG) {
+                waitCount = 5000;
+                do {
+                    AtapiStallExecution(100);
+                } while (waitCount--);
+            }
         }
         GetBaseStatus(chan, statusByte);
         AtapiEnableInterrupts(deviceExtension, lChannel);
@@ -2973,7 +3611,7 @@ AtapiHwInitialize__(
 
     return;
 
-} // end AtapiHwInitialize()
+} // end AtapiHwInitialize__()
 
 
 #ifndef UNIATA_CORE
@@ -3215,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]));
     }
@@ -3293,9 +3931,13 @@ ReturnCallback:
 
     // Check other channel
     // In simplex mode no interrupts must appear on other channels
-    for(_c=0; _c<deviceExtension->NumberChannels-1; _c++) {
+    for(_c=0; _c<deviceExtension->NumberChannels; _c++) {
         c = (_c+deviceExtension->FirstChannelToCheck) % deviceExtension->NumberChannels;
 
+        if(c == lChannel) {
+            continue;
+        }
+
         chan = &(deviceExtension->chan[c]);
 
         if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(chan->CheckIntr),
@@ -3321,7 +3963,7 @@ AtapiCallBack_X(
     )
 {
     AtapiCallBack__(HwDeviceExtension, (UCHAR)((PHW_DEVICE_EXTENSION)HwDeviceExtension)->ActiveDpcChan);
-}
+} // end AtapiCallBack_X()
 
 #endif //UNIATA_CORE
 
@@ -3352,41 +3994,69 @@ AtapiInterrupt(
     ULONG c_state;
     ULONG i_res = 0;
     ULONG pass;
-    BOOLEAN checked[AHCI_MAX_PORT];
+    //BOOLEAN checked[AHCI_MAX_PORT];
     ULONG hIS;
+    ULONG checked;
 
-    KdPrint2((PRINT_PREFIX "Intr: VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
+    KdPrint2((PRINT_PREFIX "Intr: DeviceID+VendorID/Rev %#x/%#x (ex %d)\n",
+        deviceExtension->DevID, deviceExtension->RevID, deviceExtension->ExpectingInterrupt ));
 
     if(deviceExtension->HwFlags & UNIATA_AHCI) {
+        // AHCI may generate state change notification, never skip this check
         hIS = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_IS);
-        KdPrint2((PRINT_PREFIX "AtapiInterrupt2: AHCI: hIS=%x cntrlr %#x chan %#x\n",hIS, deviceExtension->DevIndex, deviceExtension->Channel));
+        KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): AHCI: hIS=%x cntrlr %#x chan %#x\n",hIS, deviceExtension->DevIndex, deviceExtension->Channel));
         if(!hIS) {
             return FALSE;
         }
+        // assume all non-interrupted ports to be already checked
+        checked = ~hIS;
+        // assume all not implemented ports to be already checked
+        checked |= ~deviceExtension->AHCI_PI;
+    } else {
+        checked = 0; // assume all ports are not checked
     }
 
-    for(_c=0; _c<deviceExtension->NumberChannels; _c++) {
-        checked[_c] = FALSE;
+    if(!deviceExtension->ExpectingInterrupt) {
+        // if we do not expect interrupt, exit now,
+        // but keep in mind that it can be unexpected one
+        // Note: this is just a hint, not exact counter
+        KdPrint2((PRINT_PREFIX "unexpected, 1st chance\n"));
+        //deviceExtension->ExpectingInterrupt++;
+        //return FALSE;
     }
+    // clear this flag now, it can be set again in sub-calls
+    deviceExtension->ExpectingInterrupt=0;
+
+
+//    for(_c=0; _c<deviceExtension->NumberChannels; _c++) {
+//        checked[_c] = (UCHAR)((hIS >> _c) & 0x01);
+//    }
 
 //    fc = 
     for(pass=0; pass<2; pass++) {
+        //KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): pass %d\n", pass));
+        if(status && pass) {
+            // we catched some expected interrupts now.
+            // do not touch unexpected until next ISR call
+            break;
+        }
         for(_c=0; _c<deviceExtension->NumberChannels; _c++) {
 
             c = (_c+deviceExtension->FirstChannelToCheck) % deviceExtension->NumberChannels;
 
-            if(checked[c])
+            if((checked>>c) & 0x01)
                 continue;
 
             // check non-empty and expecting interrupt channels first
             if(!pass && !deviceExtension->chan[c].ExpectingInterrupt)
                 continue;
 
-            checked[c] = TRUE;
+            checked |= (ULONG)1 << c;
 
             KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): cntrlr %#x chan %#x\n",deviceExtension->DevIndex, c));
 
             if(CrNtInterlockedExchangeAdd(&(deviceExtension->chan[c].DisableIntr), 0)) {
+                // we get here on idle channels or when ISR is posted to DPC
                 KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): disabled INTR on ch %d\n", c));
                 continue;
             }
@@ -3425,7 +4095,9 @@ AtapiInterrupt(
                 if(i_res == INTERRUPT_REASON_UNEXPECTED) {
                     KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): Catch unexpected\n"));
                     InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE);
-                    return TRUE;
+                    //return TRUE;
+                    status = TRUE;
+                    continue;
                 }
                 // disable interrupts on other channel of legacy mode
                 // ISA-bridged onboard controller
@@ -3476,6 +4148,9 @@ AtapiInterrupt2(
     IN PVOID Isr2HwDeviceExtension
     )
 {
+    // This ISR is intended to catch interrupts when we are already in other ISR instance
+    // for the same device. This may happen when we have multiple channels,
+    // especially on SMP machines
 
     PISR2_DEVICE_EXTENSION Isr2DeviceExtension = (PISR2_DEVICE_EXTENSION)Isr2HwDeviceExtension;
     PHW_DEVICE_EXTENSION deviceExtension = Isr2DeviceExtension->HwDeviceExtension;
@@ -3484,6 +4159,7 @@ AtapiInterrupt2(
     ULONG c_count = 0;
     ULONG i_res;
     ULONG hIS;
+    ULONG checked;
 
     // we should never get here for ISA/MCA
     if(!BMList[deviceExtension->DevIndex].Isr2Enable) {
@@ -3492,16 +4168,35 @@ AtapiInterrupt2(
     }
 
     if(deviceExtension->HwFlags & UNIATA_AHCI) {
+        // AHCI may generate state change notification, never skip this check
         hIS = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_IS);
         KdPrint2((PRINT_PREFIX "AtapiInterrupt2: AHCI: hIS=%x cntrlr %#x chan %#x\n",hIS, deviceExtension->DevIndex, deviceExtension->Channel));
         if(!hIS) {
             return FALSE;
         }
+        // assume all non-interrupted ports to be already checked
+        checked = ~hIS; 
+        // assume all not implemented ports to be already checked
+        checked |= ~deviceExtension->AHCI_PI;
+
+    } else {
+        checked = 0; // assume all ports are not checked
+    }
+    if(!deviceExtension->ExpectingInterrupt) {
+        KdPrint2((PRINT_PREFIX "AtapiInterrupt2: !deviceExtension->ExpectingInterrupt\n"));
+        deviceExtension->ExpectingInterrupt++;
+        return FALSE;
     }
+    //deviceExtension->ExpectingInterrupt = 0;
 
     for(c=0; c<deviceExtension->NumberChannels; c++) {
         KdPrint2((PRINT_PREFIX "AtapiInterrupt2: cntrlr %#x chan %#x\n",deviceExtension->DevIndex, c));
 
+        if((checked>>c) & 0x01)
+            continue;
+
+        checked |= (ULONG)1 << c;
+
         if(CrNtInterlockedExchangeAdd(&(deviceExtension->chan[c].DisableIntr), 0)) {
             KdPrint2((PRINT_PREFIX "AtapiInterrupt2: disabled INTR\n"));
             continue;
@@ -3660,23 +4355,53 @@ AtapiEnableInterrupts(
 {
     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
     PHW_CHANNEL chan;
+    //UCHAR statusByte;
+    
     if(c >= deviceExtension->NumberChannels) {
         KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: WRONG CHANNEL\n",c));
         return;
     }
+    if((deviceExtension->HwFlags & UNIATA_AHCI) &&
+       !UniataAhciChanImplemented(deviceExtension, c)) {
+        KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: not imp. CHANNEL\n",c));
+        return;
+    }
+
     chan = &(deviceExtension->chan[c]);
     KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: %d\n",c, chan->DisableIntr));
     if(!InterlockedDecrement(&chan->DisableIntr)) {
         if(deviceExtension->HwFlags & UNIATA_AHCI) {
-            UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0);
+            UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE,
+                (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |
+                 ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_INF | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF |
+                 ((/*ch->pm_level == */0) ? ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC : 0) |
+                 ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | /* DEBUG */ 
+                 ATA_AHCI_P_IX_DI |
+                 ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB |
+                 ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)
+                );
         } else {
+            //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);
+            //    AtapiWritePort1(chan, IDX_IO2_o_Control,
+            //                           IDE_DC_A_4BIT );
+            //    SelectDrive(chan, chan->cur_cdev);
+            //}
         }
         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()
@@ -3699,16 +4424,17 @@ AtapiDisableInterrupts(
     // mark channel as busy
     if(InterlockedIncrement(&chan->DisableIntr)) {
         if(deviceExtension->HwFlags & UNIATA_AHCI) {
-            UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE,
-                (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |
-                 ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF |
-                 ((/*ch->pm_level == */0) ? ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC : 0) |
-                 ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB |
-                 ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)
-                );
+            UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0);
         } else {
+            //SelectDrive(chan, 0);
             AtapiWritePort1(chan, IDX_IO2_o_Control,
                                    IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ );
+            //if(chan->NumberLuns) {
+            //    SelectDrive(chan, 1);
+            //    AtapiWritePort1(chan, IDX_IO2_o_Control,
+            //                           IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ );
+            //    SelectDrive(chan, chan->cur_cdev);
+            //}
         }
         chan->ChannelCtrlFlags |= CTRFLAGS_INTR_DISABLED;
     }
@@ -3716,6 +4442,21 @@ AtapiDisableInterrupts(
     return;
 } // end AtapiDisableInterrupts()
 
+VOID
+UniataExpectChannelInterrupt(
+    IN struct _HW_CHANNEL* chan,
+    IN BOOLEAN Expecting
+    )
+{
+    chan->ExpectingInterrupt = Expecting;
+    if(Expecting) {
+        chan->DeviceExtension->ExpectingInterrupt++;
+    } else
+    if(chan->DeviceExtension->ExpectingInterrupt) {
+        chan->DeviceExtension->ExpectingInterrupt--;
+    }
+    return;
+} // end UniataExpectChannelInterrupt()
 
 /*
     Check hardware for interrupt state
@@ -3739,7 +4480,7 @@ AtapiCheckInterrupt__(
     UCHAR dma_status = 0;
     UCHAR reg8 = 0;
     ULONG reg32 = 0;
-    UCHAR statusByte;
+    UCHAR statusByte = 0;
     ULONG slotNumber = deviceExtension->slotNumber;
     ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
     ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK;
@@ -3747,18 +4488,50 @@ AtapiCheckInterrupt__(
     UCHAR lChannel;
     BOOLEAN DmaTransfer = FALSE;
     BOOLEAN OurInterrupt = FALSE;
+    BOOLEAN StatusValid = FALSE;
 //    ULONG k;
     UCHAR interruptReason;
     BOOLEAN EarlyIntr = FALSE;
+    BOOLEAN SingleBlockIntr = FALSE;
 
     KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__:\n"));
 
     lChannel = c;
     Channel = (UCHAR)(deviceExtension->Channel + lChannel);
+    LunExt = chan->lun[chan->cur_cdev];
+
+    //KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__ chan %#x:\n", chan));
+    //KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__ (%d/%d):\n", Channel, chan->cur_cdev));
 
     if((ChipFlags & UNIATA_AHCI) &&
         UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
-        OurInterrupt = UniataAhciStatus(HwDeviceExtension, lChannel, -1);
+
+        if(!UniataAhciChanImplemented(deviceExtension, lChannel)) {
+            return OurInterrupt;
+        }
+
+        OurInterrupt = UniataAhciStatus(HwDeviceExtension, lChannel, DEVNUM_NOT_SPECIFIED);
+        if((OurInterrupt == INTERRUPT_REASON_UNEXPECTED) &&
+           (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
+            UniataAhciWaitCommandReady(chan, 2 /* ms */ );
+            statusByte = (UCHAR)UniataAhciWaitReady(chan, 0 /* immediate */);
+            if(!(statusByte & (IDE_STATUS_BUSY)) ) {
+                KdPrint2((PRINT_PREFIX "ATAPI special case READY\n"));
+                //deviceExtension->ExpectingInterrupt++; // will be updated in ISR on ReturnEnableInterrupts
+                OurInterrupt = INTERRUPT_REASON_OUR;
+            } else
+            if((statusByte & (IDE_STATUS_BUSY | IDE_STATUS_DRDY)) == (IDE_STATUS_BUSY | IDE_STATUS_DRDY) ) {
+                KdPrint2((PRINT_PREFIX "ATAPI special case pre ERR-READY\n"));
+                OurInterrupt = INTERRUPT_REASON_OUR;
+            } else
+            if(statusByte & IDE_STATUS_ERROR) {
+                KdPrint2((PRINT_PREFIX "ATAPI special case ERR-READY\n"));
+                OurInterrupt = INTERRUPT_REASON_OUR;
+            } else {
+                KdPrint2((PRINT_PREFIX "ATAPI special case ? %x\n", statusByte));
+                OurInterrupt = INTERRUPT_REASON_OUR;
+            }
+        }
         return OurInterrupt;
     }
 
@@ -3809,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) {
@@ -3845,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)) ) {
@@ -3982,10 +4773,24 @@ check_unknown:
             } else {
                 KdPrint2((PRINT_PREFIX "  getting status...\n"));
                 GetStatus(chan, statusByte);
+                StatusValid = 1;
                 KdPrint2((PRINT_PREFIX "  status %#x\n", statusByte));
                 if(statusByte & IDE_STATUS_ERROR) {
                     KdPrint2((PRINT_PREFIX "  IDE_STATUS_ERROR -> our\n", statusByte));
                     OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
+                } else
+                if ((statusByte & IDE_STATUS_DSC) &&
+                    (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) &&
+                    (dma_status == BM_STATUS_ACTIVE)) {
+                    KdPrint2((PRINT_PREFIX "  special case DMA + ATAPI + IDE_STATUS_DSC -> our\n", statusByte));
+                    // some devices interrupts on each block transfer even in DMA mode
+                    if(LunExt->TransferMode >= ATA_SDMA && LunExt->TransferMode <= ATA_WDMA2) {
+                        KdPrint2((PRINT_PREFIX "  wait for completion\n"));
+                        ///* clear interrupt and get status */
+                        //GetBaseStatus(chan, statusByte);
+                        //return INTERRUPT_REASON_IGNORE;
+                        SingleBlockIntr = TRUE;
+                    }
                 } else {
                     return INTERRUPT_REASON_IGNORE;
                 }
@@ -4001,21 +4806,22 @@ check_unknown:
         }
     }
 skip_dma_stat_check:
-    if(!(ChipFlags & UNIATA_SATA)) {
+    if(!(ChipFlags & UNIATA_SATA) && chan->ExpectingInterrupt) {
         AtapiStallExecution(1);
     }
 
-    LunExt = chan->lun[chan->cur_cdev];
     /* if drive is busy it didn't interrupt */
     /* the exception is DCS + BSY state of ATAPI devices */
-    KdPrint2((PRINT_PREFIX "  getting status...\n"));
-    GetStatus(chan, statusByte);
+    if(!StatusValid) {
+        KdPrint2((PRINT_PREFIX "  getting status...\n"));
+        GetStatus(chan, statusByte);
+    }
     if(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
         KdPrint3((PRINT_PREFIX "  ATAPI status %#x\n", statusByte));
     } else {
         KdPrint2((PRINT_PREFIX "  IDE status %#x\n", statusByte));
     }
-    if (statusByte == 0xff) {
+    if (statusByte == IDE_STATUS_WRONG) {
         // interrupt from empty controller ?
     } else 
     if (statusByte & IDE_STATUS_BUSY) {
@@ -4030,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;
         }
@@ -4045,6 +4852,9 @@ skip_dma_stat_check:
             KdPrint3((PRINT_PREFIX "  our interrupt with BSY set, try wait in ISR or post to DPC\n"));
             /* clear interrupt and get status */
             GetBaseStatus(chan, statusByte);
+            if(!(dma_status & BM_STATUS_ACTIVE)) {
+                AtapiDmaDone(deviceExtension, DEVNUM_NOT_SPECIFIED ,lChannel, NULL);
+            }
             KdPrint3((PRINT_PREFIX "  base status %#x (+BM_STATUS_INTR)\n", statusByte));
             return INTERRUPT_REASON_OUR;
         }
@@ -4068,7 +4878,7 @@ skip_dma_stat_check:
     /* clear interrupt and get status */
     GetBaseStatus(chan, statusByte);
     KdPrint2((PRINT_PREFIX "  base status %#x\n", statusByte));
-    if (statusByte == 0xff) {
+    if (statusByte == IDE_STATUS_WRONG) {
         // interrupt from empty controller ?
     } else 
     if(!(statusByte & (IDE_STATUS_DRQ | IDE_STATUS_DRDY))) {
@@ -4078,7 +4888,7 @@ skip_dma_stat_check:
 
 #ifndef UNIATA_PIO_ONLY
     if(DmaTransfer) {
-        if(!EarlyIntr || g_WaitBusyInISR) {
+        if(!SingleBlockIntr && (!EarlyIntr || g_WaitBusyInISR)) {
             dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/);
         } else {
             PSCSI_REQUEST_BLOCK srb = UniataGetCurRequest(chan);
@@ -4086,9 +4896,13 @@ skip_dma_stat_check:
 
             //ASSERT(AtaReq);
 
-            KdPrint2((PRINT_PREFIX "  set REQ_STATE_EARLY_INTR.\n"));
+            if(SingleBlockIntr) {
+                KdPrint2((PRINT_PREFIX "  set REQ_STATE_ATAPI_EXPECTING_DATA_INTR2.\n"));
+            } else {
+                KdPrint2((PRINT_PREFIX "  set REQ_STATE_EARLY_INTR.\n"));
+            }
             if(AtaReq) {
-                AtaReq->ReqState = REQ_STATE_EARLY_INTR;
+                AtaReq->ReqState = SingleBlockIntr ? REQ_STATE_ATAPI_EXPECTING_DATA_INTR2 : REQ_STATE_EARLY_INTR;
             }
         }
     }
@@ -4104,7 +4918,7 @@ skip_dma_stat_check:
             KdPrint2((PRINT_PREFIX "  OurInterrupt = %d\n", OurInterrupt));
             return OurInterrupt;
         }
-        interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & 0x3);
+        interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
         KdPrint3((PRINT_PREFIX "AtapiCheckInterrupt__: ATAPI int reason %x\n", interruptReason));
         return OurInterrupt;
     }
@@ -4138,12 +4952,15 @@ AtapiInterrupt__(
 
     BOOLEAN atapiDev = FALSE;
 
+#ifdef _DEBUG
     UCHAR Channel;
+#endif //_DEBUG
     UCHAR lChannel;
     UCHAR DeviceNumber;
     BOOLEAN DmaTransfer = FALSE;
     UCHAR error = 0;
     ULONG TimerValue = 1000;
+    ULONG TotalTimerValue = 0;
 #ifdef UNIATA_USE_XXableInterrupts
     BOOLEAN InDpc = (KeGetCurrentIrql() == DISPATCH_LEVEL);
 #else
@@ -4153,6 +4970,7 @@ AtapiInterrupt__(
 //    BOOLEAN RestoreUseDpc = FALSE;
     BOOLEAN DataOverrun = FALSE;
     BOOLEAN NoStartIo = TRUE;
+    BOOLEAN NoRetry = FALSE;
 
     KdPrint2((PRINT_PREFIX "AtapiInterrupt:\n"));
     if(InDpc) {
@@ -4168,12 +4986,16 @@ AtapiInterrupt__(
     PHW_LU_EXTENSION LunExt;
 
     lChannel = c;
+
+#ifdef _DEBUG
     Channel = (UCHAR)(deviceExtension->Channel + lChannel);
 
     KdPrint2((PRINT_PREFIX "  cntrlr %#x:%d, irql %#x, c %d\n", deviceExtension->DevIndex, Channel, KeGetCurrentIrql(), c));
+#endif //_DEBUG
 
     if((chan->ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) ||
-       (AtaReq && (AtaReq->Flags & REQ_FLAG_DMA_OPERATION)) ) {
+       (AtaReq && (AtaReq->Flags & REQ_FLAG_DMA_OPERATION)) ||
+       (deviceExtension->HwFlags & UNIATA_AHCI)) {
         DmaTransfer = TRUE;
         KdPrint2((PRINT_PREFIX "  DmaTransfer = TRUE\n"));
     }
@@ -4231,6 +5053,7 @@ AtapiInterrupt__(
     case REQ_STATE_ATAPI_EXPECTING_CMD_INTR:
         KdPrint3((PRINT_PREFIX "  EXPECTING_CMD_INTR\n"));
     case REQ_STATE_ATAPI_EXPECTING_DATA_INTR:
+    case REQ_STATE_ATAPI_EXPECTING_DATA_INTR2:
     case REQ_STATE_DPC_WAIT_BUSY0:
     case REQ_STATE_DPC_WAIT_BUSY1:
         KdPrint2((PRINT_PREFIX "  continue service interrupt\n"));
@@ -4240,7 +5063,7 @@ AtapiInterrupt__(
         return TRUE;
     }
 
-    if(!DmaTransfer && !atapiDev) {
+    if((!DmaTransfer && !atapiDev) || deviceExtension->DriverMustPoll) {
         KdPrint2((PRINT_PREFIX "  service PIO HDD\n"));
         UseDpc = FALSE;
     }
@@ -4282,6 +5105,7 @@ PostToDpc:
     // disable interrupts for this channel,
     // but avoid recursion and double-disable
     if(OldReqState != REQ_STATE_DPC_WAIT_BUSY1) {
+        UniataExpectChannelInterrupt(chan, FALSE);
         AtapiDisableInterrupts(deviceExtension, lChannel);
     }
     // go to ISR DPC
@@ -4305,6 +5129,13 @@ PostToDpc:
 CallTimerDpc:
     AtaReq->ReqState = REQ_STATE_PROCESSING_INTR;
 CallTimerDpc2:
+    if(!InDpc && OldReqState != REQ_STATE_DPC_WAIT_BUSY1) {
+        // we must block interrupts from this channel
+        // If device generate new interrupt before we get to DPC,
+        // ISR will assume, that it is NOT our interrupt
+        AtapiDisableInterrupts(deviceExtension, lChannel);
+        // We should not clean ExpectingInterrupt flag on channel, since it is used in DPC
+    }
     // Will raise IRQL to DIRQL
     AtapiQueueTimerDpc(HwDeviceExtension, c,
                          AtapiCallBack_X,
@@ -4345,11 +5176,52 @@ ServiceInterrupt:
         AtapiStallExecution(10);
     }
 */
-    /* clear interrupt and get status */
 
+    /* clear interrupt and get status */
     if(deviceExtension->HwFlags & UNIATA_AHCI) {
         UniataAhciEndTransaction(HwDeviceExtension, lChannel, DeviceNumber, srb);
-        statusByte = (UCHAR)(AtaReq->ahci.in_status & 0xff);
+        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), 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) {
+
+                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
+                UniataDumpAhciPortRegs(chan);
+#endif
+                if(!UniataAhciAbortOperation(chan)) {
+                    KdPrint2((PRINT_PREFIX "need UniataAhciReset\n"));
+                }
+#ifdef _DEBUG
+                UniataDumpAhciPortRegs(chan);
+#endif
+                UniataAhciWaitCommandReady(chan, 10);
+            }
+        }
+
     } else {
         GetBaseStatus(chan, statusByte);
     }
@@ -4364,11 +5236,11 @@ ServiceInterrupt:
         InDpc = TRUE;
     }
                                                                        
-    if(deviceExtension->HwFlags & UNIATA_AHCI) {
-        KdPrint3((PRINT_PREFIX "  AHCI branch\n"));
-    } else
     if (!atapiDev) {
         // IDE
+        if(deviceExtension->HwFlags & UNIATA_AHCI) {
+            KdPrint3((PRINT_PREFIX "  AHCI branch (IDE)\n"));
+        } else
         if (statusByte & IDE_STATUS_BUSY) {
             if (deviceExtension->DriverMustPoll) {
                 // Crashdump is polling and we got caught with busy asserted.
@@ -4416,25 +5288,49 @@ try_dpc_wait:
         // ATAPI
         if(!LunExt->IdentifyData.MajorRevision &&
             InDpc &&
-            !atapiDev &&
+            /*!atapiDev &&*/
             !(deviceExtension->HwFlags & UNIATA_SATA)
             ) {
-            KdPrint2((PRINT_PREFIX "  additional delay 10us for old devices (2)\n"));
-            AtapiStallExecution(10);
+            //KdPrint2((PRINT_PREFIX "  additional delay 10us for old devices (2)\n"));
+            //AtapiStallExecution(10);
+        }
+        if(deviceExtension->HwFlags & UNIATA_AHCI) {
+            KdPrint3((PRINT_PREFIX "  AHCI branch (ATAPI)\n"));
+        } else {
+            interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
+            KdPrint3((PRINT_PREFIX "AtapiInterrupt: iReason %x\n", interruptReason));
         }
+
         if (statusByte & IDE_STATUS_BUSY) {
         //if(chan->ChannelCtrlFlags & CTRFLAGS_DSC_BSY) {}
-            KdPrint3((PRINT_PREFIX "  BUSY on ATAPI device, waiting\n"));
+/*
+#ifndef UNIATA_CORE
+            // This is just workaround
+            // We should DISABLE interrupts before entering WAIT state
+            UniataExpectChannelInterrupt(chan, TRUE);
+#endif //UNIATA_CORE
+*/
+            KdPrint3((PRINT_PREFIX "  BUSY on ATAPI device, waiting %d us\n", LunExt->AtapiReadyWaitDelay));
+#ifndef UNIATA_CORE
+            if(LunExt->AtapiReadyWaitDelay && (LunExt->AtapiReadyWaitDelay > g_opt_MaxIsrWait) && !InDpc && UseDpc) {
+                TimerValue = LunExt->AtapiReadyWaitDelay;
+                KdPrint2((PRINT_PREFIX "  too long wait: ISR -> DPC (0)\n"));
+                AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY0;
+                goto CallTimerDpc2;
+            }
+#endif //UNIATA_CORE
+            TimerValue = 10;
             for(k=20; k; k--) {
-                GetStatus(chan, statusByte);
+                GetBaseStatus(chan, statusByte);
                 KdPrint3((PRINT_PREFIX "  status re-check %#x\n", statusByte));
                 KdPrint3((PRINT_PREFIX "  Error reg (%#x)\n",
-                            AtapiReadPort1(chan, IDX_IO1_i_Error)));
+                            AtapiReadPort1(chan, IDX_ATAPI_IO1_i_Error)));
                 if (!(statusByte & IDE_STATUS_BUSY)) {
                     KdPrint2((PRINT_PREFIX "  expecting intr + cleared BUSY\n"));
                     break;
                 }
-                if(k <= 18) {
+                TotalTimerValue += TimerValue;
+                if(k <= 1) {
                     KdPrint3((PRINT_PREFIX "  too long wait -> DPC\n"));
                     if(!InDpc) {
                         KdPrint2((PRINT_PREFIX "  too long wait: ISR -> DPC\n"));
@@ -4446,13 +5342,21 @@ try_dpc_wait:
                         AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY1;
                     }
 #ifndef UNIATA_CORE
-                    goto CallTimerDpc2;
-#else //UNIATA_CORE
-                    AtapiStallExecution(TimerValue);
+                    if(UseDpc) {
+                        if(!LunExt->AtapiReadyWaitDelay) {
+                            LunExt->AtapiReadyWaitDelay = TotalTimerValue*2/3;
+                        }
+                        goto CallTimerDpc2;
+                    }
 #endif //UNIATA_CORE
                 }
 
-                AtapiStallExecution(10);
+                AtapiStallExecution(TimerValue);
+                TimerValue += 10;
+            }
+            if(!LunExt->AtapiReadyWaitDelay) {
+                LunExt->AtapiReadyWaitDelay = TotalTimerValue*2/3;
+                KdPrint2((PRINT_PREFIX "  store AtapiReadyWaitDelay: %d\n", LunExt->AtapiReadyWaitDelay));
             }
             if (statusByte & IDE_STATUS_BUSY) {
                 KdPrint3((PRINT_PREFIX "  expecting intr + BUSY (2), try DPC wait\n"));
@@ -4480,7 +5384,30 @@ try_dpc_wait:
         (dma_status & BM_STATUS_ERR)) {
 
         if(deviceExtension->HwFlags & UNIATA_AHCI) {
-            error = (UCHAR)((AtaReq->ahci.in_status >> 8) && 0xff);
+            error = AtaReq->ahci.in_error;
+            // wait ready
+#ifdef _DEBUG
+            UniataDumpAhciPortRegs(chan);
+#endif
+            if(!UniataAhciAbortOperation(chan)) {
+                KdPrint2((PRINT_PREFIX "need UniataAhciReset\n"));
+            }
+            // clear interrupts again
+            UniataAhciWaitCommandReady(chan, 10);
+#ifdef _DEBUG
+            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
         } else {
             error = AtapiReadPort1(chan, IDX_IO1_i_Error);
         }
@@ -4498,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);
@@ -4512,7 +5441,7 @@ continue_err:
             LunExt->DeviceFlags & DFLAGS_INT_DRQ));
 
         for (k = atapiDev ? 0 : 200; k; k--) {
-            GetStatus(chan, statusByte);
+            GetBaseStatus(chan, statusByte);
             if (!(statusByte & IDE_STATUS_DRQ)) {
                 AtapiStallExecution(50);
             } else {
@@ -4530,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;
                     }
@@ -4546,13 +5478,23 @@ continue_err:
                 }
             }
         } else {
-            interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & 0x3);
+            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;
@@ -4585,27 +5527,27 @@ continue_err:
         KdPrint2((PRINT_PREFIX "Some higher mode doesn't work right :((\n"));
         KdPrint2((PRINT_PREFIX "Recovery stats[%d]: %d vs %d\n",
               AtaReq->retry,
-              chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry],
-              chan->lun[DeviceNumber]->BlockIoCount
+              LunExt->RecoverCount[AtaReq->retry],
+              LunExt->BlockIoCount
               ));
-        chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry]++;
-        if(chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry] >= chan->lun[DeviceNumber]->BlockIoCount/3 ||
+        LunExt->RecoverCount[AtaReq->retry]++;
+        if(LunExt->RecoverCount[AtaReq->retry] >= LunExt->BlockIoCount/3 ||
            (deviceExtension->HwFlags & UNIATA_NO80CHK)
            ) {
 #else
         if(deviceExtension->HwFlags & UNIATA_NO80CHK) {
 #endif //IO_STATISTICS
-            KdPrint2((PRINT_PREFIX "Limit transfer rate to %x\n", deviceExtension->lun[DeviceNumber].TransferMode));
-            deviceExtension->lun[DeviceNumber].LimitedTransferMode =
-                deviceExtension->lun[DeviceNumber].TransferMode;
+            KdPrint2((PRINT_PREFIX "Limit transfer rate to %x\n", LunExt->TransferMode));
+            LunExt->LimitedTransferMode =
+                LunExt->TransferMode;
         }
     }
 #ifdef IO_STATISTICS
     if(AtaReq->bcount) {
         // we need stats for Read/Write operations
-        chan->lun[DeviceNumber]->BlockIoCount++;
+        LunExt->BlockIoCount++;
     }
-    chan->lun[DeviceNumber]->IoCount++;
+    LunExt->IoCount++;
 #endif //IO_STATISTICS
 
 continue_PIO:
@@ -4616,7 +5558,7 @@ continue_PIO:
         KdPrint2((PRINT_PREFIX "AtapiInterrupt: ATAPI branch\n"));
         // ATAPI branch
 
-        interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & 0x3);
+        interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
         KdPrint3((PRINT_PREFIX "AtapiInterrupt: iReason %x\n", interruptReason));
         if(DmaTransfer) {
             wordsThisInterrupt = DEV_BSIZE/2*512;
@@ -4643,10 +5585,10 @@ continue_PIO:
 
             if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
 
-                interruptReason =  0x2;
+                interruptReason = ATAPI_IR_IO_toHost;
 
             } else if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
-                interruptReason = 0x0;
+                interruptReason = ATAPI_IR_IO_toDev;
 
             } else {
                 status = SRB_STATUS_ERROR;
@@ -4661,13 +5603,14 @@ 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).
 PIO_wait_DRQ0:
                 // The ISR hits with DRQ low, but comes up later.
                 for (k = 0; k < 5000; k++) {
-                    GetStatus(chan, statusByte);
+                    GetBaseStatus(chan, statusByte);
                     if (statusByte & IDE_STATUS_DRQ) {
                         break;
                     }
@@ -4694,27 +5637,48 @@ IntrPrepareResetController:
                     goto ReturnEnableIntr;
 
                 } else {
-                    interruptReason = (srb->SrbFlags & SRB_FLAGS_DATA_IN) ? 0x2 : 0x0;
+                    interruptReason = (srb->SrbFlags & SRB_FLAGS_DATA_IN) ? ATAPI_IR_IO_toHost : ATAPI_IR_IO_toDev;
                 }
 
             } else {
                 // Command complete - verify, write, or the SMART enable/disable.
                 // Also get_media_status
-                interruptReason = 0x3;
+                interruptReason = ATAPI_IR_IO_toHost | ATAPI_IR_COD_Cmd;
             }
         }
     }
 
     KdPrint2((PRINT_PREFIX "AtapiInterrupt: i-reason=%d, status=%#x\n", interruptReason, statusByte));
     if(deviceExtension->HwFlags & UNIATA_AHCI) {
-        KdPrint2((PRINT_PREFIX "  AHCI path\n"));
-        goto ReturnEnableIntr;
+        KdPrint2((PRINT_PREFIX "  AHCI path, WordsTransfered %x, WordsLeft %x\n", AtaReq->WordsTransfered, AtaReq->WordsLeft));
+/*        if(chan->AhciLastIS & ATA_AHCI_P_IX_OF) {
+            //status = SRB_STATUS_DATA_OVERRUN;
+            DataOverrun = TRUE;
+        } else {
+            status = SRB_STATUS_SUCCESS;
+        }*/
+        if(AtaReq->WordsTransfered >= AtaReq->WordsLeft) {
+            AtaReq->WordsLeft = 0;
+        } else {
+            AtaReq->WordsLeft -= AtaReq->WordsTransfered;
+        }
+        //if(AtaReq->WordsLeft && (status == SRB_STATUS_SUCCESS)) {
+        //    status = SRB_STATUS_DATA_OVERRUN;
+        //}
+        status = SRB_STATUS_SUCCESS;
+        chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
+        goto CompleteRequest;
     } else
-    if (interruptReason == 0x1 && (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, 6, 0);
+        WriteBuffer(chan, (PUSHORT)srb->Cdb, 
+                          LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
+                          /*0*/ PIO0_TIMING);
         AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
 
         if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
@@ -4724,7 +5688,7 @@ IntrPrepareResetController:
 
         goto ReturnEnableIntr;
 
-    } else if (interruptReason == 0x0 && (statusByte & IDE_STATUS_DRQ)) {
+    } else if ((interruptReason == ATAPI_IR_IO_toDev) && (statusByte & IDE_STATUS_DRQ)) {
 
         // Write the data.
         if (atapiDev) {
@@ -4734,7 +5698,7 @@ IntrPrepareResetController:
                 AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow);
 
             wordCount |=
-                AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8;
+                (USHORT)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8;
 
             // Covert bytes to words.
             wordCount >>= 1;
@@ -4767,13 +5731,27 @@ IntrPrepareResetController:
             }
         }
 
-        if (DmaTransfer && (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) {
+        if (DmaTransfer &&
+            (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) {
             //ASSERT(AtaReq->WordsLeft == wordCount);
+            if(AtaReq->ReqState == REQ_STATE_ATAPI_EXPECTING_DATA_INTR2) {
+                KdPrint2((PRINT_PREFIX 
+                          "IdeIntr: DMA tmp INTR %#x vs %#x\n", AtaReq->WordsLeft, wordCount));
+                if(AtaReq->WordsLeft > wordCount) {
+                    AtaReq->WordsLeft -= wordCount;
+                    AtaReq->WordsTransfered += wordCount;
+                    AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
+                    goto ReturnEnableIntr;
+                }
+                dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/);
+            }
+            AtaReq->WordsTransfered = AtaReq->WordsLeft;
             AtaReq->WordsLeft = 0;
             status = SRB_STATUS_SUCCESS;
             chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
             goto CompleteRequest;
         }
+
         // Ensure that this is a write command.
         if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
 
@@ -4782,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,
@@ -4798,18 +5777,31 @@ IntrPrepareResetController:
         } else {
 
             KdPrint3((PRINT_PREFIX 
-                        "AtapiInterrupt: Int reason %#x, but srb is for a write %#x.\n",
+                        "AtapiInterrupt: Int reason %#x, but srb is for a read %#x.\n",
                         interruptReason,
                         srb));
 
             // Fail this request.
             status = SRB_STATUS_ERROR;
-            goto CompleteRequest;
-        }
+            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"));
 
-        // Advance data buffer pointer and bytes left.
+                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.
         AtaReq->DataBuffer += wordCount;
         AtaReq->WordsLeft -= wordCount;
+        AtaReq->WordsTransfered += wordCount;
 
         if (atapiDev) {
             AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
@@ -4817,20 +5809,26 @@ IntrPrepareResetController:
 
         goto ReturnEnableIntr;
 
-    } else if (interruptReason == 0x2 && (statusByte & IDE_STATUS_DRQ)) {
+    } 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);
-
-            // Covert bytes to words.
-            wordCount /= 2;
-            KdPrint2((PRINT_PREFIX "AtapiInterrupt: get R wordCount %#x\n", wordCount));
+                (ULONG)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow) |
+                ((ULONG)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8);
 
+            // Convert bytes to words.
+            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",
@@ -4856,8 +5854,21 @@ IntrPrepareResetController:
             }
         }
 
-        if (DmaTransfer && (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) {
+        if(DmaTransfer &&
+           (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) {
+            if(AtaReq->ReqState == REQ_STATE_ATAPI_EXPECTING_DATA_INTR2) {
+                KdPrint2((PRINT_PREFIX 
+                          "IdeIntr: DMA tmp INTR %#x vs %#x\n", AtaReq->WordsLeft, wordCount));
+                if(AtaReq->WordsLeft > wordCount) {
+                    AtaReq->WordsLeft -= wordCount;
+                    AtaReq->WordsTransfered += wordCount;
+                    AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
+                    goto ReturnEnableIntr;
+                }
+                dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/);
+            }
             //ASSERT(AtaReq->WordsLeft == wordCount);
+            AtaReq->WordsTransfered = AtaReq->WordsLeft;
             AtaReq->WordsLeft = 0;
             status = SRB_STATUS_SUCCESS;
             chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
@@ -4871,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));
 
@@ -4879,29 +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);
-                }
+            }
 
-                GetStatus(chan, statusByte);
-                KdPrint2((PRINT_PREFIX "  status re-check %#x\n", statusByte));
+            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);
+            }
 
-                if(DataOverrun) {
-                    KdPrint2((PRINT_PREFIX "  DataOverrun\n"));
-                    AtapiSuckPort2(chan);
-                }
+            GetBaseStatus(chan, statusByte);
+            KdPrint2((PRINT_PREFIX "  status re-check %#x\n", statusByte));
 
-            } else {
-                KdPrint2((PRINT_PREFIX 
-                          "IdeIntr: Read %#x Dwords\n", wordCount/2));
+            if(DataOverrun) {
+                KdPrint2((PRINT_PREFIX "  DataOverrun\n"));
+                AtapiSuckPort2(chan);
+                GetBaseStatus(chan, statusByte);
+            }
 
-                ReadBuffer2(chan,
-                           (PULONG)(AtaReq->DataBuffer),
-                           wordCount / 2,
-                           UniataGetPioTiming(LunExt));
+            if(statusByte & IDE_STATUS_BUSY) {
+                for (i = 0; i < 2; i++) {
+                    AtapiStallExecution(10);
+                    GetBaseStatus(chan, statusByte);
+                    if (!(statusByte & IDE_STATUS_BUSY)) {
+                        break;
+                    }
+                }
             }
+
         } else {
 
             KdPrint3((PRINT_PREFIX 
@@ -4913,10 +5946,11 @@ IntrPrepareResetController:
             status = SRB_STATUS_ERROR;
             goto CompleteRequest;
         }
-
+//continue_atapi_pio_read:
         // Advance data buffer pointer and bytes left.
         AtaReq->DataBuffer += wordCount;
         AtaReq->WordsLeft -= wordCount;
+        AtaReq->WordsTransfered += wordCount;
 
         // Check for read command complete.
         if (AtaReq->WordsLeft == 0) {
@@ -4924,22 +5958,47 @@ 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) {
 
+                        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
+                    // and all data read
+                    // Optionally, we may receive COMPLETE interrupt later and
+                    // treat it as unexpected
+                    KdPrint2((PRINT_PREFIX "AtapiInterrupt: early complete ? status %x\n", statusByte));
 
-                    *((ULONG *) &(AtaReq->DataBuffer[2])) = 0x00080000;
-                    AtaReq->DataBuffer += wordCount;
+                    status = SRB_STATUS_SUCCESS;
+                    goto CompleteRequest;
                 }
+
             } else {
 
             /*
@@ -4959,24 +6018,54 @@ IntrPrepareResetController:
         } else {
             if (atapiDev) {
                 AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
+                GetStatus(chan, statusByte);
+                if(!(statusByte & IDE_STATUS_BUSY)) {
+                    // Assume command is completed if BUSY is cleared
+                    // even if NOT all data read
+                    // Optionally, we may receive COMPLETE interrupt later and
+                    // treat it as unexpected
+                    KdPrint2((PRINT_PREFIX "AtapiInterrupt: early complete + underrun ? status %x\n", statusByte));
+
+                    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;
+                }
             }
         }
 
         goto ReturnEnableIntr;
 
-    } else if (interruptReason == 0x3  && !(statusByte & IDE_STATUS_DRQ)) {
+    } else if (interruptReason == (ATAPI_IR_IO_toHost | ATAPI_IR_COD_Cmd) && !(statusByte & IDE_STATUS_DRQ)) {
 
         KdPrint2((PRINT_PREFIX "AtapiInterrupt: interruptReason = CompleteRequest\n"));
-        // Command complete.
+        // Command complete. We exactly know this because of IReason.
+
         if(DmaTransfer) {
             KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest, was DmaTransfer\n"));
+            AtaReq->WordsTransfered += AtaReq->WordsLeft;
             AtaReq->WordsLeft = 0;
-        }
-        if (AtaReq->WordsLeft) {
-            status = SRB_STATUS_DATA_OVERRUN;
         } else {
-            status = SRB_STATUS_SUCCESS;
+            KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest, was PIO\n"));
+
+            wordCount = AtaReq->WordsLeft;
+            // Advance data buffer pointer and bytes left.
+            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;
+        //} else {
+            status = SRB_STATUS_SUCCESS;
+        //}
 
 #ifdef UNIATA_DUMP_ATAPI
         if(srb &&
@@ -4998,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,
@@ -5029,15 +6118,22 @@ IntrPrepareResetController:
 
 CompleteRequest:
 
-        KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest\n"));
+        KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest, srbstatus %x\n", status));
         // Check and see if we are processing our secret (mechanism status/request sense) srb
+
+        if(AtaReq->WordsLeft && (status == SRB_STATUS_SUCCESS)) {
+            KdPrint2((PRINT_PREFIX "WordsLeft %#x -> SRB_STATUS_DATA_OVERRUN\n", AtaReq->WordsLeft));
+            status = SRB_STATUS_DATA_OVERRUN;
+        }
+
         if (AtaReq->OriginalSrb) {
 
             ULONG srbStatus;
 
             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!!
@@ -5078,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
@@ -5094,21 +6195,20 @@ 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));
                         // The sense key doesn't say the last request is illegal, so try again
                         chan->MechStatusRetryCount--;
                         srb = AtaReq->Srb = BuildMechanismStatusSrb (
                                                               HwDeviceExtension,
                                                               AtaReq->OriginalSrb);
-                    } else {
-
-                        // last request was illegal.  No point trying again
-                        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;
@@ -5146,10 +6246,6 @@ CompleteRequest:
             KdPrint3((PRINT_PREFIX "AtapiInterrupt: Error. complete OriginalSrb\n"));
 
             if (AtaReq->OriginalSrb) {
-                KdPrint2((PRINT_PREFIX "AtapiInterrupt: call AtapiHwInitializeChanger()\n"));
-                AtapiHwInitializeChanger (HwDeviceExtension,
-                                          srb,
-                                          (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
                 srb = AtaReq->Srb = AtaReq->OriginalSrb;
                 AtaReq->OriginalSrb = NULL;
             }
@@ -5180,7 +6276,7 @@ PIO_wait_busy:
             KdPrint2((PRINT_PREFIX "AtapiInterrupt: PIO completion, wait BUSY\n"));
             // Wait for busy to drop.
             for (i = 0; i < 5*30; i++) {
-                GetStatus(chan, statusByte);
+                GetBaseStatus(chan, statusByte);
                 if (!(statusByte & IDE_STATUS_BUSY)) {
                     break;
                 }
@@ -5238,7 +6334,7 @@ PIO_wait_busy:
 PIO_wait_DRQ:
                 KdPrint2((PRINT_PREFIX "AtapiInterrupt: PIO_wait_DRQ\n"));
                 for (i = 0; i < 200; i++) {
-                    GetStatus(chan, statusByte);
+                    GetBaseStatus(chan, statusByte);
                     if (!(statusByte & IDE_STATUS_DRQ)) {
                         break;
                     }
@@ -5275,7 +6371,8 @@ PIO_wait_DRQ:
         }
 
         // Clear interrupt expecting flag.
-        chan->ExpectingInterrupt = FALSE;
+        UniataExpectChannelInterrupt(chan, FALSE);
+        // clear this flag now, it can be set again in sub-calls
         InterlockedExchange(&(chan->CheckIntr),
                                       CHECK_INTR_IDLE);
 
@@ -5301,7 +6398,10 @@ PIO_wait_DRQ:
                 }
             }
             if(status == SRB_STATUS_SUCCESS) {
-                AtaReq->WordsTransfered += AtaReq->bcount * DEV_BSIZE/2;
+                //if(!(deviceExtension->HwFlags & UNIATA_AHCI) && !atapiDev) {
+                //    // This should be set in UniataAhciEndTransaction() for AHCI
+                //    AtaReq->WordsTransfered += AtaReq->bcount * DEV_BSIZE/2;
+                //}
                 if(!atapiDev &&
                    AtaReq->WordsTransfered*2 < AtaReq->TransferLength) {
                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: more I/O required (%x of %x bytes) -> reenqueue\n",
@@ -5350,31 +6450,35 @@ IntrCompleteReq:
             } else {
 
                 KdPrint2((PRINT_PREFIX "AtapiInterrupt: IOCTL completion\n"));
-                PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
 
                 if (status != SRB_STATUS_SUCCESS) {
                     error = AtapiReadPort1(chan, IDX_IO1_i_Error);
                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: error %#x\n", error));
                 }
 
-                // Build the SMART status block depending upon the completion status.
-                cmdOutParameters->cBufferSize = wordCount;
-                cmdOutParameters->DriverStatus.bDriverError = (error) ? SMART_IDE_ERROR : 0;
-                cmdOutParameters->DriverStatus.bIDEError = error;
+                if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(srb->DataBuffer))->Signature),"SCSIDISK",sizeof("SCSIDISK")-1)) {
 
-                // If the sub-command is return smart status, jam the value from cylinder low and high, into the
-                // data buffer.
-                if (chan->SmartCommand == RETURN_SMART_STATUS) {
-                    cmdOutParameters->bBuffer[0] = RETURN_SMART_STATUS;
-                    cmdOutParameters->bBuffer[1] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason);
-                    cmdOutParameters->bBuffer[2] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_Unused1);
-                    cmdOutParameters->bBuffer[3] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow);
-                    cmdOutParameters->bBuffer[4] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh);
-                    cmdOutParameters->bBuffer[5] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_DriveSelect);
-                    cmdOutParameters->bBuffer[6] = SMART_CMD;
-                    cmdOutParameters->cBufferSize = 8;
-                }
+                    PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+                    // Build the SMART status block depending upon the completion status.
+                    cmdOutParameters->cBufferSize = wordCount;
+                    cmdOutParameters->DriverStatus.bDriverError = (error) ? SMART_IDE_ERROR : 0;
+                    cmdOutParameters->DriverStatus.bIDEError = error;
+
+                    // If the sub-command is return smart status, jam the value from cylinder low and high, into the
+                    // data buffer.
+                    if (chan->SmartCommand == RETURN_SMART_STATUS) {
+                        PIDEREGS_EX regs = (PIDEREGS_EX)&(cmdOutParameters->bBuffer);
 
+                        regs->bOpFlags = 0;
+                        UniataSnapAtaRegs(chan, 0, regs);
+
+                        regs->bCommandReg = SMART_CMD;
+                        regs->bFeaturesReg = RETURN_SMART_STATUS;
+
+                        cmdOutParameters->cBufferSize = 8;
+                    }
+                    chan->SmartCommand = 0; // cleanup after execution
+                }
                 // Indicate command complete.
                 goto IntrCompleteReq;
             }
@@ -5387,7 +6491,7 @@ IntrCompleteReq:
         if (chan->RDP) {
             // Check DSC
             for (i = 0; i < 5; i++) {
-                GetStatus(chan, statusByte);
+                GetBaseStatus(chan, statusByte);
                 if(!(statusByte & IDE_STATUS_BUSY)) {
                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: RDP + cleared BUSY\n"));
                     chan->RDP = FALSE;
@@ -5453,11 +6557,29 @@ 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"));
+            status = SRB_STATUS_SUCCESS;
+            chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
+            goto CompleteRequest;
+        }
     }
 
 ReturnEnableIntr:
 
     KdPrint2((PRINT_PREFIX "AtapiInterrupt: ReturnEnableIntr\n",srb));
+    //UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
+    deviceExtension->ExpectingInterrupt = TRUE;
     if(UseDpc) {
         if(CrNtInterlockedExchangeAdd(&(chan->DisableIntr), 0)) {
             KdPrint2((PRINT_PREFIX "AtapiInterrupt: call AtapiEnableInterrupts__()\n"));
@@ -5527,19 +6649,20 @@ ULONG
 NTAPI
 IdeSendSmartCommand(
     IN PVOID HwDeviceExtension,
-    IN PSCSI_REQUEST_BLOCK Srb
+    IN PSCSI_REQUEST_BLOCK Srb,
+    IN ULONG targetId // assume it is always valid
     )
 {
     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
-    ULONG                c               = GET_CHANNEL(Srb);
-    PHW_CHANNEL          chan            = &(deviceExtension->chan[c]);
+    ULONG                c               ; // = GET_CHANNEL(Srb); may be invalid
+    PHW_CHANNEL          chan            ; // = &(deviceExtension->chan[c]);
     PATA_REQ             AtaReq          = (PATA_REQ)(Srb->SrbExtension);
     PSENDCMDOUTPARAMS    cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
     SENDCMDINPARAMS      cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
     PIDEREGS             regs            = &cmdInParameters.irDriveRegs;
 //    ULONG                i;
-    UCHAR                statusByte,targetId;
-
+    UCHAR                statusByte;
+    ULONG DeviceNumber;
 
     if (regs->bCommandReg != SMART_CMD) {
         KdPrint2((PRINT_PREFIX 
@@ -5547,14 +6670,11 @@ IdeSendSmartCommand(
         return SRB_STATUS_INVALID_REQUEST;
     }
 
-    targetId = cmdInParameters.bDriveNumber;
+    c = targetId / deviceExtension->NumberLuns;
+    DeviceNumber = targetId % deviceExtension->NumberLuns;
+    KdPrint2((PRINT_PREFIX "  c %d, dev %d\n", c, DeviceNumber));
 
-    //TODO optimize this check
-    if ((!(deviceExtension->lun[targetId].DeviceFlags & DFLAGS_DEVICE_PRESENT)) ||
-         (deviceExtension->lun[targetId].DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
-
-        return SRB_STATUS_SELECTION_TIMEOUT;
-    }
+    chan = &(deviceExtension->chan[c]);
 
     chan->SmartCommand = regs->bFeaturesReg;
 
@@ -5562,6 +6682,14 @@ IdeSendSmartCommand(
     switch(regs->bFeaturesReg) {
     case READ_ATTRIBUTES:
     case READ_THRESHOLDS:
+    case READ_LOG_SECTOR:
+    case WRITE_LOG_SECTOR:
+
+        if(Srb->DataTransferLength < sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1) {
+            KdPrint2((PRINT_PREFIX 
+                        "IdeSendSmartCommand: wrong buffer size\n"));
+            return SRB_STATUS_DATA_OVERRUN;
+        }
 
         statusByte = WaitOnBusy(chan);
 
@@ -5578,7 +6706,7 @@ IdeSendSmartCommand(
         AtaReq->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer;
         AtaReq->WordsLeft = READ_ATTRIBUTE_BUFFER_SIZE / 2;
 
-        statusByte = AtaCommand(deviceExtension, targetId & 0x1, c,
+        statusByte = AtaCommand(deviceExtension, DeviceNumber, c,
                    regs->bCommandReg,
                    (USHORT)(regs->bCylLowReg) | (((USHORT)(regs->bCylHighReg)) << 8),
                    0,
@@ -5599,6 +6727,7 @@ IdeSendSmartCommand(
     case ENABLE_DISABLE_AUTOSAVE:
     case EXECUTE_OFFLINE_DIAGS:
     case SAVE_ATTRIBUTE_VALUES:
+    case AUTO_OFFLINE:
 
         statusByte = WaitOnBusy(chan);
 
@@ -5615,7 +6744,7 @@ IdeSendSmartCommand(
         AtaReq->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer;
         AtaReq->WordsLeft = 0;
 
-        statusByte = AtaCommand(deviceExtension, targetId & 0x1, c,
+        statusByte = AtaCommand(deviceExtension, DeviceNumber, c,
                    regs->bCommandReg,
                    (USHORT)(regs->bCylLowReg) | (((USHORT)(regs->bCylHighReg)) << 8),
                    0,
@@ -5626,6 +6755,7 @@ IdeSendSmartCommand(
 
         if(!(statusByte & IDE_STATUS_ERROR)) {
             // Wait for interrupt.
+            UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
             return SRB_STATUS_PENDING;
         }
         return SRB_STATUS_ERROR;
@@ -5641,7 +6771,7 @@ ULONGLONG
 NTAPI
 UniAtaCalculateLBARegs(
     PHW_LU_EXTENSION     LunExt,
-    ULONG                startingSector,
+    ULONGLONG            startingSector,
     PULONG               max_bcount
     )
 {
@@ -5650,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;
@@ -5673,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()
@@ -5738,8 +6868,8 @@ IdeReadWrite(
     PATA_REQ             AtaReq = (PATA_REQ)(Srb->SrbExtension);
     //ULONG                ldev = GET_LDEV(Srb);
     UCHAR                DeviceNumber = GET_CDEV(Srb);;
-    ULONG                startingSector;
-    ULONG                max_bcount;
+    ULONGLONG            startingSector=0;
+    ULONG                max_bcount = 0;
     ULONG                wordCount = 0;
     UCHAR                statusByte,statusByte2;
     UCHAR                cmd;
@@ -5769,9 +6899,9 @@ IdeReadWrite(
 
         if(AtaReq->WordsTransfered) {
             AtaReq->DataBuffer = ((PUSHORT)(Srb->DataBuffer)) + AtaReq->WordsTransfered;
-            startingSector = (ULONG)(UniAtaCalculateLBARegsBack(LunExt, AtaReq->lba)) /* latest lba */ + AtaReq->bcount /* previous bcount */;
+            startingSector = (UniAtaCalculateLBARegsBack(LunExt, AtaReq->lba)) /* latest lba */ + AtaReq->bcount /* previous bcount */;
             AtaReq->bcount = (AtaReq->TransferLength - AtaReq->WordsTransfered*2 + DEV_BSIZE-1) / DEV_BSIZE;
-            KdPrint2((PRINT_PREFIX "IdeReadWrite (Chained REQ): Starting sector %#x, OrigWordsRequested %#x, WordsTransfered %#x, DevSize %#x\n",
+            KdPrint2((PRINT_PREFIX "IdeReadWrite (Chained REQ): Starting sector %I64x, OrigWordsRequested %#x, WordsTransfered %#x, DevSize %#x\n",
                        startingSector,
                        AtaReq->TransferLength/2,
                        AtaReq->WordsTransfered,
@@ -5780,9 +6910,34 @@ IdeReadWrite(
             AtaReq->DataBuffer = (PUSHORT)(Srb->DataBuffer);
             AtaReq->TransferLength = Srb->DataTransferLength;
             // Set up 1st block.
-            MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA);
-            MOV_SWP_DW2DD(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
-            KdPrint2((PRINT_PREFIX "IdeReadWrite (Orig REQ): Starting sector %#x, OrigWordsRequested %#x, DevSize %#x\n",
+            switch(Srb->Cdb[0]) {
+            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_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;
+            case SCSIOP_READ16:
+            case SCSIOP_WRITE16:
+                MOV_QD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB16READWRITE.LBA);
+                MOV_DD_SWP(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB16READWRITE.NumOfBlocks);
+                break;
+            }
+            KdPrint2((PRINT_PREFIX "IdeReadWrite (Orig REQ): Starting sector %I64x, OrigWordsRequested %#x, DevSize %#x\n",
                        startingSector,
                        AtaReq->TransferLength/2,
                        AtaReq->bcount));
@@ -5795,15 +6950,36 @@ IdeReadWrite(
         AtaReq->WordsLeft = min(AtaReq->TransferLength - AtaReq->WordsTransfered*2,
                                 AtaReq->bcount * DEV_BSIZE) / 2;
 
-        KdPrint2((PRINT_PREFIX "IdeReadWrite (REQ): Starting sector is %#x, Number of WORDS %#x, DevSize %#x\n",
+        KdPrint2((PRINT_PREFIX "IdeReadWrite (REQ): Starting sector is %I64x, Number of WORDS %#x, DevSize %#x\n",
                    startingSector,
                    AtaReq->WordsLeft,
                    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
+        if(deviceExtension->HwFlags & UNIATA_AHCI) {
+            UniataAhciSetupCmdPtr(AtaReq);
+            if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
+                          (PUCHAR)(AtaReq->DataBuffer),
+                          AtaReq->bcount * DEV_BSIZE)) {
+                KdPrint3((PRINT_PREFIX "IdeReadWrite: AHCI !DMA\n"));
+                return SRB_STATUS_ERROR;
+            }
+        } else
         if ((LunExt->LimitedTransferMode >= ATA_DMA)) {
             use_dma = TRUE;
             // this will set REQ_FLAG_DMA_OPERATION in AtaReq->Flags on success
@@ -5814,29 +6990,25 @@ IdeReadWrite(
             }
         }
 
-        if(use_dma && (deviceExtension->HwFlags & UNIATA_AHCI)) {
-            UniataAhciSetupCmdPtr(AtaReq);
-            KdPrint2((PRINT_PREFIX "AtapiSendCommand: setup AHCI FIS\n"));
+        if(deviceExtension->HwFlags & UNIATA_AHCI) {
+            KdPrint2((PRINT_PREFIX "IdeReadWrite: setup AHCI FIS\n"));
             RtlZeroMemory(&(AtaReq->ahci.ahci_cmd_ptr->cfis), sizeof(AtaReq->ahci_cmd0.cfis));
 
             fis_size = UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
                    &(AtaReq->ahci.ahci_cmd_ptr->cfis[0]),
-                    (AtaReq->Flags & REQ_FLAG_READ) ? IDE_COMMAND_READ_DMA : /*IDE_COMMAND_WRITE_DMA*/ IDE_COMMAND_READ_DMA,
+                    (AtaReq->Flags & REQ_FLAG_READ) ? IDE_COMMAND_READ_DMA : IDE_COMMAND_WRITE_DMA,
                     lba,
                      (USHORT)(AtaReq->bcount),
-                    0,
-                    ATA_IMMEDIATE
+                    0
+                    /*,(AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE*/
                     );
 
             if(!fis_size) {
-                KdPrint3((PRINT_PREFIX "AtapiSendCommand: AHCI !FIS\n"));
+                KdPrint3((PRINT_PREFIX "IdeReadWrite: AHCI !FIS\n"));
                 return SRB_STATUS_ERROR;
             }
 
-            AtaReq->ahci.io_cmd_flags = (USHORT)(((AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE) |
-                                     /*((LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) |*/
-                                     (fis_size / sizeof(ULONG)) |
-                                     (DeviceNumber << 12));
+            AtaReq->ahci.io_cmd_flags = UniAtaAhciAdjustIoFlags(0, (AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE, fis_size, DeviceNumber);
             KdPrint2((PRINT_PREFIX "IdeReadWrite ahci io flags %x: \n", AtaReq->ahci.io_cmd_flags));
         }
 
@@ -5909,29 +7081,48 @@ IdeReadWrite(
         chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
     }
 
-    if(use_dma && (deviceExtension->HwFlags & UNIATA_AHCI)) {
+    if(deviceExtension->HwFlags & UNIATA_AHCI) {
+        // AHCI doesn't distinguish DMA and PIO
         //AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
-        UniataAhciBeginTransaction(HwDeviceExtension, DeviceNumber, lChannel, Srb);
+        UniataAhciBeginTransaction(HwDeviceExtension, lChannel, DeviceNumber, Srb);
+        UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
+        InterlockedExchange(&(chan->CheckIntr),
+                                      CHECK_INTR_IDLE);
         return SRB_STATUS_PENDING;
     }
 
     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 != 0xff) {
+/*        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;
     }
@@ -5943,9 +7134,9 @@ IdeReadWrite(
                  0, ATA_WAIT_INTR);
 
     if (!(statusByte & IDE_STATUS_DRQ) ||
-        statusByte == 0xff) {
+        statusByte == IDE_STATUS_WRONG) {
 
-        if(statusByte == 0xff) {
+        if(statusByte == IDE_STATUS_WRONG) {
             KdPrint2((PRINT_PREFIX 
                        "IdeReadWrite: error sending command (%#x)\n",
                        statusByte));
@@ -5958,22 +7149,22 @@ IdeReadWrite(
         AtaReq->WordsLeft = 0;
 
         // Clear interrupt expecting flag.
-        chan->ExpectingInterrupt = FALSE;
+        UniataExpectChannelInterrupt(chan, FALSE);
         InterlockedExchange(&(chan->CheckIntr),
                                       CHECK_INTR_IDLE);
 
         // Clear current SRB.
         UniataRemoveRequest(chan, Srb);
 
-        return (statusByte == 0xff) ? SRB_STATUS_ERROR : SRB_STATUS_TIMEOUT;
+        return (statusByte == IDE_STATUS_WRONG) ? SRB_STATUS_ERROR : SRB_STATUS_TIMEOUT;
     }
 
-    chan->ExpectingInterrupt = TRUE;
+    UniataExpectChannelInterrupt(chan, TRUE);
     InterlockedExchange(&(chan->CheckIntr),
                                   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));
 
@@ -5996,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;
@@ -6032,11 +7224,11 @@ IdeVerify(
     //ULONG                ldev = GET_LDEV(Srb);
     ULONG                DeviceNumber = GET_CDEV(Srb);
     UCHAR                statusByte;
-    ULONG                startingSector;
+    ULONGLONG            startingSector=0;
     ULONG                max_bcount;
-    ULONG                sectors;
-    ULONG                endSector;
-    USHORT               sectorCount;
+    ULONGLONG            sectors;
+    ULONGLONG            endSector;
+    ULONG                sectorCount=0;
     ULONGLONG            lba;
 
     LunExt = chan->lun[DeviceNumber];
@@ -6048,22 +7240,34 @@ IdeVerify(
     }
 
     KdPrint2((PRINT_PREFIX 
-                "IdeVerify: Total sectors %#x\n",
+                "IdeVerify: Total sectors %#I64x\n",
                 sectors));
 
     // Get starting sector number from CDB.
-    MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA);
-    MOV_DW_SWP(sectorCount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
+    switch(Srb->Cdb[0]) {
+    case SCSIOP_VERIFY:
+        MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA);
+        MOV_SWP_DW2DD(sectorCount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
+        break;
+    case SCSIOP_VERIFY12:
+        MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB12READWRITE.LBA);
+        MOV_DD_SWP(sectorCount, ((PCDB)Srb->Cdb)->CDB12READWRITE.NumOfBlocks);
+        break;
+    case SCSIOP_VERIFY16:
+        MOV_QD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB16READWRITE.LBA);
+        MOV_DD_SWP(sectorCount, ((PCDB)Srb->Cdb)->CDB16READWRITE.NumOfBlocks);
+        break;
+    }
 
     KdPrint2((PRINT_PREFIX 
-                "IdeVerify: Starting sector %#x. Number of blocks %#x\n",
+                "IdeVerify: Starting sector %#I64x. Number of blocks %#x\n",
                 startingSector,
                 sectorCount));
 
     endSector = startingSector + sectorCount;
 
     KdPrint2((PRINT_PREFIX 
-                "IdeVerify: Ending sector %#x\n",
+                "IdeVerify: Ending sector %#I64x\n",
                 endSector));
 
     if (endSector > sectors) {
@@ -6073,7 +7277,7 @@ IdeVerify(
                     "IdeVerify: Truncating request to %#x blocks\n",
                     sectors - startingSector - 1));
 
-        sectorCount = (USHORT)(sectors - startingSector - 1);
+        sectorCount = (ULONG)(sectors - startingSector - 1);
 
     } else {
 
@@ -6095,11 +7299,12 @@ IdeVerify(
 
     statusByte = AtaCommand48(deviceExtension, LunExt->Lun, GET_CHANNEL(Srb),
                  IDE_COMMAND_VERIFY, lba,
-                 sectorCount,
+                 (USHORT)sectorCount,
                  0, ATA_IMMEDIATE);
 
     if(!(statusByte & IDE_STATUS_ERROR)) {
         // Wait for interrupt.
+        UniataExpectChannelInterrupt(chan, TRUE);
         return SRB_STATUS_PENDING;
     }
     return SRB_STATUS_ERROR;
@@ -6135,13 +7340,14 @@ AtapiSendCommand(
     PHW_LU_EXTENSION     LunExt;
     //ULONG                ldev = GET_LDEV(Srb);
     ULONG                DeviceNumber = GET_CDEV(Srb);
-    ULONG i;
     ULONG flags;
-    UCHAR statusByte,byteCountLow,byteCountHigh;
+    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];
 
@@ -6149,6 +7355,7 @@ AtapiSendCommand(
     if(AtaReq->ReqState < REQ_STATE_PREPARE_TO_TRANSFER)
         AtaReq->ReqState = REQ_STATE_PREPARE_TO_TRANSFER;
 
+
 #ifdef UNIATA_DUMP_ATAPI
     if(CmdAction & CMD_ACTION_PREPARE) {
         UCHAR                   ScsiCommand;
@@ -6167,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,
@@ -6191,6 +7398,18 @@ AtapiSendCommand(
                      Cdb->CDB12READWRITE.LBA[3]
                      ));
         } else
+        if(ScsiCommand == SCSIOP_WRITE16) {
+            KdPrint(("Write16, LBA %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
+                     Cdb->CDB16READWRITE.LBA[0],
+                     Cdb->CDB16READWRITE.LBA[1],
+                     Cdb->CDB16READWRITE.LBA[2],
+                     Cdb->CDB16READWRITE.LBA[3],
+                     Cdb->CDB16READWRITE.LBA[4],
+                     Cdb->CDB16READWRITE.LBA[5],
+                     Cdb->CDB16READWRITE.LBA[6],
+                     Cdb->CDB16READWRITE.LBA[7]
+                     ));
+        } else
         if(ScsiCommand == SCSIOP_MODE_SELECT) {
             KdPrint(("ModeSelect 6\n"));
             PMODE_PARAMETER_HEADER ParamHdr = (PMODE_PARAMETER_HEADER)CdbData;
@@ -6214,38 +7433,128 @@ AtapiSendCommand(
 
 
     if(CmdAction == CMD_ACTION_PREPARE) {
-        KdPrint2((PRINT_PREFIX "AtapiSendCommand: CMD_ACTION_PREPARE\n"));
+        KdPrint2((PRINT_PREFIX "AtapiSendCommand: CMD_ACTION_PREPARE, Cdb %x\n", &(Srb->Cdb)));
+
         switch (Srb->Cdb[0]) {
+        case SCSIOP_RECEIVE:
+        case SCSIOP_SEND:
         case SCSIOP_READ:
         case SCSIOP_WRITE:
         case SCSIOP_READ12:
         case SCSIOP_WRITE12:
+        case SCSIOP_READ16:
+        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) {
+
+        ULONG srbStatus;
+
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: BuildMechanismStatusSrb()\n"));
+        // Set this flag now. If the device hangs on the mech. status
+        // command, we will not have the chance to set it.
+        LunExt->DeviceFlags |= DFLAGS_CHANGER_INITED;
+
+        chan->MechStatusRetryCount = 3;
+        AtaReq->OriginalSrb = Srb;
+        AtaReq->Srb = BuildMechanismStatusSrb (
+                                        HwDeviceExtension,
+                                        Srb);
+
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: AtapiSendCommand recursive\n"));
+        srbStatus = AtapiSendCommand(HwDeviceExtension, AtaReq->Srb, CMD_ACTION_ALL);
+        if (srbStatus == SRB_STATUS_PENDING) {
+            KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_PENDING (2)\n"));
+            return srbStatus;
+        } else {
+
+            // failed!  Get the sense key and maybe try again
+            AtaReq->Srb = BuildRequestSenseSrb (  HwDeviceExtension,
+                                                  AtaReq->OriginalSrb);
+
+            srbStatus = AtapiSendCommand(HwDeviceExtension, AtaReq->Srb, CMD_ACTION_ALL);
+
+            KdPrint3((PRINT_PREFIX "AtapiSendCommand: chan->ExpectingInterrupt %d (1)\n", chan->ExpectingInterrupt));
+
+            if (srbStatus == SRB_STATUS_PENDING) {
+                KdPrint2((PRINT_PREFIX "AtapiSendCommand: send orig SRB_STATUS_PENDING (2.1)\n"));
+                return srbStatus;
+            }
+
+            // failed again ? should not get here
+            AtaReq->Srb = AtaReq->OriginalSrb;
+            AtaReq->OriginalSrb = NULL;
+            // fall out
+        }
     }
+#endif // UNIATA_INIT_CHANGERS
+#endif //UNIATA_CORE
 
     if((CmdAction & CMD_ACTION_PREPARE) &&
        (AtaReq->ReqState != REQ_STATE_READY_TO_TRANSFER)) {
 
-        KdPrint2((PRINT_PREFIX "AtapiSendCommand: prepare..., ATAPI CMD %x\n", Srb->Cdb[0]));
+        KdPrint2((PRINT_PREFIX "AtapiSendCommand: prepare..., ATAPI CMD %x (Cdb %x)\n", Srb->Cdb[0], &(Srb->Cdb)));
+
+        if(!LunExt->IdentifyData.AtapiCmdSize &&
+            (Srb->CdbLength > 12)) {
+            KdPrint2((PRINT_PREFIX "Cdb16 not supported\n"));
+            return SRB_STATUS_INVALID_REQUEST;
+        }
+
         // Set data buffer pointer and words left.
         AtaReq->DataBuffer = (PUSHORT)Srb->DataBuffer;
         AtaReq->WordsLeft = Srb->DataTransferLength / 2;
         AtaReq->TransferLength = Srb->DataTransferLength;
         AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
+        // reset this to force PRD init. May be already setup by recursive SRB
+        AtaReq->dma_entries = 0;
 
         // check if reorderable
         switch(Srb->Cdb[0]) {
+        case SCSIOP_READ16:
+        case SCSIOP_WRITE16:
+
+            MOV_DD_SWP(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB16READWRITE.NumOfBlocks);
+            MOV_QD_SWP(AtaReq->lba, ((PCDB)Srb->Cdb)->CDB16READWRITE.LBA);
+            goto GetLba2;
+
         case SCSIOP_READ12:
         case SCSIOP_WRITE12:
 
@@ -6258,31 +7567,70 @@ AtapiSendCommand(
             MOV_SWP_DW2DD(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
 GetLba:
             MOV_DD_SWP(AtaReq->lba, ((PCDB)Srb->Cdb)->CDB10.LBA);
-
+GetLba2:
             AtaReq->Flags |= REQ_FLAG_REORDERABLE_CMD;
             AtaReq->Flags &= ~REQ_FLAG_RW_MASK;
-            AtaReq->Flags |= (Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_WRITE12) ?
+            AtaReq->Flags |= (Srb->Cdb[0] == SCSIOP_WRITE ||
+                              Srb->Cdb[0] == SCSIOP_WRITE12 ||
+                              Srb->Cdb[0] == SCSIOP_WRITE16) ?
                               REQ_FLAG_WRITE : REQ_FLAG_READ;
             break;
+        default:
+            AtaReq->Flags &= ~REQ_FLAG_RW_MASK;
+            if(!AtaReq->TransferLength) {
+                KdPrint(("  assume 0-transfer\n"));
+            } else
+            if(Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+                KdPrint(("  assume OUT\n"));
+                AtaReq->Flags |= REQ_FLAG_WRITE;
+            } else
+            if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+                KdPrint(("  assume IN\n"));
+                AtaReq->Flags |= REQ_FLAG_READ;
+            }
+            break;
         }
 
         // 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;
+            goto setup_dma;
+        } else
+/*        if((deviceExtension->HwFlags & UNIATA_SATA) && (LunExt->OrigTransferMode >= ATA_DMA)) {
+            KdPrint2((PRINT_PREFIX "AtapiSendCommand: force use dma (sata)\n"));
+            use_dma = TRUE;
+            goto setup_dma;
+        } else*/
         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:
+            case SCSIOP_WRITE16:
+            case SCSIOP_SEND:
                 if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_RO)
                     break;
                 /* FALLTHROUGH */
+            case SCSIOP_RECEIVE:
             case SCSIOP_READ:
             case SCSIOP_READ12:
+            case SCSIOP_READ16:
 
                 if(deviceExtension->opt_AtapiDmaReadWrite) {
 call_dma_setup:
+                    if(deviceExtension->HwFlags & UNIATA_AHCI) {
+                        KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma (ahci)\n"));
+                        use_dma = TRUE;
+                    } else
                     if(AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
                                   (PUCHAR)(AtaReq->DataBuffer),
                                   Srb->DataTransferLength
@@ -6294,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;
@@ -6316,7 +7665,12 @@ call_dma_setup:
                 break;
             }
             // try setup DMA
+setup_dma:
             if(use_dma) {
+                if(deviceExtension->HwFlags & UNIATA_AHCI) {
+                    KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma (ahci)\n"));
+                    //use_dma = TRUE;
+                } else
                 if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
                               (PUCHAR)(AtaReq->DataBuffer),
                               Srb->DataTransferLength)) {
@@ -6327,35 +7681,59 @@ call_dma_setup:
                 }
             }
         } 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));
         }
 
 
         if(deviceExtension->HwFlags & UNIATA_AHCI) {
-            UniataAhciSetupCmdPtr(AtaReq);
-            KdPrint2((PRINT_PREFIX "AtapiSendCommand: setup AHCI FIS\n"));
-            RtlZeroMemory(&(AtaReq->ahci.ahci_cmd_ptr->cfis), sizeof(AtaReq->ahci_cmd0.cfis));
-            RtlCopyMemory(&(AtaReq->ahci.ahci_cmd_ptr->acmd), Srb->Cdb, 16);
 
-            fis_size = UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
-                   &(AtaReq->ahci.ahci_cmd_ptr->cfis[0]),
-                    IDE_COMMAND_ATAPI_PACKET /* command */,
-                    0 /* lba */,
-                    (Srb->DataTransferLength >= 0x10000) ? (USHORT)(0xffff) : (USHORT)(Srb->DataTransferLength),
-                    use_dma ? ATA_F_DMA : 0/* feature */,
-                    ATA_IMMEDIATE /* flags */
-                    );
+            UniataAhciSetupCmdPtr(AtaReq);
 
-            if(!fis_size) {
-                KdPrint3((PRINT_PREFIX "AtapiSendCommand: AHCI !FIS\n"));
-                return SRB_STATUS_ERROR;
-            }
+            if(!Srb->DataTransferLength) {
+                KdPrint2((PRINT_PREFIX "zero-transfer\n"));
+                use_dma = FALSE;
+            } else
+            if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
+                          (PUCHAR)(AtaReq->DataBuffer),
+                          Srb->DataTransferLength)) {
+                KdPrint2((PRINT_PREFIX "AtapiSendCommand: no AHCI dma!\n"));
+                return SRB_STATUS_ERROR;
+            }
+            if(!use_dma) {
+                AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
+            } else {
+                FeatureReg |= ATA_F_DMA;
+                if(LunExt->IdentifyData.AtapiDMA.DMADirRequired) {
+                    if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+                        KdPrint2((PRINT_PREFIX "Set DMADir.\n"));
+                        FeatureReg |= ATA_F_DMAREAD;
+                    }
+                }
+            }
+
+            KdPrint2((PRINT_PREFIX "AtapiSendCommand: setup AHCI FIS\n"));
+            // this is done in UniataAhciSetupFIS_H2D()
+            //RtlZeroMemory(&(AtaReq->ahci.ahci_cmd_ptr->cfis), sizeof(AtaReq->ahci_cmd0.cfis)); 
+            RtlCopyMemory(&(AtaReq->ahci.ahci_cmd_ptr->acmd), Srb->Cdb, Srb->CdbLength);
+
+            fis_size = UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
+                   &(AtaReq->ahci.ahci_cmd_ptr->cfis[0]),
+                    IDE_COMMAND_ATAPI_PACKET /* command */,
+                    0 /* lba */,
+                    (Srb->DataTransferLength >= 0x10000) ? (USHORT)(0xffff) : (USHORT)(Srb->DataTransferLength),
+                    FeatureReg/* feature */
+                    );
+
+            if(!fis_size) {
+                KdPrint3((PRINT_PREFIX "AtapiSendCommand: AHCI !FIS\n"));
+                return SRB_STATUS_ERROR;
+            }
+
+            AtaReq->ahci.io_cmd_flags = UniAtaAhciAdjustIoFlags(0,
+                ((Srb->DataTransferLength && (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)) ? ATA_AHCI_CMD_WRITE : 0) |
+                (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH),
+                fis_size, DeviceNumber);
 
-            AtaReq->ahci.io_cmd_flags = (USHORT)(((AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE) |
-                                     /*((LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) |*/
-                                     (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) |
-                                     (fis_size / sizeof(ULONG)) |
-                                     (DeviceNumber << 12));
             KdPrint2((PRINT_PREFIX "AtapiSendCommand ahci io flags %x: \n", AtaReq->ahci.io_cmd_flags));
         }
     
@@ -6382,16 +7760,16 @@ call_dma_setup:
         KdPrint2((PRINT_PREFIX "AtapiSendCommand: !CMD_ACTION_EXEC => SRB_STATUS_PENDING\n"));
         return SRB_STATUS_PENDING;
     }
-    KdPrint3((PRINT_PREFIX "AtapiSendCommand: use_dma=%d\n", use_dma));
+    KdPrint3((PRINT_PREFIX "AtapiSendCommand: use_dma=%d, Cmd %x\n", use_dma, Srb->Cdb[0]));
     if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) {
         KdPrint2((PRINT_PREFIX "  REQ_FLAG_DMA_OPERATION\n"));
     }
 
-    if(Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
+    if((Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) && !(deviceExtension->HwFlags & UNIATA_SATA)) {
         KdPrint2((PRINT_PREFIX "AtapiSendCommand: SCSIOP_REQUEST_SENSE -> no dma setup (2)\n"));
         use_dma = FALSE;
         AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
-        //AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
+        AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
     } if(AtaReq->TransferLength) {
         if(!dma_reinited) {
             KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit()\n"));
@@ -6408,7 +7786,7 @@ call_dma_setup:
         KdPrint2((PRINT_PREFIX "AtapiSendCommand: zero transfer\n"));
         use_dma = FALSE;
         AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
-        if(!deviceExtension->opt_AtapiDmaZeroTransfer) {
+        if(!deviceExtension->opt_AtapiDmaZeroTransfer && !(deviceExtension->HwFlags & UNIATA_SATA)) {
             KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit() to PIO\n"));
             AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
         }
@@ -6420,47 +7798,8 @@ call_dma_setup:
     
     KdPrint2((PRINT_PREFIX "AtapiSendCommand: CMD_ACTION_EXEC\n"));
 
-#ifndef UNIATA_CORE
-    // 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.
-
-    if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED) &&
-        !AtaReq->OriginalSrb) {
-
-        ULONG srbStatus;
-
-        KdPrint3((PRINT_PREFIX "AtapiSendCommand: BuildMechanismStatusSrb()\n"));
-        // Set this flag now. If the device hangs on the mech. status
-        // command, we will not have the chance to set it.
-        LunExt->DeviceFlags |= DFLAGS_CHANGER_INITED;
-
-        chan->MechStatusRetryCount = 3;
-        AtaReq->OriginalSrb = Srb;
-        AtaReq->Srb = BuildMechanismStatusSrb (
-                                        HwDeviceExtension,
-                                        Srb);
-
-        KdPrint3((PRINT_PREFIX "AtapiSendCommand: AtapiSendCommand recursive\n"));
-        srbStatus = AtapiSendCommand(HwDeviceExtension, AtaReq->Srb, CMD_ACTION_ALL);
-        if (srbStatus == SRB_STATUS_PENDING) {
-            KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_PENDING (2)\n"));
-            return srbStatus;
-        } else {
-            AtaReq->Srb = AtaReq->OriginalSrb;
-            AtaReq->OriginalSrb = NULL;
-            KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiHwInitializeChanger()\n"));
-            AtapiHwInitializeChanger (HwDeviceExtension, Srb,
-                                      (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
-            // fall out
-        }
-    }
-#endif //UNIATA_CORE
-
-    KdPrint3((PRINT_PREFIX "AtapiSendCommand: Command %#x to TargetId %d lun %d\n",
-               Srb->Cdb[0], Srb->TargetId, Srb->Lun));
+    KdPrint3((PRINT_PREFIX "AtapiSendCommand: Cdb %x Command %#x to TargetId %d lun %d\n",
+               &(Srb->Cdb), Srb->Cdb[0], Srb->TargetId, Srb->Lun));
     
     // Make sure command is to ATAPI device.
     flags = LunExt->DeviceFlags;
@@ -6481,25 +7820,14 @@ call_dma_setup:
         return SRB_STATUS_SELECTION_TIMEOUT;
     }
 retry:
-    if(deviceExtension->HwFlags & UNIATA_AHCI) {
-        KdPrint2((PRINT_PREFIX "AtapiSendCommand: AHCI, begin transaction\n"));
-        if(use_dma) {
-            chan->ChannelCtrlFlags |= CTRFLAGS_DMA_OPERATION;
-        } else {
-            chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
-        }
-        UniataAhciBeginTransaction(HwDeviceExtension, DeviceNumber, lChannel, Srb);
-        return SRB_STATUS_PENDING;
-    }
-
-    // Select device 0 or 1.
+    // Select device 0 or 1. Or more for PM
     SelectDrive(chan, DeviceNumber);
 
     // Verify that controller is ready for next command.
     GetStatus(chan, statusByte);
     KdPrint3((PRINT_PREFIX "AtapiSendCommand: Entered with status %#x\n", statusByte));
 
-    if(statusByte == 0xff) {
+    if(statusByte == IDE_STATUS_WRONG) {
         KdPrint2((PRINT_PREFIX "AtapiSendCommand: bad status 0xff on entry\n"));
         goto make_reset;
     }
@@ -6513,6 +7841,16 @@ retry:
             goto make_reset;
         }
     }
+    if(deviceExtension->HwFlags & UNIATA_AHCI) {
+        ULONG CI;
+        // Check if command list is free
+        CI = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CI);
+        if(CI) {
+            // controller is busy, however we expect it to be free
+            KdPrint2((PRINT_PREFIX "AtapiSendCommand: Controller busy (CI=%#x) -> reset\n", CI));
+            goto make_reset;
+        }
+    }
     if(statusByte & IDE_STATUS_ERROR) {
         if (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE) {
 
@@ -6548,6 +7886,8 @@ retry:
         // Try to drain the data that one preliminary device thinks that it has
         // to transfer. Hopefully this random assertion of DRQ will not be present
         // in production devices.
+        statusByte = AtapiSuckPort2(chan);
+/*
         for (i = 0; i < 0x10000; i++) {
             GetStatus(chan, statusByte);
             if(statusByte & IDE_STATUS_DRQ) {
@@ -6556,11 +7896,10 @@ retry:
                 break;
             }
         }
-
-        if (i == 0x10000) {
+*/
+        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);
@@ -6575,7 +7914,7 @@ make_reset:
             // Inform the port driver that the bus has been reset.
             ScsiPortNotification(ResetDetected, HwDeviceExtension, 0);
             // Clean up device extension fields that AtapiStartIo won't.
-            chan->ExpectingInterrupt = FALSE;
+            UniataExpectChannelInterrupt(chan, FALSE);
             chan->RDP = FALSE;
             InterlockedExchange(&(deviceExtension->chan[GET_CHANNEL(Srb)].CheckIntr),
                                           CHECK_INTR_IDLE);
@@ -6613,70 +7952,91 @@ make_reset:
         chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
     }
 
+    if(deviceExtension->HwFlags & UNIATA_AHCI) {
+        KdPrint2((PRINT_PREFIX "AtapiSendCommand: AHCI, begin transaction\n"));
+        //AtaReq->Flags = ~REQ_FLAG_DMA_OPERATION; // keep proped DMA flag for proper RETRY handling
+        UniataExpectChannelInterrupt(chan, TRUE);
+        UniataAhciBeginTransaction(HwDeviceExtension, lChannel, DeviceNumber, Srb);
+        return SRB_STATUS_PENDING;
+    }
+
     statusByte = WaitOnBusy(chan);
     KdPrint3((PRINT_PREFIX "AtapiSendCommand: Entry Status (%#x)\n",
                statusByte));
 
-    AtapiWritePort1(chan, IDX_IO1_o_Feature,
-                            use_dma ? ATA_F_DMA : 0);
+    if(use_dma) {
+        FeatureReg |= ATA_F_DMA;
+        if(LunExt->IdentifyData.AtapiDMA.DMADirRequired) {
+            if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+                FeatureReg |= ATA_F_DMAREAD;
+            }
+        }
+    }
 
     // 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));
 
-        chan->ExpectingInterrupt = TRUE;
+        UniataExpectChannelInterrupt(chan, TRUE);
         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));
-
-    chan->ExpectingInterrupt = 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;
     }
 
-    // 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);
         }
@@ -6684,34 +8044,112 @@ 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.
-    chan->ExpectingInterrupt = TRUE;
-    InterlockedExchange(&(chan->CheckIntr),
-                                  CHECK_INTR_IDLE);
-    AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
+    UniataExpectChannelInterrupt(chan, TRUE);
 
+    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,
-                6,
-                0);
+                LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
+                /*0*/ PIO0_TIMING);
+
+    GetStatus(chan, statusByte);
+    KdPrint3((PRINT_PREFIX "AtapiSendCommand: cmd status (%#x)\n", statusByte));
+
+    // 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) {
+
+        GetBaseStatus(chan, statusByte);
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: Error on cmd: (%#x)\n", statusByte));
+
+        interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: iReason %x\n", interruptReason));
+
+        // TODO:  we should check interruptReason and decide what to do now
+
+        // Read the error reg. to clear it and fail this request.
+        AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
+        return MapError(deviceExtension, Srb);
+    }
+    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));
+        if(statusByte >> 4) {
+            GetBaseStatus(chan, statusByte);
+            AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
+            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"));
@@ -6760,16 +8198,20 @@ IdeSendCommand(
     UCHAR                lChannel;
     PHW_CHANNEL          chan;
     PCDB cdb;
+    PHW_LU_EXTENSION     LunExt;
 
     SetCheckPoint(4);
 
     UCHAR statusByte,errorByte;
-    ULONG status;
+    ULONG status = SRB_STATUS_INVALID_REQUEST;
     ULONG i;
+    ULONGLONG lba;
     PMODE_PARAMETER_HEADER   modeData;
     //ULONG ldev;
     ULONG DeviceNumber;
     PATA_REQ AtaReq;
+    UCHAR command;
+
     SetCheckPoint(5);
     //ULONG __ebp__ = 0;
 
@@ -6803,25 +8245,39 @@ IdeSendCommand(
     chan = &(deviceExtension->chan[lChannel]);
     //ldev = GET_LDEV(Srb);
     DeviceNumber = GET_CDEV(Srb);
+    LunExt = chan->lun[DeviceNumber];
 
     SetCheckPoint(0x40);
     if(AtaReq->ReqState < REQ_STATE_PREPARE_TO_TRANSFER)
         AtaReq->ReqState = REQ_STATE_PREPARE_TO_TRANSFER;
 
+    cdb = (PCDB)(Srb->Cdb);
+
     if(CmdAction == CMD_ACTION_PREPARE) {
         switch (Srb->Cdb[0]) {
+        case SCSIOP_SERVICE_ACTION16:
+            if( cdb->SERVICE_ACTION16.ServiceAction==SCSIOP_SA_READ_CAPACITY16 ) {
+                // ok
+            } else {
+                goto default_no_prep;
+            }
 #ifdef NAVO_TEST
         case SCSIOP_INQUIRY: // now it requires device access
 #endif //NAVO_TEST
         case SCSIOP_READ_CAPACITY:
         case SCSIOP_READ:
         case SCSIOP_WRITE:
+        case SCSIOP_READ12:
+        case SCSIOP_WRITE12:
+        case SCSIOP_READ16:
+        case SCSIOP_WRITE16:
         case SCSIOP_REQUEST_SENSE:
             // all right
             KdPrint2((PRINT_PREFIX "** Ide: Command continue prep\n"));
             SetCheckPoint(50);
             break;
         default:
+default_no_prep:
             SetCheckPoint(0);
             KdPrint2((PRINT_PREFIX "** Ide: Command break prep\n"));
             return SRB_STATUS_BUSY;
@@ -6835,11 +8291,10 @@ IdeSendCommand(
         KdPrint2((PRINT_PREFIX 
                    "IdeSendCommand: SCSIOP_INQUIRY PATH:LUN:TID = %#x:%#x:%#x\n",
                    Srb->PathId, Srb->Lun, Srb->TargetId));
-        // Filter out all TIDs but 0 and 1 since this is an IDE interface
-        // which support up to two devices.
+        // Filter out wrong TIDs.
         if ((Srb->Lun != 0) ||
             (Srb->PathId >= deviceExtension->NumberChannels) ||
-            (Srb->TargetId > deviceExtension->NumberLuns)) {
+            (Srb->TargetId >= deviceExtension->NumberLuns)) {
 
             KdPrint2((PRINT_PREFIX 
                        "IdeSendCommand: SCSIOP_INQUIRY rejected\n"));
@@ -6852,7 +8307,7 @@ IdeSendCommand(
             KdPrint2((PRINT_PREFIX 
                        "IdeSendCommand: SCSIOP_INQUIRY ok\n"));
             PINQUIRYDATA    inquiryData  = (PINQUIRYDATA)(Srb->DataBuffer);
-            PIDENTIFY_DATA2 identifyData = &(chan->lun[DeviceNumber]->IdentifyData);
+            PIDENTIFY_DATA2 identifyData = &(LunExt->IdentifyData);
 
             if (!(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
                 
@@ -6883,13 +8338,13 @@ IdeSendCommand(
             inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
 
             // Set the removable bit, if applicable.
-            if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_REMOVABLE_DRIVE) {
+            if (LunExt->DeviceFlags & DFLAGS_REMOVABLE_DRIVE) {
                 KdPrint2((PRINT_PREFIX 
                            "RemovableMedia\n"));
                 inquiryData->RemovableMedia = 1;
             }
             // Set the Relative Addressing (LBA) bit, if applicable.
-            if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_LBA_ENABLED) {
+            if (LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
                 inquiryData->RelativeAddressing = 1;
                 KdPrint2((PRINT_PREFIX 
                            "RelativeAddressing\n"));
@@ -6899,7 +8354,7 @@ IdeSendCommand(
 
             // Fill in vendor identification fields.
             for (i = 0; i < 24; i += 2) {
-                MOV_DW_SWP(inquiryData->VendorId[i], ((PUCHAR)identifyData->ModelNumber)[i]);
+                MOV_DW_SWP(inquiryData->DeviceIdentificationString[i], ((PUCHAR)identifyData->ModelNumber)[i]);
             }
 /*
             // Initialize unused portion of product id.
@@ -6918,24 +8373,90 @@ IdeSendCommand(
 
         break;
 
+    case SCSIOP_REPORT_LUNS: {
+
+        ULONG alen;
+        PREPORT_LUNS_INFO_HDR LunInfo;
+        
+        KdPrint2((PRINT_PREFIX 
+                   "IdeSendCommand: SCSIOP_REPORT_LUNS PATH:LUN:TID = %#x:%#x:%#x\n",
+                   Srb->PathId, Srb->Lun, Srb->TargetId));
+
+        MOV_DD_SWP(alen, cdb->REPORT_LUNS.AllocationLength);
+
+        if(alen < 16) {
+            goto invalid_cdb;
+        }
+        alen = 8;
+
+        LunInfo = (PREPORT_LUNS_INFO_HDR)(Srb->DataBuffer);
+        RtlZeroMemory(LunInfo, 16);
+
+        MOV_DD_SWP( LunInfo->ListLength, alen );
+        Srb->DataTransferLength = 16;
+        status = SRB_STATUS_SUCCESS;
+
+        break; }
+
     case SCSIOP_MODE_SENSE:
 
         KdPrint2((PRINT_PREFIX 
                    "IdeSendCommand: SCSIOP_MODE_SENSE PATH:LUN:TID = %#x:%#x:%#x\n",
                    Srb->PathId, Srb->Lun, Srb->TargetId));
-        // This is used to determine if the media is write-protected.
-        // Since IDE does not support mode sense then we will modify just the portion we need
-        // so the higher level driver can determine if media is protected.
-        if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
+        
+        if(cdb->MODE_SENSE.PageCode == MODE_PAGE_POWER_CONDITION) {
+            PMODE_POWER_CONDITION_PAGE modeData;
 
-            SelectDrive(chan, DeviceNumber);
-            AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS);
-            statusByte = WaitOnBusy(chan);
+            KdPrint2((PRINT_PREFIX "MODE_PAGE_POWER_CONDITION\n"));
+            modeData = (PMODE_POWER_CONDITION_PAGE)(Srb->DataBuffer);
+            if(cdb->MODE_SENSE.AllocationLength < sizeof(MODE_POWER_CONDITION_PAGE)) {
+                status = SRB_STATUS_DATA_OVERRUN;
+            } 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);
+                status = SRB_STATUS_SUCCESS;
+            }
+        } else
+        if(cdb->MODE_SENSE.PageCode == MODE_PAGE_CACHING) {
+            PMODE_CACHING_PAGE modeData;
 
-            if (!(statusByte & IDE_STATUS_ERROR)){
+            KdPrint2((PRINT_PREFIX "MODE_PAGE_CACHING\n"));
+            modeData = (PMODE_CACHING_PAGE)(Srb->DataBuffer);
+            if(cdb->MODE_SENSE.AllocationLength < sizeof(MODE_CACHING_PAGE)) {
+                status = SRB_STATUS_DATA_OVERRUN;
+            } else {
+                RtlZeroMemory(modeData, sizeof(MODE_CACHING_PAGE));
+                modeData->PageCode = MODE_PAGE_CACHING;
+                modeData->PageLength = sizeof(MODE_CACHING_PAGE)-sizeof(MODE_PARAMETER_HEADER);
+                modeData->ReadDisableCache = (LunExt->DeviceFlags & DFLAGS_RCACHE_ENABLED) ? 0 : 1;
+                modeData->WriteCacheEnable = (LunExt->DeviceFlags & DFLAGS_WCACHE_ENABLED) ? 1 : 0;
+                Srb->DataTransferLength = sizeof(MODE_CACHING_PAGE);
+                status = SRB_STATUS_SUCCESS;
+            }
+        } else
+        if (LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
+
+            // This is used to determine if the media is write-protected.
+            // Since IDE does not support mode sense then we will modify just the portion we need
+            // so the higher level driver can determine if media is protected.
+
+            //SelectDrive(chan, DeviceNumber);
+            //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS);
+            //statusByte = WaitOnBusy(chan);
+            statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_GET_MEDIA_STATUS, 0, 0, 0, 0, 0, ATA_WAIT_READY);
+
+            if (!(statusByte & IDE_STATUS_ERROR)) {
 
                 // no error occured return success, media is not protected
-                chan->ExpectingInterrupt = FALSE;
+                UniataExpectChannelInterrupt(chan, FALSE);
                 InterlockedExchange(&(chan->CheckIntr),
                                               CHECK_INTR_IDLE);
                 status = SRB_STATUS_SUCCESS;
@@ -6946,7 +8467,7 @@ IdeSendCommand(
                 errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
 
                 GetBaseStatus(chan, statusByte);
-                chan->ExpectingInterrupt = FALSE;
+                UniataExpectChannelInterrupt(chan, FALSE);
                 InterlockedExchange(&(chan->CheckIntr),
                                               CHECK_INTR_IDLE);
                 status = SRB_STATUS_SUCCESS;
@@ -6974,14 +8495,14 @@ IdeSendCommand(
         if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
 
             // Select device 0 or 1.
-            SelectDrive(chan, DeviceNumber);
-            AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS);
-
+            //SelectDrive(chan, DeviceNumber);
+            //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS);
             // Wait for busy. If media has not changed, return success
-            statusByte = WaitOnBusy(chan);
+            //statusByte = WaitOnBusy(chan);
+            statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_GET_MEDIA_STATUS, 0, 0, 0, 0, 0, ATA_WAIT_READY);
 
             if (!(statusByte & IDE_STATUS_ERROR)){
-                chan->ExpectingInterrupt = FALSE;
+                UniataExpectChannelInterrupt(chan, FALSE);
                 InterlockedExchange(&(chan->CheckIntr),
                                               CHECK_INTR_IDLE);
                 status = SRB_STATUS_SUCCESS;
@@ -6993,7 +8514,7 @@ IdeSendCommand(
                     // the 0xDA command will always fail since the write-protect bit
                     // is sticky,so we can ignore this error
                     GetBaseStatus(chan, statusByte);
-                    chan->ExpectingInterrupt = FALSE;
+                    UniataExpectChannelInterrupt(chan, FALSE);
                     InterlockedExchange(&(chan->CheckIntr),
                                                   CHECK_INTR_IDLE);
                     status = SRB_STATUS_SUCCESS;
@@ -7001,7 +8522,7 @@ IdeSendCommand(
                 } else {
 
                     // Request sense buffer to be build
-                    chan->ExpectingInterrupt = TRUE;
+                    UniataExpectChannelInterrupt(chan, TRUE);
                     InterlockedExchange(&(chan->CheckIntr),
                                                   CHECK_INTR_IDLE);
                     status = SRB_STATUS_PENDING;
@@ -7021,13 +8542,14 @@ IdeSendCommand(
         // Claim 512 byte blocks (big-endian).
         //((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock = 0x20000;
         i = DEV_BSIZE;
+        RtlZeroMemory(Srb->DataBuffer, sizeof(READ_CAPACITY_DATA));
         MOV_DD_SWP( ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock, i );
 
         // Calculate last sector.
-        if(!(i = (ULONG)chan->lun[DeviceNumber]->NumOfSectors)) {
-            i = chan->lun[DeviceNumber]->IdentifyData.SectorsPerTrack *
-                chan->lun[DeviceNumber]->IdentifyData.NumberOfHeads *
-                chan->lun[DeviceNumber]->IdentifyData.NumberOfCylinders;
+        if(!(i = (ULONG)LunExt->NumOfSectors)) {
+            i = LunExt->IdentifyData.SectorsPerTrack *
+                LunExt->IdentifyData.NumberOfHeads *
+                LunExt->IdentifyData.NumberOfCylinders;
         }
         i--;
 
@@ -7040,15 +8562,51 @@ IdeSendCommand(
         KdPrint2((PRINT_PREFIX 
                    "** IDE disk %#x - #sectors %#x, #heads %#x, #cylinders %#x\n",
                    Srb->TargetId,
-                   chan->lun[DeviceNumber]->IdentifyData.SectorsPerTrack,
-                   chan->lun[DeviceNumber]->IdentifyData.NumberOfHeads,
-                   chan->lun[DeviceNumber]->IdentifyData.NumberOfCylinders));
+                   LunExt->IdentifyData.SectorsPerTrack,
+                   LunExt->IdentifyData.NumberOfHeads,
+                   LunExt->IdentifyData.NumberOfCylinders));
 
 
         status = SRB_STATUS_SUCCESS;
         break;
 
+    case SCSIOP_SERVICE_ACTION16:
+
+        if( cdb->SERVICE_ACTION16.ServiceAction==SCSIOP_SA_READ_CAPACITY16 ) {
+            KdPrint2((PRINT_PREFIX 
+                       "** IdeSendCommand: SCSIOP_READ_CAPACITY PATH:LUN:TID = %#x:%#x:%#x\n",
+                       Srb->PathId, Srb->Lun, Srb->TargetId));
+            // Claim 512 byte blocks (big-endian).
+            //((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock = 0x20000;
+            i = DEV_BSIZE;
+            RtlZeroMemory(Srb->DataBuffer, sizeof(READ_CAPACITY16_DATA));
+            MOV_DD_SWP( ((PREAD_CAPACITY16_DATA)Srb->DataBuffer)->BytesPerBlock, i );
+
+            // Calculate last sector.
+            if(!(lba = LunExt->NumOfSectors)) {
+                lba = LunExt->IdentifyData.SectorsPerTrack *
+                    LunExt->IdentifyData.NumberOfHeads *
+                    LunExt->IdentifyData.NumberOfCylinders;
+            }
+            lba--;
+            MOV_QD_SWP( ((PREAD_CAPACITY16_DATA)Srb->DataBuffer)->LogicalBlockAddress, lba );
+
+            KdPrint2((PRINT_PREFIX 
+                       "** IDE disk %#x - #sectors %#x, #heads %#x, #cylinders %#x (16)\n",
+                       Srb->TargetId,
+                       LunExt->IdentifyData.SectorsPerTrack,
+                       LunExt->IdentifyData.NumberOfHeads,
+                       LunExt->IdentifyData.NumberOfCylinders));
+
+            status = SRB_STATUS_SUCCESS;
+        } else {
+            goto default_abort;
+        }
+        break;
+
     case SCSIOP_VERIFY:
+    case SCSIOP_VERIFY12:
+    case SCSIOP_VERIFY16:
 
         KdPrint2((PRINT_PREFIX 
                    "IdeSendCommand: SCSIOP_VERIFY PATH:LUN:TID = %#x:%#x:%#x\n",
@@ -7059,13 +8617,19 @@ IdeSendCommand(
 
     case SCSIOP_READ:
     case SCSIOP_WRITE:
+    case SCSIOP_READ12:
+    case SCSIOP_WRITE12:
+    case SCSIOP_READ16:
+    case SCSIOP_WRITE16:
 
         KdPrint2((PRINT_PREFIX 
                    "IdeSendCommand: SCSIOP_%s PATH:LUN:TID = %#x:%#x:%#x\n",
                    (Srb->Cdb[0] == SCSIOP_WRITE) ? "WRITE" : "READ",
                    Srb->PathId, Srb->Lun, Srb->TargetId));
         AtaReq->Flags &= ~REQ_FLAG_RW_MASK;
-        AtaReq->Flags |= (Srb->Cdb[0] == SCSIOP_WRITE) ? REQ_FLAG_WRITE : REQ_FLAG_READ;
+        AtaReq->Flags |= (Srb->Cdb[0] == SCSIOP_WRITE ||
+                          Srb->Cdb[0] == SCSIOP_WRITE12 ||
+                          Srb->Cdb[0] == SCSIOP_WRITE16) ? REQ_FLAG_WRITE : REQ_FLAG_READ;
         status = IdeReadWrite(HwDeviceExtension,
                               Srb, CmdAction);
         break;
@@ -7073,42 +8637,125 @@ IdeSendCommand(
     case SCSIOP_START_STOP_UNIT:
 
         KdPrint2((PRINT_PREFIX 
-                   "IdeSendCommand: SCSIOP_START_STOP_UNIT PATH:LUN:TID = %#x:%#x:%#x\n",
-                   Srb->PathId, Srb->Lun, Srb->TargetId));
+                   "IdeSendCommand: SCSIOP_START_STOP_UNIT immed %d PATH:LUN:TID = %#x:%#x:%#x\n",
+                   cdb->START_STOP.Immediate, Srb->PathId, Srb->Lun, Srb->TargetId));
         //Determine what type of operation we should perform
-        cdb = (PCDB)Srb->Cdb;
 
-        if (cdb->START_STOP.LoadEject == 1){
+        command = 0;
 
-            statusByte = WaitOnBaseBusy(chan);
+        if(cdb->START_STOP.FL ||
+           cdb->START_STOP.FormatLayerNumber ||
+           cdb->START_STOP.Reserved2 ||
+           cdb->START_STOP.Reserved2_2 ||
+           cdb->START_STOP.Reserved3 ||
+           FALSE) {
+            goto invalid_cdb;
+        }
+
+        if (cdb->START_STOP.PowerConditions) {
+            KdPrint2((PRINT_PREFIX "START_STOP Power %d\n", cdb->START_STOP.PowerConditions));
+            switch(cdb->START_STOP.PowerConditions) {
+            case StartStop_Power_Idle:
+                command = IDE_COMMAND_IDLE_IMMED;
+                break;
+            case StartStop_Power_Standby:
+                command = IDE_COMMAND_STANDBY_IMMED;
+                break;
+            case StartStop_Power_Sleep:
+                // TODO: we should save power state in order to know
+                // that RESET sould be issued to revert device into
+                // operable state
+
+                command = IDE_COMMAND_SLEEP;
+                break;
+            default:
+                goto invalid_cdb;
+            }
+            LunExt->PowerState = cdb->START_STOP.PowerConditions;
+        } else
+        if (cdb->START_STOP.LoadEject == 1) {
+            KdPrint2((PRINT_PREFIX "START_STOP eject\n"));
             // Eject media,
             // first select device 0 or 1.
-            SelectDrive(chan, DeviceNumber);
-            AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_MEDIA_EJECT);
+            //SelectDrive(chan, DeviceNumber);
+            //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_MEDIA_EJECT);
+            command = IDE_COMMAND_MEDIA_EJECT;
+        } else
+        if (cdb->START_STOP.Start == 0) {
+            KdPrint2((PRINT_PREFIX "START_STOP standby\n"));
+            command = IDE_COMMAND_STANDBY_IMMED;
+        } else {
+            // TODO: we may need to perform hard reset (after sleep) or
+            // issue IDE_COMMAND_IDLE_IMMED in order to activate device
+            KdPrint2((PRINT_PREFIX "START_STOP activate\n"));
+
+            if(LunExt->PowerState == StartStop_Power_Sleep) {
+                UniataUserDeviceReset(deviceExtension, LunExt, lChannel);
+                status = SRB_STATUS_SUCCESS;
+                break;
+            } else
+            if(LunExt->PowerState > StartStop_Power_Idle) {
+                KdPrint2((PRINT_PREFIX "  issue IDLE\n"));
+                command = IDE_COMMAND_IDLE_IMMED;
+            } else {
+                KdPrint2((PRINT_PREFIX "  do nothing\n"));
+                status = SRB_STATUS_SUCCESS;
+                break;
+            }
+        }
+        if(command) {
+            statusByte = WaitOnBaseBusy(chan);
+            statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, command, 0, 0, 0, 0, 0, 
+                cdb->START_STOP.Immediate ? ATA_IMMEDIATE : ATA_WAIT_READY);
+            status = (statusByte & IDE_STATUS_ERROR) ? SRB_STATUS_ERROR : SRB_STATUS_SUCCESS;
+            //UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
+
+        } else {
+invalid_cdb:
+            KdPrint2((PRINT_PREFIX "START_STOP invalid\n"));
+            if (Srb->SenseInfoBuffer) {
+
+                PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
+
+                senseBuffer->ErrorCode = 0x70;
+                senseBuffer->Valid     = 1;
+                senseBuffer->AdditionalSenseLength = 0xb;
+                senseBuffer->SenseKey = SCSI_SENSE_ILLEGAL_REQUEST;
+                senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_INVALID_CDB;
+                senseBuffer->AdditionalSenseCodeQualifier = 0;
+
+                Srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID;
+                Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+            }
+            status = SRB_STATUS_ERROR;
         }
-        status = SRB_STATUS_SUCCESS;
         break;
 
     case SCSIOP_MEDIUM_REMOVAL:
 
-       cdb = (PCDB)Srb->Cdb;
+        cdb = (PCDB)Srb->Cdb;
 
-       statusByte = WaitOnBaseBusy(chan);
+        if(LunExt->IdentifyData.Removable) {
+            statusByte = WaitOnBaseBusy(chan);
 
-       SelectDrive(chan, DeviceNumber);
-       if (cdb->MEDIA_REMOVAL.Prevent == TRUE) {
-           AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_LOCK);
-       } else {
-           AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_UNLOCK);
-       }
-       status = SRB_STATUS_SUCCESS;
-       break;
+            //SelectDrive(chan, DeviceNumber);
+            if (cdb->MEDIA_REMOVAL.Prevent == TRUE) {
+                //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_LOCK);
+                statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_DOOR_LOCK, 0, 0, 0, 0, 0, ATA_IMMEDIATE);
+            } else {
+                //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_UNLOCK);
+                statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_DOOR_UNLOCK, 0, 0, 0, 0, 0, ATA_IMMEDIATE);
+            }
+            status = SRB_STATUS_SUCCESS;
+        } else {
+            status = SRB_STATUS_INVALID_REQUEST;
+        }
+        break;
 
+#if 0
     // Note: I don't implement this, because NTFS driver too often issues this command
     // It causes awful performance degrade. However, if somebody wants, I will implement
     // SCSIOP_FLUSH_BUFFER/SCSIOP_SYNCHRONIZE_CACHE optionally.
-
-#if 0
     case SCSIOP_FLUSH_BUFFER:
     case SCSIOP_SYNCHRONIZE_CACHE:
 
@@ -7127,7 +8774,7 @@ IdeSendCommand(
         KdPrint2((PRINT_PREFIX 
                    "IdeSendCommand: SCSIOP_REQUEST_SENSE PATH:LUN:TID = %#x:%#x:%#x\n",
                    Srb->PathId, Srb->Lun, Srb->TargetId));
-        if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
+        if (LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
             status = IdeBuildSenseBuffer(HwDeviceExtension,Srb);
             break;
         }
@@ -7143,25 +8790,59 @@ IdeSendCommand(
         
         regs = (PIDEREGS_EX) &(Srb->Cdb[2]);
 
-        lChannel = Srb->TargetId >> 1;
-
-        regs->bDriveHeadReg &= 0x0f;
-        regs->bDriveHeadReg |= (UCHAR) (((Srb->TargetId & 0x1) << 4) | 0xA0);
+        if(chan->DeviceExtension->HwFlags & UNIATA_SATA) {
+            //lChannel = Srb->TargetId >> 1;
+        } else {
+            DeviceNumber = max(DeviceNumber, 1);
+            regs->bDriveHeadReg &= 0x0f;
+            regs->bDriveHeadReg |= (UCHAR) (((DeviceNumber & 0x1) << 4) | 0xA0);
+        }
 
         if((regs->bOpFlags & 1) == 0) {      // execute ATA command
 
             KdPrint2((PRINT_PREFIX 
-                       "IdeSendCommand: SCSIOP_START_STOP_UNIT PATH:LUN:TID = %#x:%#x:%#x\n",
+                       "IdeSendCommand: SCSIOP_ATA_PASSTHROUGH (exec) PATH:LUN:TID = %#x:%#x:%#x\n",
                        Srb->PathId, Srb->Lun, Srb->TargetId));
 
+            if((regs->bOpFlags & UNIATA_SPTI_EX_SPEC_TO) == UNIATA_SPTI_EX_SPEC_TO) {
+                to_lim = Srb->TimeOutValue;
+            } else {
+                if(Srb->TimeOutValue <= 2) {
+                    to_lim = Srb->TimeOutValue*900;
+                } else {
+                    to_lim = (Srb->TimeOutValue*999) - 500;
+                }
+            }
 
             AtapiDisableInterrupts(deviceExtension, lChannel);
 
+            if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
+                // AHCI
+                statusByte = UniataAhciSendPIOCommandDirect(
+                        deviceExtension,
+                        lChannel,
+                        DeviceNumber,
+                        Srb,
+                        regs,
+                        ATA_WAIT_INTR,
+                        to_lim
+                        );
+                if(statusByte == IDE_STATUS_WRONG) {
+                    goto passthrough_err;
+                }
+                if(statusByte & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) {
+                    UniataAhciAbortOperation(chan);
+                    goto passthrough_err;
+                }
+                goto passthrough_done;
+            }
+
+            // SATA/PATA
             if((AtaCommandFlags[regs->bCommandReg] & ATA_CMD_FLAG_DMA) || (regs->bOpFlags & UNIATA_SPTI_EX_USE_DMA)) {
-                if((chan->lun[Srb->TargetId & 0x1]->LimitedTransferMode >= ATA_DMA)) {
+                if((chan->lun[DeviceNumber]->LimitedTransferMode >= ATA_DMA)) {
                     use_dma = TRUE;
                     // this will set REQ_FLAG_DMA_OPERATION in AtaReq->Flags on success
-                    if(!AtapiDmaSetup(HwDeviceExtension, Srb->TargetId & 0x1, lChannel, Srb,
+                    if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
                                   (PUCHAR)(Srb->DataBuffer),
                                   ((Srb->DataTransferLength + DEV_BSIZE-1) & ~(DEV_BSIZE-1)))) {
                         use_dma = FALSE;
@@ -7169,8 +8850,11 @@ IdeSendCommand(
                 }
             }
 
-            AtapiWritePort1(chan, IDX_IO1_o_DriveSelect,  regs->bDriveHeadReg);
+            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);
@@ -7197,20 +8881,11 @@ IdeSendCommand(
                 if(statusByte & IDE_STATUS_ERROR) {
                     goto passthrough_err;
                 }
-                AtapiDmaStart(HwDeviceExtension, (Srb->TargetId & 0x1), lChannel, Srb);
+                AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
             }
 
             ScsiPortStallExecution(1);                  // wait for busy to be set
 
-            if(regs->bOpFlags & UNIATA_SPTI_EX_SPEC_TO) {
-                to_lim = Srb->TimeOutValue;
-            } else {
-                if(Srb->TimeOutValue <= 2) {
-                    to_lim = Srb->TimeOutValue*900;
-                } else {
-                    to_lim = (Srb->TimeOutValue*999) - 500;
-                }
-            }
             for(i=0; i<to_lim;i+=2) {      // 2 msec from WaitOnBaseBusy()
                 statusByte = WaitOnBaseBusy(chan);      // wait for busy to be clear, up to 2 msec
                 GetBaseStatus(chan, statusByte);
@@ -7231,7 +8906,7 @@ IdeSendCommand(
             if(use_dma) {
                 AtapiCheckInterrupt__(deviceExtension, (UCHAR)lChannel);
             }
-            AtapiDmaDone(deviceExtension, (Srb->TargetId & 0x1), lChannel, NULL);
+            AtapiDmaDone(deviceExtension, DeviceNumber, lChannel, NULL);
             GetBaseStatus(chan, statusByte);
 
             if(statusByte & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) {
@@ -7271,41 +8946,40 @@ passthrough_err:
                 }
                 status = SRB_STATUS_SUCCESS;
             }
-
+passthrough_done:;
             AtapiEnableInterrupts(deviceExtension, lChannel);
 
         } else { // read task register
 
+            BOOLEAN use48;
             regs = (PIDEREGS_EX) Srb->DataBuffer;
 
-            regs->bDriveHeadReg    = AtapiReadPort1(chan, IDX_IO1_i_DriveSelect);
+            KdPrint2((PRINT_PREFIX 
+                       "IdeSendCommand: SCSIOP_ATA_PASSTHROUGH (snap) PATH:LUN:TID = %#x:%#x:%#x\n",
+                       Srb->PathId, Srb->Lun, Srb->TargetId));
 
-            if((regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) == 0) {      // execute ATA command
-                regs->bFeaturesReg     = AtapiReadPort1(chan, IDX_IO1_i_Error);
-                regs->bSectorCountReg  = AtapiReadPort1(chan, IDX_IO1_i_BlockCount);
-                regs->bSectorNumberReg = AtapiReadPort1(chan, IDX_IO1_i_BlockNumber);
-                regs->bCylLowReg       = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
-                regs->bCylHighReg      = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
+            if((Srb->DataTransferLength >= sizeof(IDEREGS_EX)) &&
+               (regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND)) {
+                use48 = TRUE;
+            } else
+            if(Srb->DataTransferLength >= sizeof(IDEREGS)) {
+                use48 = FALSE;
             } else {
-                regs->bFeaturesReg     = AtapiReadPort1(chan, IDX_IO1_i_Error);
-                regs->bFeaturesRegH    = AtapiReadPort1(chan, IDX_IO1_i_Error);
-                regs->bSectorCountReg  = AtapiReadPort1(chan, IDX_IO1_i_BlockCount);
-                regs->bSectorCountRegH = AtapiReadPort1(chan, IDX_IO1_i_BlockCount);
-                regs->bSectorNumberReg = AtapiReadPort1(chan, IDX_IO1_i_BlockNumber);
-                regs->bSectorNumberRegH= AtapiReadPort1(chan, IDX_IO1_i_BlockNumber);
-                regs->bCylLowReg       = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
-                regs->bCylLowRegH      = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
-                regs->bCylHighReg      = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
-                regs->bCylHighRegH     = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
+                KdPrint2((PRINT_PREFIX " buffer too small \n"));
+                status = SRB_STATUS_DATA_OVERRUN;
+                break;
             }
-            regs->bCommandReg      = AtapiReadPort1(chan, IDX_IO1_i_Status);
+            RtlZeroMemory(regs, use48 ? sizeof(IDEREGS_EX) : sizeof(IDEREGS));
+            regs->bOpFlags = use48 ? ATA_FLAGS_48BIT_COMMAND : 0;
+            UniataSnapAtaRegs(chan, 0, regs);
+
             status = SRB_STATUS_SUCCESS;
         }
         break;
     }
 
     default:
-
+default_abort:
         KdPrint2((PRINT_PREFIX 
                    "IdeSendCommand: Unsupported command %#x\n",
                    Srb->Cdb[0]));
@@ -7353,6 +9027,7 @@ IdeMediaStatus(
     UCHAR statusByte,errorByte;
 
     chan = &(deviceExtension->chan[lChannel]);
+    SelectDrive(chan, DeviceNumber);
 
     if (EnableMSN == TRUE){
 
@@ -7472,23 +9147,24 @@ NTAPI
 UniataUserDeviceReset(
     PHW_DEVICE_EXTENSION deviceExtension,
     PHW_LU_EXTENSION LunExt,
-    ULONG PathId
+    ULONG lChannel
     )
 {
     ULONG i;
-    AtapiDisableInterrupts(deviceExtension, PathId);
-    if (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
+    AtapiDisableInterrupts(deviceExtension, lChannel);
+    if ((LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) &&
+        (LunExt->PowerState != StartStop_Power_Sleep)) {
         KdPrint2((PRINT_PREFIX "UniataUserDeviceReset: Reset ATAPI\n"));
-        AtapiSoftReset(&(deviceExtension->chan[PathId]), LunExt->Lun);
+        AtapiSoftReset(&(deviceExtension->chan[lChannel]), LunExt->Lun);
     } else {
         KdPrint2((PRINT_PREFIX "UniataUserDeviceReset: Reset IDE -> reset entire channel\n"));
-        AtapiResetController__(deviceExtension, PathId, RESET_COMPLETE_NONE);
+        AtapiResetController__(deviceExtension, lChannel, RESET_COMPLETE_NONE);
         for(i=0; i<deviceExtension->NumberLuns; i++) {
-            deviceExtension->chan[PathId].lun[i]->DeviceFlags |= DFLAGS_REINIT_DMA;
+            deviceExtension->chan[lChannel].lun[i]->DeviceFlags |= DFLAGS_REINIT_DMA;
         }
     }
     LunExt->DeviceFlags |= DFLAGS_REINIT_DMA;  // force PIO/DMA reinit
-    AtapiEnableInterrupts(deviceExtension, PathId);
+    AtapiEnableInterrupts(deviceExtension, lChannel);
     return;
 } // end UniataUserDeviceReset()
 
@@ -7534,6 +9210,7 @@ Routine Description:
 
     This routine is called from the SCSI port driver synchronized
     with the kernel to start an IO request.
+    ->HwStartIo
 
 Arguments:
 
@@ -7593,16 +9270,18 @@ AtapiStartIo__(
 */
     if(TopLevel && Srb && Srb->SrbExtension) {
         KdPrint2((PRINT_PREFIX "TopLevel\n"));
-        RtlZeroMemory(Srb->SrbExtension, sizeof(ATA_REQ));
+        //RtlZeroMemory(Srb->SrbExtension, sizeof(ATA_REQ));
+        UniAtaClearAtaReq(Srb->SrbExtension);
     }
 
-    do {
+    do { // fetch all queued commands for the channel (if valid)
 
         lChannel = GET_CHANNEL(Srb);
         //ldev = GET_LDEV(Srb);
         chan = NULL;
         LunExt = NULL;
         DeviceNumber = GET_CDEV(Srb);
+        commPort = FALSE;
 
         //ASSERT(deviceExtension);
         //ASSERT(chan);
@@ -7610,17 +9289,26 @@ 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 &&
            ((Srb->Function == SRB_FUNCTION_IO_CONTROL) ||
             (Srb->Function == SRB_FUNCTION_EXECUTE_SCSI && Srb->Cdb[0] == SCSIOP_INQUIRY))
            ) {
+            // This is our virtual device
             KdPrint2((PRINT_PREFIX 
                        "AtapiStartIo: Communication port\n"));
             if(Srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
 
+                if(Srb->DataTransferLength < sizeof(PINQUIRYDATA)) {
+                    KdPrint2((PRINT_PREFIX "AtapiStartIo: Buffer too small: %#x < %#x\n", Srb->DataTransferLength,
+                        sizeof(PINQUIRYDATA) ));
+wrong_buffer_size:
+                    status = SRB_STATUS_DATA_OVERRUN;
+                    goto complete_req;
+                }
+
                 PINQUIRYDATA    inquiryData  = (PINQUIRYDATA)(Srb->DataBuffer);
 
                 KdPrint2((PRINT_PREFIX 
@@ -7640,22 +9328,26 @@ AtapiStartIo__(
             /* Pass IOCTL request down */
         } else
         if(lChannel >= deviceExtension->NumberChannels ||
-           Srb->TargetId /*DeviceNumber*/ >= deviceExtension->NumberLuns ||
-           Srb->Lun) {
+            Srb->TargetId /*DeviceNumber*/ >= deviceExtension->NumberLuns ||
+            Srb->Lun) {
 
-           if(lChannel >= deviceExtension->NumberChannels) {
-               chan = NULL;
-           }
+            if(lChannel >= deviceExtension->NumberChannels) {
+                chan = NULL;
+            }
 
 reject_srb:
             //if(!CheckDevice(HwDeviceExtension, lChannel, DeviceNumber, FALSE)) {
-                KdPrint3((PRINT_PREFIX 
+            KdPrint3((PRINT_PREFIX 
                            "AtapiStartIo: SRB rejected\n"));
-                // Indicate no device found at this address.
-                KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
-                status = SRB_STATUS_SELECTION_TIMEOUT;
-                goto complete_req;
+            // Indicate no device found at this address.
+            KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
+            status = SRB_STATUS_SELECTION_TIMEOUT;
+            goto complete_req;
             //}
+        } else
+        if((deviceExtension->HwFlags & UNIATA_AHCI) &&
+           !UniataAhciChanImplemented(deviceExtension, lChannel)) {
+            chan = NULL;
         }
 
         if(!commPort) {
@@ -7713,6 +9405,9 @@ reject_srb:
                     break;
                 //}
                 }
+            } else {
+                KdPrint2((PRINT_PREFIX 
+                           "  SRB %#x, CDB %#x, AtaReq %#x, SCmd %#x\n", Srb, &(Srb->Cdb), Srb->SrbExtension, Srb->Cdb[0]));
             }
 /*
             __try {
@@ -7761,8 +9456,9 @@ reject_srb:
                 KdPrint2((PRINT_PREFIX "AtapiStartIo: Already have %d request(s)!\n", chan->queue_depth));
 
             } else {
+
                 // Send command to device.
-                KdPrint2((PRINT_PREFIX "Send to device\n"));
+                KdPrint2((PRINT_PREFIX "Send to device %x\n", Srb->Cdb[0]));
                 if(TopLevel) {
                     KdPrint2((PRINT_PREFIX "TopLevel (2), srb %#x\n", Srb));
                     AtaReq = (PATA_REQ)(Srb->SrbExtension);
@@ -7800,8 +9496,9 @@ reject_srb:
 #endif //NAVO_TEST
 
                 if(atapiDev &&
-                   (Srb->Cdb[0] != SCSIOP_ATA_PASSTHROUGH)) {
-                    KdPrint3((PRINT_PREFIX "Try ATAPI send\n"));
+                   (Srb->Cdb[0] != SCSIOP_ATA_PASSTHROUGH)/* &&
+                   (Srb->Cdb[0] != SCSIOP_REPORT_LUNS)*/) {
+                    KdPrint3((PRINT_PREFIX "Try ATAPI send %x\n", Srb->Cdb[0]));
                     status = AtapiSendCommand(HwDeviceExtension, Srb, CMD_ACTION_ALL);
                 } else {
                     KdPrint2((PRINT_PREFIX "Try IDE send\n"));
@@ -7899,7 +9596,7 @@ reject_srb:
             // For now we support only Lun=0
 
             // Note: reset is immediate command, it cannot be queued since it is usually used to
-            // revert not- responding device to operational state
+            // revert not-responding device to operational state
             KdPrint2((PRINT_PREFIX "AtapiStartIo: Reset device request received\n"));
             UniataUserDeviceReset(deviceExtension, LunExt, lChannel);
             status = SRB_STATUS_SUCCESS;
@@ -7979,40 +9676,11 @@ do_bus_reset:
 
             break;
 
-        case SRB_FUNCTION_FLUSH:
-
-            KdPrint2((PRINT_PREFIX "AtapiStartIo: Flush (do nothing)\n"));
-            status = SRB_STATUS_SUCCESS;
-            break;
-
-    /*    case SRB_FUNCTION_SHUTDOWN:
-        case SRB_FUNCTION_FLUSH:
-
-            // Flush device's cache.
-            KdPrint2((PRINT_PREFIX "AtapiStartIo: Device flush received\n"));
-
-            if (chan->CurrentSrb) {
-
-                KdPrint2((PRINT_PREFIX "AtapiStartIo (SRB_FUNCTION_FLUSH): Already have a request!\n"));
-                Srb->SrbStatus = SRB_STATUS_BUSY;
-                ScsiPortNotification(RequestComplete,
-                                     deviceExtension,
-                                     Srb);
-                return FALSE;
-            }
-
-            if (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
-                status = SRB_STATUS_SUCCESS;
-            } else {
-                status = AtaCommand(deviceExtension, GET_CDEV(Srb), GET_CHANNEL(Srb),
-                           IDE_COMMAND_FLUSH_CACHE, 0, 0, 0, 0, 0, ATA_WAIT_INTR);
-                if (status & IDE_STATUS_DRQ) {
-                    status = SRB_STATUS_SUCCESS;
-                } else {
-                    status = SRB_STATUS_SELECTION_TIMEOUT;
-                }
-            }
-            break;*/
+        case SRB_FUNCTION_FLUSH:
+
+            KdPrint2((PRINT_PREFIX "AtapiStartIo: Flush (do nothing)\n"));
+            status = SRB_STATUS_SUCCESS;
+            break;
 
         case SRB_FUNCTION_IO_CONTROL: {
 
@@ -8024,44 +9692,122 @@ do_bus_reset:
 
             if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature),"SCSIDISK",sizeof("SCSIDISK")-1)) {
 
+                ULONG targetId = (ULONG)(-1);
+
+                if(len < sizeof(SRB_IO_CONTROL)) {
+                    goto wrong_buffer_size;
+                }
+
+                // extract bogus bus address
                 switch (((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode) {
                 case IOCTL_SCSI_MINIPORT_SMART_VERSION: {
-
                     PGETVERSIONINPARAMS versionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
-                    UCHAR deviceNumber;
 
-                    KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_SMART_VERSION\n"));
+                    if(len < sizeof(SRB_IO_CONTROL)+sizeof(GETVERSIONINPARAMS)) {
+                        goto wrong_buffer_size;
+                    }
 
-                    // Version and revision per SMART 1.03
+                    targetId = versionParameters->bIDEDeviceMap;
+                    KdPrint2((PRINT_PREFIX "targetId (smart ver) %d\n", targetId));
+                    break; }
+                case IOCTL_SCSI_MINIPORT_IDENTIFY:
+                case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
+                case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
+                case IOCTL_SCSI_MINIPORT_ENABLE_SMART:
+                case IOCTL_SCSI_MINIPORT_DISABLE_SMART:
+                case IOCTL_SCSI_MINIPORT_RETURN_STATUS:
+                case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
+                case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
+                case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
+                case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE:
+                case IOCTL_SCSI_MINIPORT_READ_SMART_LOG:
+                case IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG:
+                    {
+                    PSENDCMDINPARAMS   cmdInParameters = (PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+
+                    if(len < sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS) - 1) {
+                        goto wrong_buffer_size;
+                    }
 
-                    versionParameters->bVersion = 1;
-                    versionParameters->bRevision = 1;
-                    versionParameters->bReserved = 0;
+                    targetId = cmdInParameters->bDriveNumber;
+                    KdPrint2((PRINT_PREFIX "targetId (smart/ident) %d\n", targetId));
+                    break; }
+                default:
+invalid_request:
+                    KdPrint2((PRINT_PREFIX "AtapiStartIo: invalid IoControl %#x for SCSIDISK signature\n",
+                                ((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode ));
+                    status = SRB_STATUS_INVALID_REQUEST;
+                    goto complete_req;
+                } // end switch()
 
-                    // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands.
-                    versionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD);
+                // adjust (if necessary) bus address
+                if(targetId != (ULONG)(-1)) {
 
                     // This is done because of how the IOCTL_SCSI_MINIPORT
                     // determines 'targetid's'. Disk.sys places the real target id value
                     // in the DeviceMap field. Once we do some parameter checking, the value passed
                     // back to the application will be determined.
 
-                    deviceNumber = versionParameters->bIDEDeviceMap;
-
+                    if (deviceExtension->NumberChannels == 1) {
+                        // do this for legacy controllers and legacy callers
+                        KdPrint2((PRINT_PREFIX "AtapiStartIo: legacy call\n"));
+                        DeviceNumber = (targetId & 0x01);
+                        lChannel = 0;
+                    } else
                     if(commPort) {
+                        // do this for smartmontools, sending IOCTLs to PhysicalDrive%d
+                        // due to DISK.SYS design bug, we have invalid SCSI address in SRB
+                        KdPrint2((PRINT_PREFIX "AtapiStartIo: legacy call (2)\n"));
+                        if(deviceExtension->HwFlags & UNIATA_AHCI) {
+                            lChannel = (UCHAR)targetId / 2;
+                            DeviceNumber = 0;
+                        } else {
+                            lChannel = (UCHAR)(targetId / 2);
+                            DeviceNumber = targetId & 0x01;
+                        }
+                    } else {
+                        // otherwise assume lChannel and DeviceNumber from Srb are ok
+                    }
+                    if(lChannel >= deviceExtension->NumberChannels ||
+                        DeviceNumber >= deviceExtension->NumberLuns) {
                         KdPrint2((PRINT_PREFIX 
-                                   "AtapiStartIo: SCSIDISK IOCTL for commPort -> EXECUTE_SCSI rejected (2)\n"));
+                                   "AtapiStartIo: SCSIDISK IOCTL for non-exestent drive %d -> EXECUTE_SCSI rejected (2)\n",
+                                       targetId));
                         // Indicate no device found at this address.
-                        KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
-                        status = SRB_STATUS_SELECTION_TIMEOUT;
-                        break;
+                        goto reject_srb;
+                    }
+                    targetId = lChannel*deviceExtension->NumberLuns+DeviceNumber;
+                    chan = &(deviceExtension->chan[lChannel]);
+                    LunExt = chan->lun[DeviceNumber];
+                    if(!LunExt) {
+                        goto reject_srb;
                     }
+                    atapiDev = (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE;
 
-                    if (!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT) ||
-                        atapiDev) {
+                    if (!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+                        goto reject_srb;
+                    }
+                }
 
-                        status = SRB_STATUS_SELECTION_TIMEOUT;
-                        break;
+                switch (((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode) {
+                case IOCTL_SCSI_MINIPORT_SMART_VERSION: {
+
+                    PGETVERSIONINPARAMS versionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+                    UCHAR deviceNumberMap;
+
+                    KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_SMART_VERSION\n"));
+
+                    // Version and revision per SMART 1.03
+
+                    versionParameters->bVersion = 1;
+                    versionParameters->bRevision = 1;
+                    versionParameters->bReserved = 0;
+
+                    // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands.
+                    versionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD);
+
+                    if (atapiDev) {
+                        goto invalid_request;
                     }
 
                     // NOTE: This will only set the bit
@@ -8072,17 +9818,21 @@ do_bus_reset:
                     //     S M S M
                     //     3 2 1 0
 
+                    if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
+                        deviceNumberMap = 1 << lChannel;
+                        DeviceNumber = 0;
+                    } else
                     if (deviceExtension->NumberChannels == 1) {
                         if (chan->PrimaryAddress) {
-                            deviceNumber = 1 << DeviceNumber;
+                            deviceNumberMap = 1 << DeviceNumber;
                         } else {
-                            deviceNumber = 4 << DeviceNumber;
+                            deviceNumberMap = 4 << DeviceNumber;
                         }
                     } else {
-                        deviceNumber = (1 << DeviceNumber) << lChannel;
+                        deviceNumberMap = 1 << (DeviceNumber+lChannel*2);
                     }
 
-                    versionParameters->bIDEDeviceMap = deviceNumber;
+                    versionParameters->bIDEDeviceMap = deviceNumberMap;
 
                     status = SRB_STATUS_SUCCESS;
                     break;
@@ -8092,34 +9842,24 @@ do_bus_reset:
 
                     PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
                     SENDCMDINPARAMS   cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
-                    UCHAR             targetId;
 
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_IDENTIFY\n"));
                     // Extract the target.
-                    targetId = cmdInParameters.bDriveNumber;
                     KdPrint2((PRINT_PREFIX "targetId %d\n", targetId));
-                    if((targetId >= deviceExtension->NumberChannels*2) ||
-                       !(deviceExtension->lun[targetId].DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
-                        KdPrint2((PRINT_PREFIX "Error: xxx_ID_CMD for non-existant device\n"));
-                        status = SRB_STATUS_SELECTION_TIMEOUT;
-                        break;
-                    }
 
                     switch(cmdInParameters.irDriveRegs.bCommandReg) {
                     case ID_CMD:
-                        if((deviceExtension->lun[targetId].DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
+                        if(atapiDev) {
                             KdPrint2((PRINT_PREFIX "Error: ID_CMD for ATAPI\n"));
-                            status = SRB_STATUS_INVALID_REQUEST;
-                            break;
+                            goto invalid_request;
                         }
                         /* FALL THROUGH */
                     case ATAPI_ID_CMD:
 
-                        if(!(deviceExtension->lun[targetId].DeviceFlags & DFLAGS_ATAPI_DEVICE) &&
+                        if(!atapiDev &&
                            (cmdInParameters.irDriveRegs.bCommandReg == ATAPI_ID_CMD)) {
                             KdPrint2((PRINT_PREFIX "Error: ATAPI_ID_CMD for non-ATAPI\n"));
-                            status = SRB_STATUS_INVALID_REQUEST;
-                            break;
+                            goto invalid_request;
                         }
 
                         len = min(len, sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE);
@@ -8135,9 +9875,21 @@ do_bus_reset:
                         cmdOutParameters->DriverStatus.bIDEError = 0;
 
                         // Extract the identify data from the device extension.
-                        ScsiPortMoveMemory (cmdOutParameters->bBuffer, &deviceExtension->lun[targetId].IdentifyData,
+                        ScsiPortMoveMemory (cmdOutParameters->bBuffer, &(LunExt->IdentifyData),
                             cmdOutParameters->cBufferSize);
 
+                        if((cmdOutParameters->cBufferSize == IDENTIFY_BUFFER_SIZE) &&
+                           (LunExt->IdentifyData.ChecksumValid == ATA_ChecksumValid)) {
+                            // adjust checksum if it is possible
+                            CHAR csum = 0;
+                            ULONG i;
+
+                            for(i=0; i < IDENTIFY_BUFFER_SIZE-1; i++) {
+                                csum += (CHAR)(cmdOutParameters->bBuffer[i]);
+                            }
+                            cmdOutParameters->bBuffer[i] = -csum;
+                            KdPrint2((PRINT_PREFIX "AtapiStartIo: adjust checksum %d\n"));
+                        }
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_IDENTIFY Ok\n"));
 
                         status = SRB_STATUS_SUCCESS;
@@ -8151,7 +9903,7 @@ do_bus_reset:
                     }
                     break;
                 }
-
+/*
                 case  IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
                 case  IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
                 case  IOCTL_SCSI_MINIPORT_ENABLE_SMART:
@@ -8160,14 +9912,15 @@ do_bus_reset:
                 case  IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
                 case  IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
                 case  IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
-
+*/
+                default:
+                    // *all* IOCTLs here are SMART
                     if(commPort) {
                         KdPrint2((PRINT_PREFIX 
                                    "AtapiStartIo: SCSIDISK Smart IOCTL for commPort -> EXECUTE_SCSI rejected (3)\n"));
-                        // Indicate no device found at this address.
-                        KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
-                        status = SRB_STATUS_SELECTION_TIMEOUT;
-                        break;
+                    }
+                    if (atapiDev) {
+                        goto invalid_request;
                     }
 
                     PostReq = UniataNeedQueueing(deviceExtension, chan, TopLevel);
@@ -8186,16 +9939,17 @@ do_bus_reset:
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: Already have %d request(s)!\n", chan->queue_depth));
                     } else {
 
-                        status = IdeSendSmartCommand(HwDeviceExtension,Srb);
+                        status = IdeSendSmartCommand(HwDeviceExtension, Srb, targetId);
                     }
                     break;
 
-                default :
+                // we should not get here, checked above
+/*                default :
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: invalid IoControl %#x for SCSIDISK signature\n",
                                 ((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode ));
                     status = SRB_STATUS_INVALID_REQUEST;
                     break;
-
+*/
                 }
             } else
             if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature),"-UNIATA-", sizeof("-UNIATA-")-1)) {
@@ -8204,8 +9958,15 @@ do_bus_reset:
                 //ULONG ldev = GET_LDEV2(AtaCtl->addr.PathId, AtaCtl->addr.TargetId, 0);
                 ULONG DeviceNumber = AtaCtl->addr.TargetId;
                 BOOLEAN bad_ldev;
-                ULONG i;
+                ULONG i, pos;
+
+                pos = FIELD_OFFSET(UNIATA_CTL, RawData);
                 //chan = &(deviceExtension->chan[lChannel]);
+                if(len < pos) {
+                    KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+                        FIELD_OFFSET(UNIATA_CTL, RawData) ));
+                    goto wrong_buffer_size;
+                }
 
                 if(AtaCtl->addr.Lun ||
                    AtaCtl->addr.TargetId >= deviceExtension->NumberLuns || 
@@ -8270,6 +10031,11 @@ handle_bad_ldev:
                     }
                     goto uata_ctl_queue;
                 case  IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE:
+                    if(len < pos+sizeof(AtaCtl->SetMode)) {
+                        KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+                            pos+sizeof(AtaCtl->SetMode) ));
+                        goto wrong_buffer_size;
+                    }
                     if(!AtaCtl->SetMode.ApplyImmediately) {
                         break;
                     }
@@ -8300,6 +10066,11 @@ uata_ctl_queue:
 
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: rescan bus\n"));
 
+                    if(len < pos+sizeof(AtaCtl->FindDelDev)) {
+                        KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+                            pos+sizeof(AtaCtl->FindDelDev) ));
+                        goto wrong_buffer_size;
+                    }
                     if(AtaCtl->FindDelDev.Flags & UNIATA_ADD_FLAGS_UNHIDE) {
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: unhide from further detection\n"));
                         if(AtaCtl->addr.TargetId != 0xff) {
@@ -8324,10 +10095,16 @@ uata_ctl_queue:
 
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: remove %#x:%#x\n", AtaCtl->addr.PathId, AtaCtl->addr.TargetId));
 
+                    if(len < pos+sizeof(AtaCtl->FindDelDev)) {
+                        KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+                            pos+sizeof(AtaCtl->FindDelDev) ));
+                        goto wrong_buffer_size;
+                    }
                     LunExt->DeviceFlags = 0;
                     if(AtaCtl->FindDelDev.Flags & UNIATA_REMOVE_FLAGS_HIDE) {
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: hide from further detection\n"));
-                        LunExt->DeviceFlags |= DFLAGS_HIDDEN;
+                        //LunExt->DeviceFlags |= DFLAGS_HIDDEN;
+                        UniataForgetDevice(LunExt);
                     }
 
                     for(i=0; i<AtaCtl->FindDelDev.WaitForPhysicalLink && i<30; i++) {
@@ -8341,6 +10118,11 @@ uata_ctl_queue:
 
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: Set transfer mode\n"));
 
+                    if(len < pos+sizeof(AtaCtl->SetMode)) {
+                        KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+                            pos+sizeof(AtaCtl->SetMode) ));
+                        goto wrong_buffer_size;
+                    }
                     if(AtaCtl->SetMode.OrigMode != IOMODE_NOT_SPECIFIED) {
                         LunExt->OrigTransferMode = (UCHAR)(AtaCtl->SetMode.OrigMode);
                     }
@@ -8368,9 +10150,15 @@ uata_ctl_queue:
 
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: Get transfer mode\n"));
 
+                    if(len < pos+sizeof(AtaCtl->GetMode)) {
+                        KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+                            pos+sizeof(AtaCtl->GetMode) ));
+                        goto wrong_buffer_size;
+                    }
                     AtaCtl->GetMode.OrigMode    = LunExt->OrigTransferMode;
                     AtaCtl->GetMode.MaxMode     = LunExt->LimitedTransferMode;
                     AtaCtl->GetMode.CurrentMode = LunExt->TransferMode;
+                    AtaCtl->GetMode.PhyMode     = LunExt->PhyTransferMode;
 
                     status = SRB_STATUS_SUCCESS;
                     break;
@@ -8379,6 +10167,11 @@ uata_ctl_queue:
 
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: Get version\n"));
 
+                    if(len < pos+sizeof(AtaCtl->Version)) {
+                        KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+                            pos+sizeof(AtaCtl->Version) ));
+                        goto wrong_buffer_size;
+                    }
                     AtaCtl->Version.Length      = sizeof(GETDRVVERSION);
                     AtaCtl->Version.VersionMj   = UNIATA_VER_MJ;
                     AtaCtl->Version.VersionMn   = UNIATA_VER_MN;
@@ -8392,14 +10185,12 @@ uata_ctl_queue:
 
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: Get adapter info\n"));
 
-                    AtaCtl->AdapterInfo.HeaderLength = FIELD_OFFSET(ADAPTERINFO, Chan);
-
-                    if(len < AtaCtl->AdapterInfo.HeaderLength + sizeof(AtaCtl->AdapterInfo.Chan)) {
-                        KdPrint2((PRINT_PREFIX "AtapiStartIo: Buffer too small: %#x < %#x\n", len,
-                            AtaCtl->AdapterInfo.HeaderLength + sizeof(AtaCtl->AdapterInfo.Chan)));
-                        status = SRB_STATUS_DATA_OVERRUN;
-                        break;
+                    if(len < pos+sizeof(AtaCtl->AdapterInfo)) {
+                        KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+                            pos+sizeof(AtaCtl->AdapterInfo) ));
+                        goto wrong_buffer_size;
                     }
+                    AtaCtl->AdapterInfo.HeaderLength = sizeof(ADAPTERINFO);
 
                     AtaCtl->AdapterInfo.DevID      = deviceExtension->DevID;
                     AtaCtl->AdapterInfo.RevID      = deviceExtension->RevID;
@@ -8426,8 +10217,35 @@ uata_ctl_queue:
                     }
                     AtaCtl->AdapterInfo.ChanInfoValid = FALSE;
                     AtaCtl->AdapterInfo.LunInfoValid = FALSE;
-
-                    RtlZeroMemory(&AtaCtl->AdapterInfo.Chan, sizeof(AtaCtl->AdapterInfo.Chan));
+                    AtaCtl->AdapterInfo.ChanHeaderLengthValid = TRUE;
+
+                    pos += AtaCtl->AdapterInfo.HeaderLength;
+
+                    // zero tail
+                    RtlZeroMemory(((PCHAR)AtaCtl)+pos,
+                        len-pos);
+
+                    if(len >= pos+AtaCtl->AdapterInfo.NumberChannels*sizeof(CHANINFO)) {
+                        PCHANINFO ChanInfo = (PCHANINFO)( ((PCHAR)AtaCtl)+pos );
+                        PHW_CHANNEL cur_chan;
+                        KdPrint2((PRINT_PREFIX "AtapiStartIo: Fill channel info\n"));
+                        for(i=0;i<AtaCtl->AdapterInfo.NumberChannels;i++) {
+                            KdPrint2((PRINT_PREFIX "chan[%d] %x\n", i, cur_chan));
+                            cur_chan = &(deviceExtension->chan[i]);
+                            ChanInfo->MaxTransferMode = cur_chan->MaxTransferMode;
+                            ChanInfo->ChannelCtrlFlags = cur_chan->ChannelCtrlFlags;
+                            RtlCopyMemory(&(ChanInfo->QueueStat), &(cur_chan->QueueStat), sizeof(ChanInfo->QueueStat));
+                            ChanInfo->ReorderCount        = cur_chan->ReorderCount;
+                            ChanInfo->IntersectCount      = cur_chan->IntersectCount;
+                            ChanInfo->TryReorderCount     = cur_chan->TryReorderCount;
+                            ChanInfo->TryReorderHeadCount = cur_chan->TryReorderHeadCount;
+                            ChanInfo->TryReorderTailCount = cur_chan->TryReorderTailCount;
+                            //ChanInfo->opt_MaxTransferMode = cur_chan->opt_MaxTransferMode;
+                            ChanInfo++;
+                        }
+                        AtaCtl->AdapterInfo.ChanInfoValid = TRUE;
+                        AtaCtl->AdapterInfo.ChanHeaderLength = sizeof(*ChanInfo);
+                    }
 
                     status = SRB_STATUS_SUCCESS;
                     break;
@@ -8498,13 +10316,19 @@ complete_req:
             // Set status in SRB.
             Srb->SrbStatus = (UCHAR)status;
 
-            AtapiDmaDBSync(chan, Srb);
+            if(chan && Srb) {
+                KdPrint2((PRINT_PREFIX "AtapiStartIo: AtapiDmaDBSync(%x, %x)\n", chan, Srb));
+                AtapiDmaDBSync(chan, Srb);
+            }
+            KdPrint2((PRINT_PREFIX "AtapiStartIo: UniataRemoveRequest(%x, %x)\n", chan, Srb));
             UniataRemoveRequest(chan, Srb);
             // Indicate command complete.
+            KdPrint2((PRINT_PREFIX "AtapiStartIo: ScsiPortNotification\n"));
             ScsiPortNotification(RequestComplete,
                                  deviceExtension,
                                  Srb);
 
+            KdPrint2((PRINT_PREFIX "AtapiStartIo: UniataGetCurRequest\n"));
             // Remove current Srb & get next one
             if((Srb = UniataGetCurRequest(chan))) {
                 AtaReq = (PATA_REQ)(Srb->SrbExtension);
@@ -8514,6 +10338,7 @@ complete_req:
                     Srb = NULL;
                 }
             }
+            KdPrint2((PRINT_PREFIX "AtapiStartIo: chan %x, Src %x\n", chan, Srb));
             if(!chan) {
                 //ASSERT(TopLevel);
             }
@@ -8538,7 +10363,7 @@ complete_req:
 
 } // end AtapiStartIo__()
 
-
+#if 0
 void
 NTAPI
 UniataInitAtaCommands()
@@ -8554,7 +10379,7 @@ UniataInitAtaCommands()
         flags = 0;
         command = i;
 
-        KdPrint2((PRINT_PREFIX "cmd %2.2x: ", command));
+        //KdPrint2((PRINT_PREFIX "cmd %2.2x: ", command));
 
         switch(command) {
         case IDE_COMMAND_READ_DMA48:
@@ -8575,11 +10400,19 @@ UniataInitAtaCommands()
         case IDE_COMMAND_WRITE_LOG_DMA48:
         case IDE_COMMAND_TRUSTED_RCV_DMA:
         case IDE_COMMAND_TRUSTED_SEND_DMA:
-            KdPrint2((PRINT_PREFIX "DMA "));
+        case IDE_COMMAND_DATA_SET_MGMT: // TRIM
+            //KdPrint2((PRINT_PREFIX "DMA "));
             flags |= ATA_CMD_FLAG_DMA;
         }
 
         switch(command) {
+        case IDE_COMMAND_WRITE_FUA_DMA48:
+        case IDE_COMMAND_WRITE_FUA_DMA_Q48:
+        case IDE_COMMAND_WRITE_MUL_FUA48:
+
+            flags |= ATA_CMD_FLAG_FUA;
+            /* FALL THROUGH */
+
         case IDE_COMMAND_READ48:
         case IDE_COMMAND_READ_DMA48:
         case IDE_COMMAND_READ_DMA_Q48:
@@ -8592,13 +10425,10 @@ UniataInitAtaCommands()
         case IDE_COMMAND_WRITE_MUL48:
         case IDE_COMMAND_WRITE_STREAM_DMA48:
         case IDE_COMMAND_WRITE_STREAM48:
-        case IDE_COMMAND_WRITE_FUA_DMA48:
-        case IDE_COMMAND_WRITE_FUA_DMA_Q48:
-        case IDE_COMMAND_WRITE_MUL_FUA48:
         case IDE_COMMAND_FLUSH_CACHE48:
         case IDE_COMMAND_VERIFY48:
 
-            KdPrint2((PRINT_PREFIX "48 "));
+            //KdPrint2((PRINT_PREFIX "48 "));
             flags |= ATA_CMD_FLAG_48;
             /* FALL THROUGH */
 
@@ -8613,10 +10443,23 @@ UniataInitAtaCommands()
         case IDE_COMMAND_FLUSH_CACHE:
         case IDE_COMMAND_VERIFY:
 
-            KdPrint2((PRINT_PREFIX "LBA "));
+            //KdPrint2((PRINT_PREFIX "LBA "));
             flags |= ATA_CMD_FLAG_LBAIOsupp;
         }
 
+        switch(command) {
+        case IDE_COMMAND_READ_NATIVE_SIZE48:
+        case IDE_COMMAND_SET_NATIVE_SIZE48:
+            // we cannot set LBA flag for these commands to avoid BadBlock handling
+            //flags |= ATA_CMD_FLAG_LBAIOsupp;
+            flags |= ATA_CMD_FLAG_48;
+
+        case IDE_COMMAND_READ_NATIVE_SIZE:
+        case IDE_COMMAND_SET_NATIVE_SIZE:
+
+            flags |= ATA_CMD_FLAG_LBAIOsupp | ATA_CMD_FLAG_FUA;
+        }
+
         flags |= ATA_CMD_FLAG_48supp;
 
         switch (command) {
@@ -8645,15 +10488,47 @@ UniataInitAtaCommands()
         case IDE_COMMAND_VERIFY:
             command = IDE_COMMAND_VERIFY48; break;
         default:
-            KdPrint2((PRINT_PREFIX "!28->48 "));
+            //KdPrint2((PRINT_PREFIX "!28->48 "));
             flags &= ~ATA_CMD_FLAG_48supp;
         }
 
-        KdPrint2((PRINT_PREFIX "\t -> %2.2x (%2.2x)\n", command, flags));
+        switch (command) {
+        case IDE_COMMAND_READ:
+        case IDE_COMMAND_READ_MULTIPLE:
+        case IDE_COMMAND_READ_DMA48:
+        case IDE_COMMAND_READ_DMA_Q48:
+        case IDE_COMMAND_READ_STREAM_DMA48:
+        case IDE_COMMAND_READ_STREAM48:
+        case IDE_COMMAND_READ_DMA_Q:
+        case IDE_COMMAND_READ_DMA:
+        case IDE_COMMAND_READ_LOG_DMA48:
+        case IDE_COMMAND_TRUSTED_RCV_DMA:
+        case IDE_COMMAND_IDENTIFY:
+        case IDE_COMMAND_ATAPI_IDENTIFY:
+            //KdPrint2((PRINT_PREFIX "RD "));
+            flags |= ATA_CMD_FLAG_In;
+            break;
+        case IDE_COMMAND_WRITE:
+        case IDE_COMMAND_WRITE_MULTIPLE:
+        case IDE_COMMAND_WRITE_DMA48:
+        case IDE_COMMAND_WRITE_DMA_Q48:
+        case IDE_COMMAND_WRITE_DMA:
+        case IDE_COMMAND_WRITE_DMA_Q:
+        case IDE_COMMAND_WRITE_STREAM_DMA48:
+        case IDE_COMMAND_WRITE_STREAM48:
+        case IDE_COMMAND_WRITE_FUA_DMA48:
+        case IDE_COMMAND_WRITE_FUA_DMA_Q48:
+            //KdPrint2((PRINT_PREFIX "WR "));
+            flags |= ATA_CMD_FLAG_Out;
+            break;
+        }
+
+        //KdPrint2((PRINT_PREFIX "\t -> %2.2x (%2.2x)\n", command, flags));
         AtaCommands48[i]   = command;
         AtaCommandFlags[i] = flags;
     }
 } // end UniataInitAtaCommands()
+#endif
 
 /*++
 
@@ -8680,11 +10555,11 @@ 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;
-    WCHAR                  a;
+//    WCHAR                  a;
 #ifndef USE_REACTOS_DDK
     NTSTATUS               status;
 #endif
@@ -8692,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);
+    //a = (WCHAR)strlen(ver_string);
+
+    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;
 
-    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");
+    // 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) {
@@ -8711,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
@@ -8719,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)\n", MajorVersion, MinorVersion, BuildNumber));
+        KdPrint(("UniATA Init: OS ver %x.%x (%d), %d CPU(s)\n", MajorVersion, MinorVersion, BuildNumber, CPU_num));
 
         KeQuerySystemTime(&t0);
         do {
@@ -8744,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;
@@ -8771,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"));
@@ -8804,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);
@@ -8816,26 +10712,58 @@ 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:
+            KdPrint2((PRINT_PREFIX "adjust options for VirtualBox\n"));
             // adjust options for VirtualBox
             g_opt_WaitBusyCount = 20000;
             g_opt_WaitBusyDelay = 150;
             g_opt_WaitDrqDelay  = 100;
-            g_opt_AtapiSendDisableIntr = 0;
+            g_opt_WaitBusyLongCount = 20000;
+            g_opt_MaxIsrWait = 200;
+            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 (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
         g_opt_WaitBusyDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyDelay", g_opt_WaitBusyDelay); // 10 vs 150
         g_opt_WaitDrqDelay  = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitDrqDelay",  g_opt_WaitDrqDelay);  // 10 vs 100
-        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_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) ? 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"));
@@ -8846,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) {
@@ -8858,22 +10786,53 @@ DriverEntry(
             }
             continue;
         }
-        BMList[i].AltInitMasterDev = (UCHAR)0xff;
+        //BMList[i].AltInitMasterDev = (UCHAR)0xff;
 
         if(GlobalConfig->AtDiskPrimaryAddressClaimed)
             PrimaryClaimed = TRUE;
         if(GlobalConfig->AtDiskSecondaryAddressClaimed)
             SecondaryClaimed = TRUE;
+        pref_alt = 0;
+
+        if(!WinVer_WDM_Model && !PrimaryClaimed && !SecondaryClaimed && !g_Dump &&
+            !(BMList[i].ChanInitOk & 0x80)) {
+            
+            // 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;
+            }
+        }
 
         if(g_opt_Verbose) {
             _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;
                 }
@@ -8917,13 +10876,21 @@ 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;
                 }
                 if (newStatus == STATUS_SUCCESS) {
-                    BMList[i].ChanInitOk |= 0x01 << c;
+                    if(WinVer_Id() < WinVer_2k) {
+                        // This should be done in HwInitialize under w2k+ to ensure that 
+                        // channel is actually initialized
+                        BMList[i].ChanInitOk |= 0x01 << c;
+                    } else {
+                        if(BMList[i].ChanInitOk & (0x01 << c)) {
+                            KdPrint2((PRINT_PREFIX "HwInit passed\n"));
+                        }
+                    }
 /*
                     if(BMList[i].MasterDev && (WinVer_Id() > WinVer_NT)) {
                         c = 1; // this will break our for()
@@ -8932,43 +10899,28 @@ DriverEntry(
 */
                 }
             }
-            if(WinVer_Id() >= WinVer_2k) {
-                // the following doesn't work under higher OSes
+/*            if(WinVer_Id() >= WinVer_2k) {
+                // the following didn't work under higher OSes,
+                // until we move setting of FLAGS to HwInit
                 KdPrint2((PRINT_PREFIX "make still one attempt\n"));
                 continue;
-            }
+            }*/
             if(BMList[i].ChanInitOk & 0x03) {
-                // under NT we receive status immediately, so
-                // we can omit alternative init method id STATUS_SUCCESS returned
+                // Under NT we receive status immediately, so
+                // we can omit alternative init method if STATUS_SUCCESS returned.
+                // Under w2k+ we relay on flags, set in HwInitialize.
                 KdPrint2((PRINT_PREFIX "Ok, no more retries required\n"));
                 break;
+            } else
+            if(WinVer_Id() >= WinVer_2k) {
+                // try AltInit if HwInit was not called immediately under w2k+
+                KdPrint2((PRINT_PREFIX "make still one attempt w2k+\n"));
+            } else {
+                // if (WinVer_Id() == WinVer_NT) and some error occured
+                // try alternative init method
+                KdPrint2((PRINT_PREFIX "make still one attempt w2k+\n"));
             }
-            // if (WinVer_Id() == WinVer_NT) and some error occured
-            // try alternative init method
         } // for(alt...)
-#if 0
-        if(WinVer_WDM_Model) {
-            hwInitializationData.comm.HwFindAdapter = UniataFindFakeBusMasterController;
-            hwInitializationData.comm.NumberOfAccessRanges = 5;
-            hwInitializationData.comm.AdapterInterfaceType = PCIBus;
-
-            hwInitializationData.comm.VendorId             = BMList[i].VendorId;
-            hwInitializationData.comm.VendorIdLength       = (USHORT) BMList[i].VendorIdLength;
-            hwInitializationData.comm.DeviceId             = BMList[i].DeviceId;
-            hwInitializationData.comm.DeviceIdLength       = (USHORT) BMList[i].DeviceIdLength;
-
-            //BMList[i].channel = 0/*(UCHAR)c*/;
-
-            KdPrint2((PRINT_PREFIX "Try init fake: %4.4s %4.4s \n",
-                                   hwInitializationData.comm.VendorId,
-                                   hwInitializationData.comm.DeviceId));
-            newStatus = ScsiPortInitialize(DriverObject,
-                                           Argument2,
-                                           &hwInitializationData.comm,
-                                           (PVOID)i);
-            KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
-        }
-#endif //0
         if(g_opt_Verbose) {
             if(BMList[i].ChanInitOk & 0x03) {
                 _PrintNtConsole("  OK\n");
@@ -8989,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)
@@ -9006,9 +10958,9 @@ DriverEntry(
         hwInitializationData.comm.NumberOfAccessRanges = 6;
         hwInitializationData.comm.AdapterInterfaceType = PCIBus;
 
-        hwInitializationData.comm.VendorId             = BMList[i].VendorId;
+        hwInitializationData.comm.VendorId             = (PVOID)BMList[i].VendorId;
         hwInitializationData.comm.VendorIdLength       = (USHORT) BMList[i].VendorIdLength;
-        hwInitializationData.comm.DeviceId             = BMList[i].DeviceId;
+        hwInitializationData.comm.DeviceId             = (PVOID)BMList[i].DeviceId;
         hwInitializationData.comm.DeviceIdLength       = (USHORT) BMList[i].DeviceIdLength;
 
         BMList[i].channel = 0/*(UCHAR)c*/;
@@ -9019,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
@@ -9032,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)
@@ -9060,12 +11012,18 @@ DriverEntry(
     hwInitializationData.comm.DeviceId             = 0;
     hwInitializationData.comm.DeviceIdLength       = 0;
 
+    if(!BMListLen) {
+        hwInitializationData.comm.SrbExtensionSize        = //FIELD_OFFSET(ATA_REQ, ata);
+                                                            sizeof(ATA_REQ);
+        KdPrint2((PRINT_PREFIX "using AtaReq sz %x\n", hwInitializationData.comm.SrbExtensionSize));
+    }
+
     // The adapter count is used by the find adapter routine to track how
     // which adapter addresses have been tested.
 
     // 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.
@@ -9142,6 +11100,8 @@ BuildMechanismStatusSrb(
     cdb->MECH_STATUS.OperationCode       = SCSIOP_MECHANISM_STATUS;
     cdb->MECH_STATUS.AllocationLength[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
 
+    KdPrint2((PRINT_PREFIX " MechanismStatusSrb %#x\n", srb));
+
     return srb;
 } // end BuildMechanismStatusSrb()
 
@@ -9184,6 +11144,8 @@ BuildRequestSenseSrb (
     cdb->CDB6INQUIRY.OperationCode    = SCSIOP_REQUEST_SENSE;
     cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
 
+    KdPrint2((PRINT_PREFIX " RequestSenseSrb %#x\n", srb));
+
     return srb;
 } // end BuildRequestSenseSrb()
 
@@ -9284,6 +11246,7 @@ AtapiRegCheckDevValue(
     IN ULONG VendorID;
     IN ULONG DeviceID;
     IN ULONG SlotNumber;
+    IN ULONG HwFlags;
 
     ULONG val = Default;
 
@@ -9293,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);
@@ -9404,6 +11389,10 @@ 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));
@@ -9434,11 +11423,14 @@ AtapiRegCheckParameterValue(
 
     status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/,
                                     paramPath.Buffer, parameters, NULL, NULL);
-    KdPrint(( "AtapiCheckRegValue: %ws -> %ws is %#x\n", PathSuffix, Name, doRun));
+    if(NT_SUCCESS(status)) {
+        KdPrint(( "AtapiCheckRegValue: %ws -> %ws is %#x\n", PathSuffix, Name, doRun));
+    }
 
     ExFreePool(paramPath.Buffer);
 
     if(!NT_SUCCESS(status)) {
+failed:
         doRun = Default;
     }
 
@@ -9502,7 +11494,7 @@ AtapiAdapterControl(
             }
             if(deviceExtension->AdapterInterfaceType == PCIBus) {
                 // we must never get here for non-PCI
-                status = UniataDisconnectIntr2(HwDeviceExtension);
+                /*status =*/ UniataDisconnectIntr2(HwDeviceExtension);
                 BMList[deviceExtension->DevIndex].Isr2Enable = FALSE;
             }
             break;
@@ -9515,15 +11507,17 @@ AtapiAdapterControl(
 
             AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, CHAN_NOT_SPECIFIED);
             status = UniataConnectIntr2(HwDeviceExtension);
-            for (c = 0; c < numberChannels; c++) {
-                AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, c);
-                FindDevices(HwDeviceExtension, 0, c);
-                AtapiEnableInterrupts(deviceExtension, c);
-                AtapiHwInitialize__(deviceExtension, c);
-            }
-            if(deviceExtension->Isr2DevObj) {
-                // we must never get here for non-PCI
-                BMList[deviceExtension->DevIndex].Isr2Enable = TRUE;
+            if(NT_SUCCESS(status)) {
+                for (c = 0; c < numberChannels; c++) {
+                    AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, c);
+                    FindDevices(HwDeviceExtension, 0, c);
+                    AtapiEnableInterrupts(deviceExtension, c);
+                    AtapiHwInitialize__(deviceExtension, c);
+                }
+                if(deviceExtension->Isr2DevObj) {
+                    // we must never get here for non-PCI
+                    BMList[deviceExtension->DevIndex].Isr2Enable = TRUE;
+                }
             }
 
             break;
@@ -9548,6 +11542,8 @@ HalDisplayString (
     PUCHAR String
     );
 
+#define DEBUG_MSG_BUFFER_SIZE   512
+
 extern "C"
 VOID
 _cdecl
@@ -9556,19 +11552,25 @@ _PrintNtConsole(
     ...
     )
 {
-    int len;
-    UCHAR dbg_print_tmp_buff[512];
+    //int len;
+    UCHAR dbg_print_tmp_buff[DEBUG_MSG_BUFFER_SIZE];
 //    UNICODE_STRING msgBuff;
     va_list ap;
     va_start(ap, DebugMessage);
 
-    len = _vsnprintf((PCHAR)&dbg_print_tmp_buff[0], 511, DebugMessage, ap);
+    /*len =*/ _vsnprintf((PCHAR)&dbg_print_tmp_buff[0], DEBUG_MSG_BUFFER_SIZE-1, DebugMessage, ap);
 
-    dbg_print_tmp_buff[511] = 0;
+    dbg_print_tmp_buff[DEBUG_MSG_BUFFER_SIZE-1] = 0;
 
-    KdPrint(((PCHAR)&(dbg_print_tmp_buff[0])));
+    //DbgPrint(((PCHAR)&(dbg_print_tmp_buff[0]))); // already done in KdPrint macro
     HalDisplayString(dbg_print_tmp_buff);
 
+#ifdef _DEBUG
+    if(g_LogToDisplay > 1) {
+        AtapiStallExecution(g_LogToDisplay*1000);
+    }
+#endif // _DEBUG
+
     va_end(ap);
 
 } // end PrintNtConsole()