[uniata]
[reactos.git] / reactos / drivers / storage / ide / uniata / id_ata.cpp
index 1d141b5..122431b 100644 (file)
@@ -1,6 +1,6 @@
 /*++
 
-Copyright (c) 2002-2008 Alexandr A. Telyatnikov (Alter)
+Copyright (c) 2002-2014 Alexandr A. Telyatnikov (Alter)
 
 Module Name:
     id_ata.cpp
@@ -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,7 +47,7 @@ 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)
 
     etc. (See todo.txt)
@@ -83,11 +83,24 @@ ULONG  g_LogToDisplay = 0;
 
 ULONG  g_WaitBusyInISR = 1;
 
+ULONG  g_opt_WaitBusyCount = 200; // 20000
+ULONG  g_opt_WaitBusyDelay = 10;  // 150
+ULONG  g_opt_WaitDrqDelay  = 10; // 100
+ULONG  g_opt_WaitBusyLongCount = 2000; // 2000
+ULONG  g_opt_WaitBusyLongDelay = 250;  // 250
+ULONG  g_opt_MaxIsrWait = 40; //
+BOOLEAN g_opt_AtapiSendDisableIntr = 0; // 0
+BOOLEAN g_opt_AtapiDmaRawRead = 1; // 0
+BOOLEAN hasPCI = FALSE;
+
+ULONG g_opt_VirtualMachine = 0; // Auto
+
 BOOLEAN InDriverEntry = TRUE;
 
 BOOLEAN g_opt_Verbose = 0;
 
 BOOLEAN WinVer_WDM_Model = FALSE;
+
 //UCHAR EnableDma = FALSE;
 //UCHAR EnableReorder = FALSE;
 
@@ -108,6 +121,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
@@ -159,14 +180,6 @@ AtapiAdapterControl(
 
 #endif //UNIATA_CORE
 
-BOOLEAN
-NTAPI
-AtapiCheckInterrupt__(
-    IN PVOID HwDeviceExtension,
-    IN UCHAR c
-    );
-
-
 #ifndef UNIATA_CORE
 
 BOOLEAN
@@ -234,13 +247,12 @@ UniataNanoSleep(
     } while(t);
 } // end UniataNanoSleep()
 
-
 #define AtapiWritePortN_template(_type, _Type, sz) \
 VOID \
 DDKFASTAPI \
 AtapiWritePort##sz( \
     IN PHW_CHANNEL chan, \
-    IN ULONG_PTR _port, \
+    IN ULONGIO_PTR _port, \
     IN _type  data \
     ) \
 { \
@@ -254,6 +266,8 @@ AtapiWritePort##sz( \
         KdPrint(("invalid io write request @ ch %x, res* %x\n", chan, _port)); \
         return; \
     } \
+    if(res->Proc) {             \
+    } else  \
     if(!res->MemIo) {             \
         ScsiPortWritePort##_Type((_type*)(res->Addr), data); \
     } else {                                      \
@@ -272,7 +286,7 @@ VOID \
 DDKFASTAPI \
 AtapiWritePortEx##sz( \
     IN PHW_CHANNEL chan, \
-    IN ULONG_PTR _port, \
+    IN ULONGIO_PTR _port, \
     IN ULONG offs, \
     IN _type  data \
     ) \
@@ -287,6 +301,8 @@ AtapiWritePortEx##sz( \
         KdPrint(("invalid io write request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
         return; \
     } \
+    if(res->Proc) {             \
+    } else  \
     if(!res->MemIo) {             \
         ScsiPortWritePort##_Type((_type*)(res->Addr+offs), data); \
     } else {                                      \
@@ -305,7 +321,7 @@ _type \
 DDKFASTAPI \
 AtapiReadPort##sz( \
     IN PHW_CHANNEL chan, \
-    IN ULONG_PTR _port \
+    IN ULONGIO_PTR _port \
     ) \
 { \
     PIORES res; \
@@ -318,6 +334,9 @@ AtapiReadPort##sz( \
         KdPrint(("invalid io read request @ ch %x, res* %x\n", chan, _port)); \
         return (_type)(-1); \
     } \
+    if(res->Proc) {             \
+        return 0; \
+    } else  \
     if(!res->MemIo) {             \
         /*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
         return ScsiPortReadPort##_Type((_type*)(res->Addr)); \
@@ -336,7 +355,7 @@ _type \
 DDKFASTAPI \
 AtapiReadPortEx##sz( \
     IN PHW_CHANNEL chan, \
-    IN ULONG_PTR _port, \
+    IN ULONGIO_PTR _port, \
     IN ULONG offs \
     ) \
 { \
@@ -350,6 +369,9 @@ AtapiReadPortEx##sz( \
         KdPrint(("invalid io read request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
         return (_type)(-1); \
     } \
+    if(res->Proc) {             \
+        return 0; \
+    } else  \
     if(!res->MemIo) {             \
         return ScsiPortReadPort##_Type((_type*)(res->Addr+offs)); \
     } else {                                      \
@@ -367,7 +389,7 @@ VOID \
 DDKFASTAPI \
 AtapiReadBuffer##sz( \
     IN PHW_CHANNEL chan, \
-    IN ULONG_PTR _port, \
+    IN ULONGIO_PTR _port, \
     IN PVOID Buffer, \
     IN ULONG Count,   \
     IN ULONG Timing   \
@@ -412,7 +434,7 @@ VOID \
 DDKFASTAPI \
 AtapiWriteBuffer##sz( \
     IN PHW_CHANNEL chan, \
-    IN ULONG_PTR _port, \
+    IN ULONGIO_PTR _port, \
     IN PVOID Buffer, \
     IN ULONG Count,   \
     IN ULONG Timing   \
@@ -468,6 +490,7 @@ AtapiSuckPort2(
     UCHAR statusByte;
     ULONG i;
 
+    // Assume, proper drive is already seleted
     WaitOnBusyLong(chan);
     for (i = 0; i < 0x10000; i++) {
 
@@ -493,10 +516,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;
@@ -517,10 +542,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;
@@ -536,11 +561,11 @@ WaitOnBaseBusy(
     )
 {
     ULONG i;
-    UCHAR Status;
-    for (i=0; i<20000; i++) {
+    UCHAR Status = IDE_STATUS_WRONG;
+    for (i=0; i<g_opt_WaitBusyCount; i++) {
         GetBaseStatus(chan, Status);
         if (Status & IDE_STATUS_BUSY) {
-            AtapiStallExecution(150);
+            AtapiStallExecution(g_opt_WaitBusyDelay);
             continue;
         } else {
             break;
@@ -582,8 +607,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;
@@ -615,7 +640,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
@@ -640,11 +665,11 @@ WaitForDrq(
     for (i=0; i<1000; i++) {
         GetStatus(chan, Status);
         if (Status & IDE_STATUS_BUSY) {
-            AtapiStallExecution(100);
+            AtapiStallExecution(g_opt_WaitDrqDelay);
         } else if (Status & IDE_STATUS_DRQ) {
             break;
         } else {
-            AtapiStallExecution(200);
+            AtapiStallExecution(g_opt_WaitDrqDelay*2);
         }
     }
     return Status;
@@ -661,11 +686,11 @@ WaitShortForDrq(
     for (i=0; i<2; i++) {
         GetStatus(chan, Status);
         if (Status & IDE_STATUS_BUSY) {
-            AtapiStallExecution(100);
+            AtapiStallExecution(g_opt_WaitDrqDelay);
         } else if (Status & IDE_STATUS_DRQ) {
             break;
         } else {
-            AtapiStallExecution(100);
+            AtapiStallExecution(g_opt_WaitDrqDelay);
         }
     }
     return Status;
@@ -684,20 +709,48 @@ AtapiSoftReset(
     KdPrint2((PRINT_PREFIX "AtapiSoftReset:\n"));
     UCHAR statusByte2;
 
+    if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
+        UniataAhciSoftReset(chan->DeviceExtension, chan->lChannel, DeviceNumber);
+        return;
+    }
+
     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
+        AtapiStallExecution(10000);
+        for (i = 0; i < 1000; i++) {
+            AtapiStallExecution(999);
+        }
+    } else {
+        AtapiStallExecution(500);
+        GetBaseStatus(chan, statusByte2);
+        AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET);
+
+        // Do not wait for BUSY assertion if it was initially set, jump to
+        // BUSY release wait loop
+        if(!(statusByte2 & IDE_STATUS_BUSY)) {
+            // Wait for BUSY assertion, in some cases delay may occure
+            // 100ms should be enough
+            i = 10*1000;
+            while (!(AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) &&
+                   i--)
+            {
+                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);
+        }
     }
 
     SelectDrive(chan, DeviceNumber);
@@ -719,7 +772,10 @@ AtapiSoftReset(
         GetBaseStatus(chan, statusByte2);
     }
     if(chan->DeviceExtension->HwFlags & UNIATA_SATA) {
-        UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT);
+        UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT, DeviceNumber);
+/*        if(!(chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE)) {
+            UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT, 1);
+        }*/
     }
     return;
 
@@ -739,36 +795,53 @@ 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 ldev = lChannel*2 + DeviceNumber;
     ULONG i;
     PUCHAR plba;
 
-    KdPrint2((PRINT_PREFIX "AtaCommand48: cntrlr %#x:%#x ldev %#x, cmd %#x, lba %#I64x count %#x feature %#x\n",
-                 deviceExtension->DevIndex, deviceExtension->Channel, ldev, command, lba, count, feature ));
+    KdPrint2((PRINT_PREFIX "AtaCommand48: cntrlr %#x:%#x dev %#x, cmd %#x, lba %#I64x count %#x feature %#x\n",
+                 deviceExtension->DevIndex, deviceExtension->Channel, DeviceNumber, command, lba, count, feature ));
 
-    //if(!(deviceExtension->HwFlags & UNIATA_SATA)) {
-        SelectDrive(chan, DeviceNumber);
+    if(deviceExtension->HwFlags & UNIATA_AHCI) {
+        //PIDE_AHCI_CMD  AHCI_CMD = &(chan->AhciCtlBlock->cmd);
 
-        statusByte = WaitOnBusy(chan);
+        KdPrint3(("  (ahci)\n"));
 
-        /* ready to issue command ? */
-        if (statusByte & IDE_STATUS_BUSY) {
-            KdPrint2((PRINT_PREFIX "  Returning BUSY status\n"));
-            return statusByte;
-        }
-    //}
+        statusByte = UniataAhciSendPIOCommand(deviceExtension, lChannel, DeviceNumber,
+            (PSCSI_REQUEST_BLOCK)NULL,
+            NULL,
+            0,
+            command,
+            lba, count,
+            feature,
+            0 /* ahci flags */ ,
+            wait_flags,
+            1000 /* timeout 1 sec */
+            );
+
+        return statusByte;
+    }
+
+    SelectDrive(chan, DeviceNumber);
+
+    statusByte = WaitOnBusy(chan);
+
+    /* ready to issue command ? */
+    if (statusByte & IDE_STATUS_BUSY) {
+        KdPrint2((PRINT_PREFIX "  Returning BUSY status\n"));
+        return statusByte;
+    }
     // !!! We should not check ERROR condition here
     // ERROR bit may be asserted durring previous operation
     // and not cleared after SELECT
 
     //>>>>>> NV: 2006/08/03
-    if((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) &&
-       CheckIfBadBlock(&(deviceExtension->lun[ldev]), lba, count)) {
+    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;
         //return SRB_STATUS_ERROR;
@@ -776,10 +849,10 @@ AtaCommand48(
     //<<<<<< NV:  2006/08/03
 
     /* only use 48bit addressing if needed because of the overhead */
-    if ((lba >= ATA_MAX_LBA28 || count > 256) &&
-        deviceExtension->lun[ldev].IdentifyData.FeaturesSupport.Address48) {
+    if (UniAta_need_lba48(command, lba, count,
+        chan->lun[DeviceNumber]->IdentifyData.FeaturesSupport.Address48)) {
 
-        KdPrint2((PRINT_PREFIX "  ldev %#x USE_LBA_48\n", ldev ));
+        KdPrint2((PRINT_PREFIX "  dev %#x USE_LBA_48\n", DeviceNumber ));
         /* translate command into 48bit version */
         if(AtaCommandFlags[command] & ATA_CMD_FLAG_48supp) {
             command = AtaCommands48[command];
@@ -802,7 +875,7 @@ AtaCommand48(
         AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)(plba[5]));
         AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)(plba[2]));
 
-        //KdPrint2((PRINT_PREFIX "AtaCommand48: ldev %#x USE_LBA48 (2)\n", ldev ));
+        //KdPrint2((PRINT_PREFIX "AtaCommand48: dev %#x USE_LBA48 (2)\n", DeviceNumber ));
         AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_2 : IDE_DRIVE_1) );
     } else {
 
@@ -810,18 +883,18 @@ AtaCommand48(
         chan->ChannelCtrlFlags &= ~CTRFLAGS_LBA48;
         
         //if(feature ||
-        //   (deviceExtension->lun[ldev].DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_TAPE_DEVICE | DFLAGS_LBA_ENABLED))) {
+        //   (chan->lun[DeviceNumber]->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_TAPE_DEVICE | DFLAGS_LBA_ENABLED))) {
             AtapiWritePort1(chan, IDX_IO1_o_Feature,      (UCHAR)feature);
         //}
         AtapiWritePort1(chan, IDX_IO1_o_BlockCount,   (UCHAR)count);
         AtapiWritePort1(chan, IDX_IO1_o_BlockNumber,  (UCHAR)plba[0]);
         AtapiWritePort1(chan, IDX_IO1_o_CylinderLow,  (UCHAR)plba[1]);
         AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)plba[2]);
-        if(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_LBA_ENABLED) {
-            //KdPrint2((PRINT_PREFIX "AtaCommand28: ldev %#x USE_LBA\n", ldev ));
+        if(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_LBA_ENABLED) {
+            //KdPrint2((PRINT_PREFIX "AtaCommand28: dev %#x USE_LBA\n", DeviceNumber ));
             AtapiWritePort1(chan, IDX_IO1_o_DriveSelect,  (UCHAR)(plba[3] & 0xf) | IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1) );
         } else {
-            //KdPrint2((PRINT_PREFIX "AtaCommand28: ldev %#x USE_CHS\n", ldev ));
+            //KdPrint2((PRINT_PREFIX "AtaCommand28: dev %#x USE_CHS\n", DeviceNumber ));
             AtapiWritePort1(chan, IDX_IO1_o_DriveSelect,  (UCHAR)(plba[3] & 0xf) | (DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1) );
         }
     }
@@ -829,7 +902,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
@@ -851,7 +924,7 @@ AtaCommand48(
 
             GetStatus(chan, statusByte);
             statusByte = UniataIsIdle(deviceExtension, statusByte);
-            if(statusByte == 0xff) {
+            if(statusByte == IDE_STATUS_WRONG) {
                 // no drive ?
                 break;
             } else
@@ -891,7 +964,7 @@ AtaCommand48(
             KdPrint2((PRINT_PREFIX "  try to continue\n"));
             statusByte &= ~IDE_STATUS_ERROR;
         }
-        chan->ExpectingInterrupt = TRUE;
+        UniataExpectChannelInterrupt(chan, TRUE);
         // !!!!!
         InterlockedExchange(&(chan->CheckIntr),
                                       CHECK_INTR_IDLE);
@@ -920,13 +993,29 @@ AtaCommand(
     IN UCHAR sector,
     IN UCHAR count,
     IN UCHAR feature,
-    IN ULONG flags
+    IN ULONG wait_flags
     )
 {
-    return AtaCommand48(deviceExtension, DeviceNumber, lChannel,
-                        command,
-                        (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
-                        count, feature, flags);
+    if(!(deviceExtension->HwFlags & UNIATA_AHCI)) {
+        return AtaCommand48(deviceExtension, DeviceNumber, lChannel,
+                            command,
+                            (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
+                            count, feature, wait_flags);
+    } else {
+        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 */
+            );
+
+    }
 } // end AtaCommand()
 
 LONG
@@ -962,7 +1051,7 @@ AtaPioMode(PIDENTIFY_DATA2 ident)
         return 1;
     if (ident->PioCycleTimingMode == 0)
         return 0;
-    return -1;
+    return IOMODE_NOT_SPECIFIED;
 } // end AtaPioMode()
 
 LONG
@@ -975,7 +1064,7 @@ AtaWmode(PIDENTIFY_DATA2 ident)
         return 1;
     if (ident->MultiWordDMASupport & 0x01)
         return 0;
-    return -1;
+    return IOMODE_NOT_SPECIFIED;
 } // end AtaWmode()
 
 LONG
@@ -983,7 +1072,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)
@@ -998,9 +1087,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
 
@@ -1025,7 +1132,7 @@ AtapiTimerDpc(
         KdPrint2((PRINT_PREFIX "AtapiTimerDpc: no items\n"));
         return;
     }
-    chan = &deviceExtension->chan[lChannel];
+    chan = &(deviceExtension->chan[lChannel]);
 
     while(TRUE) {
 
@@ -1114,13 +1221,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 {
@@ -1146,6 +1253,7 @@ AtapiQueueTimerDpc(
 
 #endif //UNIATA_CORE
 
+#if DBG
 VOID
 NTAPI
 UniataDumpATARegs(
@@ -1176,6 +1284,43 @@ UniataDumpATARegs(
     }
     return;
 } // end UniataDumpATARegs()
+#endif
+
+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()
 
 /*++
 
@@ -1205,17 +1350,28 @@ 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;
-    ULONG                ldev = (lChannel * 2) + DeviceNumber;
-    PHW_LU_EXTENSION     LunExt = &(deviceExtension->lun[ldev]);
+    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
+        } else {
+            KdPrint2((PRINT_PREFIX "IssueIdentify: PM empty port\n"));
+            return FALSE;
+        }
+    } else
     if(DeviceNumber && (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE)) {
         KdPrint2((PRINT_PREFIX "IssueIdentify: NO SLAVE\n"));
         return FALSE;
@@ -1225,13 +1381,20 @@ IssueIdentify(
         return FALSE;
     }
 
-    SelectDrive(chan, DeviceNumber);
-    AtapiStallExecution(10);
-    statusByte = WaitOnBusyLong(chan);
-    // Check that the status register makes sense.
-    GetBaseStatus(chan, statusByte2);
-
-    UniataDumpATARegs(chan);
+    if(use_ahci) {
+        statusByte = WaitOnBusyLong(chan);
+#if DBG
+        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, statusByte);
+    }
 
     if (Command == IDE_COMMAND_IDENTIFY) {
         // Mask status byte ERROR bits.
@@ -1255,7 +1418,7 @@ IssueIdentify(
                 if (signatureLow == ATAPI_MAGIC_LSB &&
                     signatureHigh == ATAPI_MAGIC_MSB) {
                     // Device is Atapi.
-                    KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (ldev %d)\n", ldev));
+                    KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (dev %d)\n", DeviceNumber));
                     return FALSE;
                 }
 
@@ -1266,13 +1429,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.
@@ -1281,7 +1448,7 @@ IssueIdentify(
 
             if (signatureLow == ATAPI_MAGIC_LSB &&
                 signatureHigh == ATAPI_MAGIC_MSB) {
-                KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (2) (ldev %d)\n", ldev));
+                KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (2) (dev %d)\n", DeviceNumber));
                 // Device is Atapi.
                 return FALSE;
             }
@@ -1289,12 +1456,15 @@ IssueIdentify(
             statusByte = UniataIsIdle(deviceExtension, statusByte) & ~IDE_STATUS_INDEX;
             if (statusByte != IDE_STATUS_IDLE) {
                 // Give up on this.
-                KdPrint2((PRINT_PREFIX "IssueIdentify: no dev (ldev %d)\n", ldev));
+                KdPrint2((PRINT_PREFIX "IssueIdentify: no dev (dev %d)\n", DeviceNumber));
                 return FALSE;
             }
         }
     } 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);
@@ -1304,14 +1474,37 @@ 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;
+        j = 4; // skip old-style checks
     } else {
         j = 0;
     }
     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 & IDE_STATUS_DRQ) {
@@ -1319,14 +1512,16 @@ IssueIdentify(
             KdPrint2((PRINT_PREFIX "IssueIdentify: IDE_STATUS_DRQ (%#x)\n", statusByte));
             GetBaseStatus(chan, statusByte);
             // One last check for Atapi.
-            signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
-            signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
+            if (Command == IDE_COMMAND_IDENTIFY) {
+                signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
+                signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
 
-            if (signatureLow == ATAPI_MAGIC_LSB &&
-                signatureHigh == ATAPI_MAGIC_MSB) {
-                KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (3) (ldev %d)\n", ldev));
-                // Device is Atapi.
-                return FALSE;
+                if (signatureLow == ATAPI_MAGIC_LSB &&
+                    signatureHigh == ATAPI_MAGIC_MSB) {
+                    KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (3) (dev %d)\n", DeviceNumber));
+                    // Device is Atapi.
+                    return FALSE;
+                }
             }
             break;
         } else {
@@ -1339,11 +1534,16 @@ IssueIdentify(
                 if (signatureLow == ATAPI_MAGIC_LSB &&
                     signatureHigh == ATAPI_MAGIC_MSB) {
                     // Device is Atapi.
-                    KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (4) (ldev %d)\n", ldev));
+                    KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (4) (dev %d)\n", DeviceNumber));
                     return FALSE;
                 }
+            } else {
+                if(!(statusByte & IDE_STATUS_ERROR) && (statusByte & IDE_STATUS_BUSY)) {
+                    KdPrint2((PRINT_PREFIX "IssueIdentify: DRQ not asserted immediately, BUSY -> WaitForDrq\n"));
+                    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);
@@ -1364,65 +1564,57 @@ 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 (!(statusByte & IDE_STATUS_DRQ)) {
-        KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (2) (%#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);
-        return FALSE;
-    }
-    GetBaseStatus(chan, statusByte);
-    KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte));
+    } else {
 
-    if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
+        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));
 
-        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;
+        if (!(statusByte & IDE_STATUS_DRQ)) {
+            KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (2) (%#x)\n", statusByte));
+            GetBaseStatus(chan, statusByte);
+            return FALSE;
         }
-#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);
-    }
+        GetBaseStatus(chan, statusByte);
+        KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte));
 
-    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) {
@@ -1440,18 +1632,40 @@ 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, cur %d\n",
+        deviceExtension->FullIdentifyData.CfAdvPowerMode
+        ));
 
     // Check out a few capabilities / limitations of the device.
     if (deviceExtension->FullIdentifyData.RemovableStatus & 1) {
         // Determine if this drive supports the MSN functions.
         KdPrint2((PRINT_PREFIX "IssueIdentify: Marking drive %d as removable. SFE = %d\n",
-                    ldev,
+                    DeviceNumber,
                     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 =
@@ -1464,7 +1678,7 @@ IssueIdentify(
         ULONGLONG cylinders=0;
         ULONGLONG tmp_cylinders=0;
         // Read very-old-style drive geometry
-        KdPrint2((PRINT_PREFIX "CHS %#x:%#x:%#x\n",
+        KdPrint2((PRINT_PREFIX "CHS %#x:%#x:%#x\n", 
                 deviceExtension->FullIdentifyData.NumberOfCylinders,
                 deviceExtension->FullIdentifyData.NumberOfHeads,
                 deviceExtension->FullIdentifyData.SectorsPerTrack
@@ -1478,7 +1692,7 @@ IssueIdentify(
 /*            (deviceExtension->FullIdentifyData.TranslationFieldsValid) &&*/
             (NumOfSectors < deviceExtension->FullIdentifyData.UserAddressableSectors)) {
             KdPrint2((PRINT_PREFIX "NumberOfCylinders == 0x3fff\n"));
-            cylinders =
+            cylinders = 
                 (deviceExtension->FullIdentifyData.UserAddressableSectors /
                     (deviceExtension->FullIdentifyData.NumberOfHeads *
                        deviceExtension->FullIdentifyData.SectorsPerTrack));
@@ -1516,13 +1730,13 @@ IssueIdentify(
                (deviceExtension->FullIdentifyData.UserAddressableSectors48 > NumOfSectors)
                ) {
                 KdPrint2((PRINT_PREFIX "LBA48\n"));
-                cylinders =
+                cylinders = 
                     (deviceExtension->FullIdentifyData.UserAddressableSectors48 /
                         (deviceExtension->FullIdentifyData.NumberOfHeads *
                            deviceExtension->FullIdentifyData.SectorsPerTrack));
 
                 KdPrint2((PRINT_PREFIX "cylinders %#I64x\n", cylinders));
-
+                
                 NativeNumOfSectors = cylinders *
                                deviceExtension->FullIdentifyData.NumberOfHeads *
                                deviceExtension->FullIdentifyData.SectorsPerTrack;
@@ -1544,21 +1758,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
@@ -1572,13 +1789,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)
+                                                ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 40) 
                                                 ;
+                            }
                         }
 
                         if((NativeNumOfSectors & 0xffffff) == ((NativeNumOfSectors >> 24) & 0xffffff)) {
@@ -1599,9 +1820,9 @@ IssueIdentify(
                             NumOfSectors = NativeNumOfSectors;
                         }
                     }
-                }
+                } // !error
             }
-
+    
             if(NumOfSectors < 0x2100000 /*&& NumOfSectors > 31*1000*1000*/) {
                 // check for native LBA size
                 // some drives report ~32Gb in Identify Block
@@ -1611,11 +1832,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) {
@@ -1658,7 +1882,6 @@ IssueIdentify(
                 }
             }
         }
-        KdPrint2((PRINT_PREFIX "final LunExt->opt_GeomType=%x\n", LunExt->opt_GeomType));
 
         if(LunExt->opt_GeomType == GEOM_STD) {
             deviceExtension->FullIdentifyData.CurrentSectorsPerTrack =
@@ -1798,12 +2021,16 @@ SetDriveParameters(
     )
 {
     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
-    PIDENTIFY_DATA2      identifyData   = &deviceExtension->lun[(lChannel * 2) + DeviceNumber].IdentifyData;
+    PIDENTIFY_DATA2      identifyData;
+    PHW_LU_EXTENSION     LunExt;
 //    ULONG i;
     UCHAR statusByte;
     UCHAR errorByte;
 
-    if(deviceExtension->lun[(lChannel * 2) + DeviceNumber].DeviceFlags &
+    LunExt = deviceExtension->chan[lChannel].lun[DeviceNumber];
+    identifyData = &(LunExt->IdentifyData);
+
+    if(LunExt->DeviceFlags &
           (DFLAGS_LBA_ENABLED | DFLAGS_ORIG_GEOMETRY))
        return TRUE;
 
@@ -1838,7 +2065,9 @@ UniataForgetDevice(
     PHW_LU_EXTENSION   LunExt
     )
 {
+    // keep only DFLAGS_HIDDEN flag
     LunExt->DeviceFlags &= DFLAGS_HIDDEN;
+    LunExt->AtapiReadyWaitDelay = 0;
 } // end UniataForgetDevice()
 
 
@@ -1846,6 +2075,7 @@ UniataForgetDevice(
 
 Routine Description:
     Reset IDE controller and/or Atapi device.
+    ->HwResetBus
 
 Arguments:
     HwDeviceExtension - HBA miniport driver's adapter data storage
@@ -1862,11 +2092,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__(
@@ -1879,7 +2108,7 @@ AtapiResetController__(
     ULONG                numberChannels  = deviceExtension->NumberChannels;
     PHW_CHANNEL          chan = NULL;
     ULONG i,j;
-    ULONG max_ldev;
+    ULONG MaxLuns;
     UCHAR statusByte;
     PSCSI_REQUEST_BLOCK CurSrb;
     ULONG ChannelCtrlFlags;
@@ -1893,10 +2122,11 @@ AtapiResetController__(
 #endif
     //ULONG RevID    =  deviceExtension->RevID;
     ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK;
-    UCHAR tmp8;
+    //UCHAR tmp8;
     UCHAR tmp16;
 
     KdPrint2((PRINT_PREFIX "AtapiResetController: Reset IDE %#x/%#x @ %#x\n", VendorID, DeviceID, slotNumber));
+    KdPrint2((PRINT_PREFIX "simplexOnly %d\n", deviceExtension->simplexOnly));
 
     if(!deviceExtension->simplexOnly && (PathId != CHAN_NOT_SPECIFIED)) {
         // we shall reset both channels on SimplexOnly devices,
@@ -1911,20 +2141,22 @@ 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));
-        max_ldev = (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE) ? 1 : 2;
+        chan = &(deviceExtension->chan[j]);
+        MaxLuns = chan->NumberLuns;
+        KdPrint2((PRINT_PREFIX "  CompleteType %#x, Luns %d, chan %#x, sptr %#x\n", CompleteType, MaxLuns, chan, &chan));
+        //MaxLuns = (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE) ? 1 : 2;
         if(CompleteType != RESET_COMPLETE_NONE) {
 #ifndef UNIATA_CORE
             while((CurSrb = UniataGetCurRequest(chan))) {
 
                 PATA_REQ AtaReq = (PATA_REQ)(CurSrb->SrbExtension);
 
-                KdPrint2((PRINT_PREFIX "AtapiResetController: pending SRB %#x\n", CurSrb));
+                KdPrint2((PRINT_PREFIX "AtapiResetController: pending SRB %#x, chan %#x\n", CurSrb, chan));
                 // 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;
@@ -1947,6 +2179,7 @@ AtapiResetController__(
                     if (CurSrb->SenseInfoBuffer) {
 
                         PSENSE_DATA  senseBuffer = (PSENSE_DATA)CurSrb->SenseInfoBuffer;
+                        KdPrint2((PRINT_PREFIX "  senseBuffer %#x, chan %#x\n", senseBuffer, chan));
 
                         senseBuffer->ErrorCode = 0x70;
                         senseBuffer->Valid     = 1;
@@ -1968,6 +2201,7 @@ AtapiResetController__(
                     AtaReq->WordsLeft = 0;
                     AtaReq->DataBuffer = NULL;
                     AtaReq->TransferLength = 0;
+                    KdPrint2((PRINT_PREFIX "chan %#x\n", chan));
 
                     ScsiPortNotification(RequestComplete,
                                          deviceExtension,
@@ -1975,7 +2209,7 @@ AtapiResetController__(
 
                     // Indicate ready for next request.
                     ScsiPortNotification(NextLuRequest,
-                                         deviceExtension,
+                                         deviceExtension, 
                                          PathId,
                                          TargetId,
                                          Lun);
@@ -1989,123 +2223,166 @@ AtapiResetController__(
         // Save control flags
         ChannelCtrlFlags = chan->ChannelCtrlFlags;
         // Clear expecting interrupt flag.
-        chan->ExpectingInterrupt = FALSE;
+        UniataExpectChannelInterrupt(chan, FALSE);
         chan->RDP = FALSE;
         chan->ChannelCtrlFlags = 0;
         InterlockedExchange(&(chan->CheckIntr),
                                       CHECK_INTR_IDLE);
-
+        
+        for (i = 0; i < MaxLuns; i++) {
+            chan->lun[i]->PowerState = 0;
+        }
         // Reset controller
-        KdPrint2((PRINT_PREFIX "  disable intr (0)\n"));
-        AtapiDisableInterrupts(deviceExtension, j);
-        KdPrint2((PRINT_PREFIX "  done\n"));
-        switch(VendorID) {
-        case ATA_INTEL_ID: {
-            ULONG mask;
-            ULONG timeout;
-            if(!(ChipFlags & UNIATA_SATA))
-                goto default_reset;
-            if(!UniataIsSATARangeAvailable(deviceExtension, j)) {
-                goto default_reset;
+        if(ChipFlags & UNIATA_AHCI) {
+            KdPrint2((PRINT_PREFIX "  AHCI path\n"));
+            if(UniataAhciChanImplemented(deviceExtension, j)) {
+#ifdef _DEBUG
+                UniataDumpAhciPortRegs(chan);
+#endif
+                AtapiDisableInterrupts(deviceExtension, j);
+                UniataAhciReset(HwDeviceExtension, j);
+            } else {
+                KdPrint2((PRINT_PREFIX "  skip not implemented\n"));
             }
+        } else {
+            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)) {
+                    goto default_reset;
+                }
+                if(!UniataIsSATARangeAvailable(deviceExtension, j)) {
+                    goto default_reset;
+                }
 
-            /* ICH6 & ICH7 in compat mode has 4 SATA ports as master/slave on 2 ch's */
-            if(ChipFlags & UNIATA_AHCI) {
-                mask = 0x0005 << j;
-            } else {
-                /* ICH5 in compat mode has SATA ports as master/slave on 1 channel */
-                GetPciConfig1(0x90, tmp8);
-                if(tmp8 & 0x04) {
-                    mask = 0x0003;
+#if 0
+                /* ICH6 & ICH7 in compat mode has 4 SATA ports as master/slave on 2 ch's */
+                if(ChipFlags & UNIATA_AHCI) {
+                    mask = 0x0005 << j;
                 } else {
-                    mask = 0x0001 << j;
+                    /* ICH5 in compat mode has SATA ports as master/slave on 1 channel */
+                    GetPciConfig1(0x90, tmp8);
+                    if(tmp8 & 0x04) {
+                        mask = 0x0003;
+                    } else {
+                        mask = 0x0001 << j;
+                    }
                 }
-            }
-            ChangePciConfig2(0x92, a & ~mask);
-            AtapiStallExecution(10);
-            ChangePciConfig2(0x92, a | mask);
-            timeout = 100;
-            while (timeout--) {
-                AtapiStallExecution(10000);
-                GetPciConfig2(0x92, tmp16);
-                if ((tmp16 & (mask << 4)) == (mask << 4)) {
-                    AtapiStallExecution(10000);
-                    break;
+#else
+                mask = 1 << chan->lun[0]->SATA_lun_map;
+                if (MaxLuns > 1) {
+                    mask |= (1 << chan->lun[1]->SATA_lun_map);
                 }
-            }
-            break; }
-        case ATA_SIS_ID:
-        case ATA_NVIDIA_ID: {
-            KdPrint2((PRINT_PREFIX "  SIS/nVidia\n"));
-            if(!(ChipFlags & UNIATA_SATA))
-                goto default_reset;
-            break; }
-        case ATA_SILICON_IMAGE_ID: {
-            ULONG offset;
-            ULONG Channel = deviceExtension->Channel + j;
-            if(!(ChipFlags & UNIATA_SATA))
-                goto default_reset;
-            offset = ((Channel & 1) << 7) + ((Channel & 2) << 8);
-            /* disable PHY state change interrupt */
-            AtapiWritePortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0, 0x148 + offset, 0);
-
-            UniataSataClearErr(HwDeviceExtension, j, UNIATA_SATA_IGNORE_CONNECT);
-
-            /* reset controller part for this channel */
-            AtapiWritePortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0, 0x48,
-                 AtapiReadPortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0, 0x48) | (0xc0 >> Channel));
-            AtapiStallExecution(1000);
-            AtapiWritePortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0, 0x48,
-                 AtapiReadPortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0, 0x48) & ~(0xc0 >> Channel));
-
+#endif
+                ChangePciConfig2(0x92, a & ~mask);
+                AtapiStallExecution(10);
+                ChangePciConfig2(0x92, a | mask);
+                timeout = 100;
 
-            break; }
-        case ATA_PROMISE_ID: {
-            break; }
-        default:
-            if(ChipFlags & UNIATA_SATA) {
-                KdPrint2((PRINT_PREFIX "  SATA generic reset\n"));
-                UniataSataClearErr(HwDeviceExtension, j, UNIATA_SATA_IGNORE_CONNECT);
-            }
+                /* Wait up to 1 sec for "connect well". */
+                if (ChipFlags & (I6CH | I6CH2)) {
+                    pshift = 8;
+                } else {
+                    pshift = 4;
+                }
+                while (timeout--) {
+                    GetPciConfig2(0x92, tmp16);
+                    if (((tmp16 >> pshift) & mask) == mask) {
+                        GetBaseStatus(chan, statusByte);
+                        if(statusByte != IDE_STATUS_WRONG) {
+                            break;
+                        }
+                    }
+                    AtapiStallExecution(10000);
+                }
+                break; }
+            case ATA_SIS_ID:
+            case ATA_NVIDIA_ID: {
+                KdPrint2((PRINT_PREFIX "  SIS/nVidia\n"));
+                if(!(ChipFlags & UNIATA_SATA))
+                    goto default_reset;
+                break; }
+            case ATA_SILICON_IMAGE_ID: {
+                ULONG offset;
+                ULONG Channel = deviceExtension->Channel + j;
+                if(!(ChipFlags & UNIATA_SATA))
+                    goto default_reset;
+                offset = ((Channel & 1) << 7) + ((Channel & 2) << 8);
+                /* disable PHY state change interrupt */
+                AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x148 + offset, 0);
+
+                UniataSataClearErr(HwDeviceExtension, j, UNIATA_SATA_IGNORE_CONNECT, 0);
+
+                /* reset controller part for this channel */
+                AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x48,
+                     AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x48) | (0xc0 >> Channel));
+                AtapiStallExecution(1000);
+                AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x48,
+                     AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x48) & ~(0xc0 >> Channel));
+
+
+                break; }
+            case ATA_PROMISE_ID: {
+                break; }
+            default:
+                if(ChipFlags & UNIATA_SATA) {
+                    KdPrint2((PRINT_PREFIX "  SATA generic reset\n"));
+                    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 );
-            KdPrint2((PRINT_PREFIX "  wait a little\n"));
-            AtapiStallExecution(10000);
-            // Disable interrupts
-            KdPrint2((PRINT_PREFIX "  disable intr\n"));
-            AtapiDisableInterrupts(deviceExtension, j);
-            AtapiStallExecution(100);
-            KdPrint2((PRINT_PREFIX "  re-enable intr\n"));
-            AtapiEnableInterrupts(deviceExtension, j);
-            KdPrint2((PRINT_PREFIX "  wait a little (2)\n"));
-            AtapiStallExecution(100000);
-            KdPrint2((PRINT_PREFIX "  done\n"));
+                KdPrint2((PRINT_PREFIX "  send reset\n"));
+                AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_DISABLE_INTERRUPTS |
+                                                                        IDE_DC_RESET_CONTROLLER );
+                KdPrint2((PRINT_PREFIX "  wait a little\n"));
+                AtapiStallExecution(10000);
+                // Disable interrupts
+                KdPrint2((PRINT_PREFIX "  disable intr\n"));
+                AtapiDisableInterrupts(deviceExtension, j);
+                AtapiStallExecution(100);
+                KdPrint2((PRINT_PREFIX "  re-enable intr\n"));
+                AtapiEnableInterrupts(deviceExtension, j);
+                KdPrint2((PRINT_PREFIX "  wait a little (2)\n"));
+                AtapiStallExecution(100000);
+                KdPrint2((PRINT_PREFIX "  done\n"));
 
-            break;
-        }
+                break;
+            } // end switch()
 
-        //if(!(ChipFlags & UNIATA_SATA)) {
-        if(!UniataIsSATARangeAvailable(deviceExtension, j)) {
-            // Reset DMA engine if active
-            KdPrint2((PRINT_PREFIX "  check DMA engine\n"));
-            dma_status = GetDmaStatus(chan->DeviceExtension, chan->lChannel);
-            KdPrint2((PRINT_PREFIX "  DMA status %#x\n", dma_status));
-            if((ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) ||
-               (dma_status & BM_STATUS_INTR)) {
-                AtapiDmaDone(HwDeviceExtension, 0, j, NULL);
+            //if(!(ChipFlags & UNIATA_SATA)) {}
+            if(!UniataIsSATARangeAvailable(deviceExtension, j)) {
+                // Reset DMA engine if active
+                KdPrint2((PRINT_PREFIX "  check DMA engine\n"));
+                dma_status = GetDmaStatus(chan->DeviceExtension, chan->lChannel);
+                KdPrint2((PRINT_PREFIX "  DMA status %#x\n", dma_status));
+                if((ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) ||
+                   (dma_status & BM_STATUS_INTR)) {
+                    AtapiDmaDone(HwDeviceExtension, 0, j, NULL);
+                }
             }
-        }
+        } // ATA vs AHCI
 
         // 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 < max_ldev; i++) {
+        for (i = 0; i < MaxLuns; i++) {
 
             // Check if device present.
-            if (!(deviceExtension->lun[i + (j * 2)].DeviceFlags & DFLAGS_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()
+                    KdPrint2((PRINT_PREFIX "  device have gone\n"));
+                    continue;
+                }
 #ifdef NAVO_TEST
                 continue;
 #else //NAVO_TEST
@@ -2117,9 +2394,23 @@ default_reset:
                     continue;
                 }
             } else {
-                if(!UniataAnybodyHome(HwDeviceExtension, j, i)) {
-                    KdPrint2((PRINT_PREFIX "  device have gone\n"));
-                    UniataForgetDevice(&(deviceExtension->lun[i + (j * 2)]));
+                if(ChipFlags & UNIATA_AHCI) {
+                    // everything is done in UniataAhciReset()
+                    KdPrint2((PRINT_PREFIX "  found some device\n"));
+
+                    if(!IssueIdentify(HwDeviceExtension,
+                                  i, j,
+                             ATAPI_DEVICE(chan, i) ?
+                                  IDE_COMMAND_ATAPI_IDENTIFY : IDE_COMMAND_IDENTIFY,
+                                  FALSE)) {
+                        KdPrint2((PRINT_PREFIX "  identify failed !\n"));
+                        UniataForgetDevice(chan->lun[i]);
+                    }
+                    continue;
+                }
+                if(!UniataAnybodyHome(HwDeviceExtension, j, i)) {
+                    KdPrint2((PRINT_PREFIX "  device have gone\n"));
+                    UniataForgetDevice(chan->lun[i]);
                 }
 #endif //NAVO_TEST
             }
@@ -2128,14 +2419,14 @@ default_reset:
             AtapiStallExecution(10);
             statusByte = WaitOnBusyLong(chan);
             statusByte = UniataIsIdle(deviceExtension, statusByte);
-            if(statusByte == 0xff) {
-                KdPrint2((PRINT_PREFIX
+            if(statusByte == IDE_STATUS_WRONG) {
+                KdPrint2((PRINT_PREFIX 
                            "no drive, status %#x\n",
                            statusByte));
-                UniataForgetDevice(&(deviceExtension->lun[i + (j * 2)]));
+                UniataForgetDevice(chan->lun[i]);
             } else
             // Check for ATAPI disk.
-            if (deviceExtension->lun[i + (j * 2)].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",
@@ -2154,7 +2445,7 @@ default_reset:
                                   IDE_COMMAND_ATAPI_IDENTIFY, FALSE);
                 } else {
 
-                    KdPrint2((PRINT_PREFIX
+                    KdPrint2((PRINT_PREFIX 
                                "AtapiResetController: Status after soft reset %#x\n",
                                statusByte));
                 }
@@ -2182,11 +2473,11 @@ default_reset:
                 GetBaseStatus(chan, statusByte);
             }
             // force DMA mode reinit
-            deviceExtension->lun[i + (j * 2)].DeviceFlags |= DFLAGS_REINIT_DMA;
+            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,
@@ -2195,7 +2486,7 @@ default_reset:
 
         // Call the HwInitialize routine to setup multi-block.
         AtapiHwInitialize__(deviceExtension, j);
-    }
+    } // for(channel)
     ScsiPortNotification(NextRequest, deviceExtension, NULL);
 
     return TRUE;
@@ -2227,24 +2518,33 @@ 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 ldev = GET_LDEV(Srb);
+    ULONG DeviceNumber = GET_CDEV(Srb);
+    PHW_LU_EXTENSION     LunExt = chan->lun[DeviceNumber];
 
     // Read the error register.
 
-    errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
-    KdPrint2((PRINT_PREFIX
+    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));
 
-    if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) {
+    if (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
 
         switch (errorByte >> 4) {
         case SCSI_SENSE_NO_SENSE:
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "ATAPI: No sense information\n"));
             scsiStatus = SCSISTAT_CHECK_CONDITION;
             srbStatus = SRB_STATUS_ERROR;
@@ -2252,7 +2552,7 @@ MapError(
 
         case SCSI_SENSE_RECOVERED_ERROR:
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "ATAPI: Recovered error\n"));
             scsiStatus = 0;
             srbStatus = SRB_STATUS_SUCCESS;
@@ -2260,7 +2560,7 @@ MapError(
 
         case SCSI_SENSE_NOT_READY:
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "ATAPI: Device not ready\n"));
             scsiStatus = SCSISTAT_CHECK_CONDITION;
             srbStatus = SRB_STATUS_ERROR;
@@ -2268,7 +2568,7 @@ MapError(
 
         case SCSI_SENSE_MEDIUM_ERROR:
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "ATAPI: Media error\n"));
             scsiStatus = SCSISTAT_CHECK_CONDITION;
             srbStatus = SRB_STATUS_ERROR;
@@ -2276,7 +2576,7 @@ MapError(
 
         case SCSI_SENSE_HARDWARE_ERROR:
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "ATAPI: Hardware error\n"));
             scsiStatus = SCSISTAT_CHECK_CONDITION;
             srbStatus = SRB_STATUS_ERROR;
@@ -2284,7 +2584,7 @@ MapError(
 
         case SCSI_SENSE_ILLEGAL_REQUEST:
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "ATAPI: Illegal request\n"));
             scsiStatus = SCSISTAT_CHECK_CONDITION;
             srbStatus = SRB_STATUS_ERROR;
@@ -2292,7 +2592,7 @@ MapError(
 
         case SCSI_SENSE_UNIT_ATTENTION:
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "ATAPI: Unit attention\n"));
             scsiStatus = SCSISTAT_CHECK_CONDITION;
             srbStatus = SRB_STATUS_ERROR;
@@ -2300,7 +2600,7 @@ MapError(
 
         case SCSI_SENSE_DATA_PROTECT:
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "ATAPI: Data protect\n"));
             scsiStatus = SCSISTAT_CHECK_CONDITION;
             srbStatus = SRB_STATUS_ERROR;
@@ -2308,14 +2608,14 @@ MapError(
 
         case SCSI_SENSE_BLANK_CHECK:
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "ATAPI: Blank check\n"));
             scsiStatus = SCSISTAT_CHECK_CONDITION;
             srbStatus = SRB_STATUS_ERROR;
             break;
 
         case SCSI_SENSE_ABORTED_COMMAND:
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                         "Atapi: Command Aborted\n"));
             scsiStatus = SCSISTAT_CHECK_CONDITION;
             srbStatus = SRB_STATUS_ERROR;
@@ -2323,7 +2623,7 @@ MapError(
 
         default:
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "ATAPI: Invalid sense information\n"));
             scsiStatus = 0;
             srbStatus = SRB_STATUS_ERROR;
@@ -2338,7 +2638,7 @@ MapError(
         chan->ReturningMediaStatus = errorByte;
 
         if (errorByte & IDE_ERROR_MEDIA_CHANGE_REQ) {
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "IDE: Media change\n"));
             scsiStatus = SCSISTAT_CHECK_CONDITION;
             srbStatus = SRB_STATUS_ERROR;
@@ -2358,7 +2658,7 @@ MapError(
             }
 
         } else if (errorByte & IDE_ERROR_COMMAND_ABORTED) {
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "IDE: Command abort\n"));
             srbStatus = SRB_STATUS_ABORTED;
             scsiStatus = SCSISTAT_CHECK_CONDITION;
@@ -2377,11 +2677,11 @@ MapError(
                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
             }
 
-            deviceExtension->lun[ldev].ErrorCount++;
+            LunExt->ErrorCount++;
 
         } else if (errorByte & IDE_ERROR_END_OF_MEDIA) {
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "IDE: End of media\n"));
             scsiStatus = SCSISTAT_CHECK_CONDITION;
             srbStatus = SRB_STATUS_ERROR;
@@ -2401,13 +2701,13 @@ MapError(
                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
             }
 
-            if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)){
-                deviceExtension->lun[ldev].ErrorCount++;
+            if (!(LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)){
+                LunExt->ErrorCount++;
             }
 
         } else if (errorByte & IDE_ERROR_ILLEGAL_LENGTH) {
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "IDE: Illegal length\n"));
             srbStatus = SRB_STATUS_INVALID_REQUEST;
 
@@ -2428,7 +2728,7 @@ MapError(
 
         } else if (errorByte & IDE_ERROR_BAD_BLOCK) {
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "IDE: Bad block\n"));
             srbStatus = SRB_STATUS_ERROR;
             scsiStatus = SCSISTAT_CHECK_CONDITION;
@@ -2448,7 +2748,7 @@ MapError(
 
         } else if (errorByte & IDE_ERROR_ID_NOT_FOUND) {
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "IDE: Id not found\n"));
             srbStatus = SRB_STATUS_ERROR;
             scsiStatus = SCSISTAT_CHECK_CONDITION;
@@ -2467,11 +2767,11 @@ MapError(
                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
             }
 
-            deviceExtension->lun[ldev].ErrorCount++;
+            LunExt->ErrorCount++;
 
         } else if (errorByte & IDE_ERROR_MEDIA_CHANGE) {
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "IDE: Media change\n"));
             scsiStatus = SCSISTAT_CHECK_CONDITION;
             srbStatus = SRB_STATUS_ERROR;
@@ -2492,13 +2792,13 @@ MapError(
 
         } else if (errorByte & IDE_ERROR_DATA_ERROR) {
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                    "IDE: Data error\n"));
             scsiStatus = SCSISTAT_CHECK_CONDITION;
             srbStatus = SRB_STATUS_ERROR;
 
-            if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)){
-                deviceExtension->lun[ldev].ErrorCount++;
+            if (!(LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)){
+                LunExt->ErrorCount++;
             }
 
             // Build sense buffer
@@ -2517,21 +2817,21 @@ MapError(
             }
         }
 
-        if (deviceExtension->lun[ldev].ErrorCount >= MAX_ERRORS) {
+        if (LunExt->ErrorCount >= MAX_ERRORS) {
 //            deviceExtension->DWordIO = FALSE;
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                         "MapError: ErrorCount >= MAX_ERRORS\n"));
 
-            deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_DWORDIO_ENABLED;
-            deviceExtension->lun[ldev].MaximumBlockXfer = 0;
+            LunExt->DeviceFlags &= ~DFLAGS_DWORDIO_ENABLED;
+            LunExt->MaximumBlockXfer = 0;
             BrutePoint();
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                         "MapError: Disabling 32-bit PIO and Multi-sector IOs\n"));
 
             // Log the error.
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                         "ScsiPortLogError: devExt %#x, Srb %#x, P:T:D=%d:%d:%d, MsgId %#x (%d)\n",
                               HwDeviceExtension,
                               Srb,
@@ -2552,10 +2852,10 @@ MapError(
             // Reprogram to not use Multi-sector.
             UCHAR statusByte;
 
-            if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT &&
-                 !(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
+            if (LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT &&
+                 !(LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_MANUAL_CHS))) {
 
-                statusByte = AtaCommand(deviceExtension, ldev & 0x1, lChannel, IDE_COMMAND_SET_MULTIPLE, 0, 0, 0, 0, 0, ATA_WAIT_BASE_READY);
+                statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_SET_MULTIPLE, 0, 0, 0, 0, 0, ATA_WAIT_BASE_READY);
 
                 // Check for errors. Reset the value to 0 (disable MultiBlock) if the
                 // command was aborted.
@@ -2569,7 +2869,7 @@ MapError(
                                 errorByte));
 
                     // Adjust the devExt. value, if necessary.
-                    deviceExtension->lun[ldev].MaximumBlockXfer = 0;
+                    LunExt->MaximumBlockXfer = 0;
                     BrutePoint();
 
                 }
@@ -2591,6 +2891,7 @@ Routine Description:
 
 Arguments:
     HwDeviceExtension - HBA miniport driver's adapter data storage
+    ->HwInitialize
 
 Return Value:
     TRUE - if initialization successful.
@@ -2612,6 +2913,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);
@@ -2642,14 +2948,19 @@ 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);
 
-    for (i = lChannel*2; i < (lChannel+1)*2; i++) {
+    for (i = 0; i < chan->NumberLuns; i++) {
 
         KdPrint3((PRINT_PREFIX "AtapiHwInitialize: lChannel %#x, dev %x\n", lChannel, i));
 
-        LunExt = &(deviceExtension->lun[i]);
+        LunExt = chan->lun[i];
         // skip empty slots
         if (!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
             continue;
@@ -2658,14 +2969,14 @@ 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
-            IdeMediaStatus(TRUE,deviceExtension,(UCHAR)i);
+            IdeMediaStatus(TRUE,deviceExtension,lChannel,(UCHAR)i);
 
             // If supported, setup Multi-block transfers.
-            statusByte = AtaCommand(deviceExtension, i & 1, lChannel,
+            statusByte = AtaCommand(deviceExtension, i, lChannel,
                                 IDE_COMMAND_SET_MULTIPLE, 0, 0, 0,
                                 LunExt->MaximumBlockXfer, 0, ATA_WAIT_BASE_READY);
 
@@ -2680,9 +2991,9 @@ AtapiHwInitialize__(
                             statusByte,
                             errorByte));
 
-                statusByte = AtaCommand(deviceExtension, i & 1, lChannel,
+                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.
@@ -2703,17 +3014,17 @@ AtapiHwInitialize__(
             }
 
             if(LunExt->IdentifyData.MajorRevision) {
-
+            
                 if(LunExt->opt_ReadCacheEnable) {
                     KdPrint2((PRINT_PREFIX "  Try Enable Read Cache\n"));
                     // If supported, setup read/write cacheing
-                    statusByte = AtaCommand(deviceExtension, i & 1, lChannel,
+                    statusByte = AtaCommand(deviceExtension, i, lChannel,
                                         IDE_COMMAND_SET_FEATURES, 0, 0, 0,
                                         0, ATA_C_F_ENAB_RCACHE, ATA_WAIT_BASE_READY);
 
                     // Check for errors.
                     if (statusByte & IDE_STATUS_ERROR) {
-                        KdPrint2((PRINT_PREFIX
+                        KdPrint2((PRINT_PREFIX 
                                     "AtapiHwInitialize: Enable read/write cacheing on Device %d failed\n",
                                     i));
                         LunExt->DeviceFlags &= ~DFLAGS_RCACHE_ENABLED;
@@ -2722,7 +3033,7 @@ AtapiHwInitialize__(
                     }
                 } else {
                     KdPrint2((PRINT_PREFIX "  Disable Read Cache\n"));
-                    statusByte = AtaCommand(deviceExtension, i & 1, lChannel,
+                    statusByte = AtaCommand(deviceExtension, i, lChannel,
                                         IDE_COMMAND_SET_FEATURES, 0, 0, 0,
                                         0, ATA_C_F_DIS_RCACHE, ATA_WAIT_BASE_READY);
                     LunExt->DeviceFlags &= ~DFLAGS_RCACHE_ENABLED;
@@ -2730,12 +3041,12 @@ AtapiHwInitialize__(
                 if(LunExt->opt_WriteCacheEnable) {
                     KdPrint2((PRINT_PREFIX "  Try Enable Write Cache\n"));
                     // If supported & allowed, setup write cacheing
-                    statusByte = AtaCommand(deviceExtension, i & 1, lChannel,
+                    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
+                        KdPrint2((PRINT_PREFIX 
                                     "AtapiHwInitialize: Enable write cacheing on Device %d failed\n",
                                     i));
                         LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
@@ -2744,17 +3055,73 @@ AtapiHwInitialize__(
                     }
                 } else {
                     KdPrint2((PRINT_PREFIX "  Disable Write Cache\n"));
-                    statusByte = AtaCommand(deviceExtension, i & 1, lChannel,
+                    statusByte = AtaCommand(deviceExtension, i, lChannel,
                                         IDE_COMMAND_SET_FEATURES, 0, 0, 0,
-                                        0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY);
+                                        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_IDLE, 0, 0, 0,
+                                        LunExt->opt_StandbyTimer, 0, ATA_WAIT_BASE_READY);
+                    // Check for errors.
+                    if (statusByte & IDE_STATUS_ERROR) {
+                        KdPrint2((PRINT_PREFIX 
+                                    "AtapiHwInitialize: standby timer on Device %d failed\n",
+                                    i));
+                    }
+                }
             }
 
         } 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"));
@@ -2775,13 +3142,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;
         }
@@ -2792,14 +3159,12 @@ AtapiHwInitialize__(
         }
 
         KdPrint2((PRINT_PREFIX "  try mode %#x\n", PreferedMode));
-        LunExt->OrigTransferMode =
         LunExt->LimitedTransferMode =
         LunExt->TransferMode =
             (CHAR)PreferedMode;
 
-        AtapiDmaInit__(deviceExtension, i);
+        AtapiDmaInit__(deviceExtension, LunExt);
 
-        LunExt->OrigTransferMode =
         LunExt->LimitedTransferMode =
             LunExt->TransferMode;
         KdPrint2((PRINT_PREFIX "Using %#x mode\n", LunExt->TransferMode));
@@ -2824,9 +3189,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);
@@ -2834,10 +3202,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);
@@ -2846,7 +3216,7 @@ AtapiHwInitialize__(
 
     return;
 
-} // end AtapiHwInitialize()
+} // end AtapiHwInitialize__()
 
 
 #ifndef UNIATA_CORE
@@ -2859,12 +3229,15 @@ AtapiHwInitializeChanger(
     IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus)
 {
     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
-    ULONG                ldev = GET_LDEV(Srb);
+    ULONG lChannel = GET_CHANNEL(Srb);
+    PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
+    ULONG DeviceNumber = GET_CDEV(Srb);
+    PHW_LU_EXTENSION     LunExt = chan->lun[DeviceNumber];
 
     if (MechanismStatus) {
-        deviceExtension->lun[ldev].DiscsPresent = MechanismStatus->NumberAvailableSlots;
-        if (deviceExtension->lun[ldev].DiscsPresent > 1) {
-            deviceExtension->lun[ldev].DeviceFlags |= DFLAGS_ATAPI_CHANGER;
+        LunExt->DiscsPresent = MechanismStatus->NumberAvailableSlots;
+        if (LunExt->DiscsPresent > 1) {
+            LunExt->DeviceFlags |= DFLAGS_ATAPI_CHANGER;
         }
     }
     return;
@@ -2907,7 +3280,7 @@ AtapiParseArgumentString(
         return 0;
     }
 
-    // Calculate the string length.
+    // Calculate the string length and lower case all characters.
     cptr = String;
     while (*cptr++) {
         stringLength++;
@@ -2942,8 +3315,8 @@ ContinueSearch:
 
     kptr = KeyWord;
     while ((*cptr == *kptr) ||
-           (*cptr <= 'Z' && *cptr + ('a' - 'A') == *kptr) ||
-           (*cptr >= 'a' && *cptr - ('a' - 'A') == *kptr)) {
+           (*cptr >= 'A' && *cptr <= 'Z' && *cptr + ('a' - 'A') == *kptr) ||
+           (*cptr >= 'a' && *cptr <= 'z' && *cptr - ('a' - 'A') == *kptr)) {
         cptr++;
         kptr++;
 
@@ -3085,7 +3458,7 @@ AtapiCallBack__(
         goto ReturnCallback;
     }
 
-#if DBG
+#ifdef DBG
     if (!IS_RDP((srb->Cdb[0]))) {
         KdPrint2((PRINT_PREFIX "AtapiCallBack: Invalid CDB marked as RDP - %#x\n", srb->Cdb[0]));
     }
@@ -3114,7 +3487,7 @@ AtapiCallBack__(
 
         // Ask for next request.
         ScsiPortNotification(NextLuRequest,
-                             deviceExtension,
+                             deviceExtension, 
                              PathId,
                              TargetId,
                              Lun);
@@ -3163,14 +3536,19 @@ 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)InterlockedCompareExchange(&chan->CheckIntr,
-                                      CHECK_INTR_ACTIVE,
-                                      CHECK_INTR_DETECTED) == CHECK_INTR_DETECTED) {
+        if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(chan->CheckIntr),
+                                      CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
+                                      CRNT_ILK_TYPE CHECK_INTR_DETECTED) == CHECK_INTR_DETECTED)
+        {
             //ASSERT(!deviceExtension->simplexOnly);
             chan->DpcState = DPC_STATE_ISR;
             if(!AtapiInterrupt__(HwDeviceExtension, (UCHAR)c)) {
@@ -3190,7 +3568,7 @@ AtapiCallBack_X(
     )
 {
     AtapiCallBack__(HwDeviceExtension, (UCHAR)((PHW_DEVICE_EXTENSION)HwDeviceExtension)->ActiveDpcChan);
-}
+} // end AtapiCallBack_X()
 
 #endif //UNIATA_CORE
 
@@ -3221,34 +3599,69 @@ AtapiInterrupt(
     ULONG c_state;
     ULONG i_res = 0;
     ULONG pass;
-    BOOLEAN checked[AHCI_MAX_PORT];
-
-    KdPrint2((PRINT_PREFIX "Intr: VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
+    //BOOLEAN checked[AHCI_MAX_PORT];
+    ULONG hIS;
+    ULONG checked;
+
+    KdPrint2((PRINT_PREFIX "Intr: VendorID+DeviceID/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 "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;
     }
-//    fc =
-//    atapiDev = (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : 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;
-            //non_empty_chan = (deviceExtension->lun[c*2].DeviceFlags | deviceExtension->lun[c*2+1].DeviceFlags)
-            //        & DFLAGS_DEVICE_PRESENT;
 
-            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;
             }
@@ -3259,17 +3672,19 @@ AtapiInterrupt(
                 // if (deviceExtension->chan[c].CheckIntr == CHECK_INTR_DETECTED) {
                 //     deviceExtension->chan[c].CheckIntr = CHECK_INTR_ACTIVE;
                 // }
-                c_state = (ULONG)InterlockedCompareExchange(&(deviceExtension->chan[c].CheckIntr),
-                                              CHECK_INTR_ACTIVE,
-                                              CHECK_INTR_DETECTED);
+                c_state =
+                    (ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(deviceExtension->chan[c].CheckIntr),
+                                              CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
+                                              CRNT_ILK_TYPE CHECK_INTR_DETECTED);
                 if(c_state == CHECK_INTR_IDLE) {
                     // c_state = deviceExtension->chan[c].CheckIntr;
                     // if (deviceExtension->chan[c].CheckIntr == CHECK_INTR_IDLE) {
                     //     deviceExtension->chan[c].CheckIntr = CHECK_INTR_ACTIVE
                     // }
-                    c_state = (ULONG)InterlockedCompareExchange(&(deviceExtension->chan[c].CheckIntr),
-                                                  CHECK_INTR_ACTIVE,
-                                                  CHECK_INTR_IDLE);
+                    c_state =
+                        (ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(deviceExtension->chan[c].CheckIntr),
+                                                  CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
+                                                  CRNT_ILK_TYPE CHECK_INTR_IDLE);
                 }
             } while(c_state == CHECK_INTR_CHECK);
             KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): locked\n"));
@@ -3282,10 +3697,12 @@ AtapiInterrupt(
             if((c_state == CHECK_INTR_DETECTED) ||
                (i_res = AtapiCheckInterrupt__(deviceExtension, (UCHAR)c))) {
 
-                if(i_res == 2) {
+                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
@@ -3336,6 +3753,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;
@@ -3343,6 +3763,8 @@ AtapiInterrupt2(
     BOOLEAN status = FALSE;
     ULONG c_count = 0;
     ULONG i_res;
+    ULONG hIS;
+    ULONG checked;
 
     // we should never get here for ISA/MCA
     if(!BMList[deviceExtension->DevIndex].Isr2Enable) {
@@ -3350,17 +3772,45 @@ AtapiInterrupt2(
         return FALSE;
     }
 
+    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;
         }
 
-        if((ULONG)CrNtInterlockedCompareExchange(&(deviceExtension->chan[c].CheckIntr),
-                                      CHECK_INTR_CHECK,
-                                      CHECK_INTR_IDLE) != CHECK_INTR_IDLE) {
+        if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(deviceExtension->chan[c].CheckIntr),
+                                      CRNT_ILK_TYPE CHECK_INTR_CHECK,
+                                      CRNT_ILK_TYPE CHECK_INTR_IDLE) != CHECK_INTR_IDLE)
+        {
             KdPrint2((PRINT_PREFIX "AtapiInterrupt2: !CHECK_INTR_IDLE\n"));
             // hunt on unexpected intr (Some devices generate double interrupts,
             // some controllers (at least CMD649) interrupt twice with small delay.
@@ -3373,7 +3823,7 @@ AtapiInterrupt2(
         if((i_res = AtapiCheckInterrupt__(deviceExtension, (UCHAR)c))) {
 
             KdPrint2((PRINT_PREFIX "AtapiInterrupt2: intr\n"));
-            if(i_res == 2) {
+            if(i_res == INTERRUPT_REASON_UNEXPECTED) {
                 KdPrint2((PRINT_PREFIX "AtapiInterrupt2: Catch unexpected\n"));
                 InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE);
                 return TRUE;
@@ -3396,7 +3846,7 @@ AtapiInterrupt2(
     }
     KdPrint2((PRINT_PREFIX "AtapiInterrupt2: return %d\n", status));
     return status;
-
+    
 } // end AtapiInterrupt2()
 
 RETTYPE_XXableInterrupts
@@ -3413,12 +3863,13 @@ AtapiInterruptDpc(
 
         if(!(deviceExtension->chan[c].ChannelCtrlFlags & CTRFLAGS_DPC_REQ)) {
 
-            if((ULONG)InterlockedCompareExchange(&(deviceExtension->chan[c].CheckIntr),
-                                          CHECK_INTR_ACTIVE,
-                                          CHECK_INTR_DETECTED) != CHECK_INTR_DETECTED) {
+            if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(deviceExtension->chan[c].CheckIntr),
+                                          CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
+                                          CRNT_ILK_TYPE CHECK_INTR_DETECTED) != CHECK_INTR_DETECTED)
+            {
                 continue;
             }
-
+                        
         } else {
             deviceExtension->chan[c].ChannelCtrlFlags &= ~CTRFLAGS_DPC_REQ;
         }
@@ -3467,9 +3918,9 @@ AtapiEnableInterrupts__(
         } else {
             // check if other channel(s) interrupted
             // must do nothing in simplex mode
-            if((ULONG)CrNtInterlockedCompareExchange(&(chan->CheckIntr),
-                                          CHECK_INTR_ACTIVE,
-                                          CHECK_INTR_DETECTED) != CHECK_INTR_DETECTED) {
+            if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(chan->CheckIntr),
+                                          CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
+                                          CRNT_ILK_TYPE CHECK_INTR_DETECTED) != CHECK_INTR_DETECTED) {
                 continue;
             }
             //ASSERT(!deviceExtension->simplexOnly);
@@ -3508,16 +3959,48 @@ AtapiEnableInterrupts(
     )
 {
     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
-    KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: %d\n",c, deviceExtension->chan[c].DisableIntr));
+    PHW_CHANNEL chan;
+    //UCHAR statusByte;
+    
     if(c >= deviceExtension->NumberChannels) {
+        KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: WRONG CHANNEL\n",c));
         return;
     }
-    if(!InterlockedDecrement(&deviceExtension->chan[c].DisableIntr)) {
-        AtapiWritePort1(&deviceExtension->chan[c], IDX_IO2_o_Control,
-                               IDE_DC_A_4BIT );
-        deviceExtension->chan[c].ChannelCtrlFlags &= ~CTRFLAGS_INTR_DISABLED;
+    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,
+                (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 );
+            //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(&deviceExtension->chan[c], IDX_IO2_o_Control,
+        AtapiWritePort1(chan, IDX_IO2_o_Control,
                                IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ );
     }
     return;
@@ -3531,20 +4014,49 @@ AtapiDisableInterrupts(
     )
 {
     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
-    KdPrint2((PRINT_PREFIX "AtapiDisableInterrupts_%d: %d\n",c, deviceExtension->chan[c].DisableIntr));
-    // mark channel as busy
+    PHW_CHANNEL chan;
     if(c >= deviceExtension->NumberChannels) {
+        KdPrint2((PRINT_PREFIX "AtapiDisableInterrupts_%d: WRONG CHANNEL\n",c));
         return;
     }
-    if(InterlockedIncrement(&deviceExtension->chan[c].DisableIntr)) {
-        AtapiWritePort1(&deviceExtension->chan[c], IDX_IO2_o_Control,
-                               IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ );
-        deviceExtension->chan[c].ChannelCtrlFlags |= CTRFLAGS_INTR_DISABLED;
+    chan = &(deviceExtension->chan[c]);
+    KdPrint2((PRINT_PREFIX "AtapiDisableInterrupts_%d: %d\n",c, chan->DisableIntr));
+    // mark channel as busy
+    if(InterlockedIncrement(&chan->DisableIntr)) {
+        if(deviceExtension->HwFlags & UNIATA_AHCI) {
+            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;
     }
 
     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
@@ -3568,7 +4080,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;
@@ -3576,14 +4088,52 @@ 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)) {
+
+        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;
+    }
 
     if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) {
         DmaTransfer = TRUE;
@@ -3602,12 +4152,6 @@ AtapiCheckInterrupt__(
         goto check_unknown;
     }
 
-    if((ChipFlags & UNIATA_AHCI) &&
-        UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
-        OurInterrupt = UniataAhciStatus(HwDeviceExtension, lChannel);
-        return OurInterrupt;
-    }
-
     // Attention !
     // We can catch (BM_STATUS_ACTIVE + BM_STATUS_INTR) when operation is actually completed
     // Such behavior was observed with Intel ICH-xxx chips
@@ -3619,13 +4163,13 @@ AtapiCheckInterrupt__(
         switch(ChipType) {
         case PROLD:
         case PRNEW:
-            status = AtapiReadPortEx4(chan, (ULONG_PTR)&deviceExtension->BaseIoAddressBM_0,0x1c);
+            status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x1c);
             if (!DmaTransfer)
                 break;
-            if (!(status &
+            if (!(status & 
                   ((Channel) ? 0x00004000 : 0x00000400))) {
                 KdPrint2((PRINT_PREFIX "  Promise old/new unexpected\n"));
-                return FALSE;
+                return INTERRUPT_REASON_IGNORE;
             }
             break;
         case PRTX:
@@ -3635,26 +4179,44 @@ AtapiCheckInterrupt__(
                 break;
             if(!(status & 0x20)) {
                 KdPrint2((PRINT_PREFIX "  Promise tx unexpected\n"));
-                return FALSE;
+                return INTERRUPT_REASON_IGNORE;
             }
             break;
-        case PRMIO:
-            status = AtapiReadPortEx4(chan, (ULONG_PTR)&deviceExtension->BaseIoAddressBM_0,0x0040);
-            if(ChipFlags & PRSATA) {
-                pr_status = AtapiReadPortEx4(chan, (ULONG_PTR)&deviceExtension->BaseIoAddressBM_0,0x006c);
-                AtapiWritePortEx4(chan, (ULONG_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 FALSE;
+                UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH, 0);
             }
             if(!(status & (0x01 << Channel))) {
-                KdPrint2((PRINT_PREFIX "  Promise mio unexpected\n"));
-                return FALSE;
+                // 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: {
@@ -3668,31 +4230,31 @@ AtapiCheckInterrupt__(
 
         /* get and clear interrupt status */
         if(ChipFlags & NVQ) {
-            pr_status = AtapiReadPortEx4(chan, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0,offs);
-            AtapiWritePortEx4(chan, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0,offs, (0x0fUL << shift) | 0x00f000f0);
+            pr_status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs);
+            AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs, (0x0fUL << shift) | 0x00f000f0);
         } else {
-            pr_status = AtapiReadPortEx1(chan,(ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0,offs);
-            AtapiWritePortEx1(chan, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0,offs, (0x0f << shift));
+            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));
 
         /* check for and handle connect events */
         if(((pr_status & (0x0cUL << shift)) == (0x04UL << shift)) ) {
-            UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH);
+            UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH, 0);
         }
         /* check for and handle disconnect events */
         if((pr_status & (0x08UL << shift)) &&
             !((pr_status & (0x04UL << shift) &&
-            AtapiReadPort4(chan, IDX_SATA_SStatus))) ) {
-            UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH);
+            UniataSataReadPort4(chan, IDX_SATA_SStatus, 0))) ) {
+            UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH, 0);
         }
         /* do we have any device action ? */
         if(!(pr_status & (0x01UL << shift))) {
             KdPrint2((PRINT_PREFIX "  nVidia unexpected\n"));
-            if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT)) {
-                OurInterrupt = 2;
+            if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
+                OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
             } else {
-                return FALSE;
+                return INTERRUPT_REASON_IGNORE;
             }
         }
 
@@ -3712,11 +4274,11 @@ AtapiCheckInterrupt__(
             KdPrint2((PRINT_PREFIX "  Sii DS0 %x\n", reg32));
             if(reg32 == 0xffffffff) {
                 KdPrint2((PRINT_PREFIX "  Sii mio unexpected\n"));
-                return FALSE;
+                return INTERRUPT_REASON_IGNORE;
             }
             if(!(reg32 & (BM_DS0_SII_DMA_SATA_IRQ | BM_DS0_SII_DMA_COMPLETE | BM_DS0_SII_IRQ | BM_DS0_SII_DMA_ENABLE | BM_DS0_SII_DMA_ERROR))) {
                 KdPrint2((PRINT_PREFIX "  Sii mio unexpected (2)\n"));
-                return FALSE;
+                return INTERRUPT_REASON_IGNORE;
             }
 
             if(ChipFlags & UNIATA_SATA) {
@@ -3726,8 +4288,8 @@ AtapiCheckInterrupt__(
                     * controllers continue to assert IRQ as long as
                     * SError bits are pending.  Clear SError immediately.
                     */
-                    if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT)) {
-                        OurInterrupt = 2;
+                    if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
+                        OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
                     }
                 }
             }
@@ -3748,11 +4310,11 @@ AtapiCheckInterrupt__(
             KdPrint2((PRINT_PREFIX "  0x71 = %#x\n", reg8));
             if (!(reg8 &
                   (Channel ? 0x08 : 0x04))) {
-                return FALSE;
+                return INTERRUPT_REASON_IGNORE;
             }
             if (!DmaTransfer) {
                 KdPrint2((PRINT_PREFIX "  cmd our\n"));
-                OurInterrupt = 2;
+                OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
             }
             SetPciConfig1(0x71, (Channel ? 0x08 : 0x04));
         }
@@ -3764,21 +4326,38 @@ AtapiCheckInterrupt__(
         //dma_status = GetDmaStatus(deviceExtension, lChannel);
         if (!((dma_status = GetDmaStatus(deviceExtension, lChannel)) & BM_STATUS_INTR)) {
             KdPrint2((PRINT_PREFIX "  Acard unexpected\n"));
-            return FALSE;
+            return INTERRUPT_REASON_IGNORE;
         }
         AtapiWritePort1(chan, IDX_BM_Status, dma_status | BM_STATUS_INTR);
         AtapiStallExecution(1);
         AtapiWritePort1(chan, IDX_BM_Command,
             AtapiReadPort1(chan, IDX_BM_Command) & ~BM_COMMAND_START_STOP);
         goto skip_dma_stat_check;
+    case ATA_INTEL_ID:
+        if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
+            if(ChipFlags & UNIATA_AHCI) {
+                // Do nothing here
+            } else
+            if(ChipFlags & UNIATA_SATA) {
+                if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
+                    OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
+                }
+                if(!(chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE)) {
+                    if(UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT, 1)) {
+                        OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
+                    }
+                }
+            }
+        }
+        break;
     default:
         if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
             if(ChipFlags & UNIATA_AHCI) {
                 // Do nothing here
             } else
             if(ChipFlags & UNIATA_SATA) {
-                if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT)) {
-                    OurInterrupt = 2;
+                if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
+                    OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
                 }
             }
         }
@@ -3790,16 +4369,30 @@ check_unknown:
             KdPrint2((PRINT_PREFIX "  DmaTransfer + !BM_STATUS_INTR (%x)\n", dma_status));
             if(dma_status & BM_STATUS_ERR) {
                 KdPrint2((PRINT_PREFIX "  DmaTransfer + BM_STATUS_ERR -> our\n"));
-                OurInterrupt = 2;
+                OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
             } 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 = 2;
+                    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 FALSE;
+                    return INTERRUPT_REASON_IGNORE;
                 }
             }
         }
@@ -3809,25 +4402,26 @@ check_unknown:
             KdPrint2((PRINT_PREFIX "  clear unexpected DMA intr\n"));
             AtapiDmaDone(deviceExtension, DEVNUM_NOT_SPECIFIED ,lChannel, NULL);
             // catch it !
-            OurInterrupt = 2;
+            OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
         }
     }
 skip_dma_stat_check:
-    if(!(ChipFlags & UNIATA_SATA)) {
+    if(!(ChipFlags & UNIATA_SATA) && chan->ExpectingInterrupt) {
         AtapiStallExecution(1);
     }
 
-    LunExt = &(deviceExtension->lun[c*2 + 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) {
@@ -3840,15 +4434,15 @@ skip_dma_stat_check:
             KdPrint2((PRINT_PREFIX "  ATAPI additional check\n"));
         } else {
             KdPrint2((PRINT_PREFIX "  expecting intr + BUSY (3), non ATAPI\n"));
-            return FALSE;
+            return INTERRUPT_REASON_IGNORE;
         }
         if((statusByte & ~IDE_STATUS_DRQ) != (IDE_STATUS_BUSY | IDE_STATUS_DRDY | IDE_STATUS_DSC)) {
             KdPrint3((PRINT_PREFIX "  unexpected status, seems it is not our\n"));
-            return FALSE;
+            return INTERRUPT_REASON_IGNORE;
         }
         if(!(LunExt->DeviceFlags & DFLAGS_INT_DRQ) && (statusByte & IDE_STATUS_DRQ)) {
             KdPrint3((PRINT_PREFIX "  unexpected DRQ, seems it is not our\n"));
-            return FALSE;
+            return INTERRUPT_REASON_IGNORE;
         }
 
         EarlyIntr = TRUE;
@@ -3857,8 +4451,11 @@ 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 TRUE;
+            return INTERRUPT_REASON_OUR;
         }
 
         if(g_WaitBusyInISR) {
@@ -3871,7 +4468,7 @@ skip_dma_stat_check:
             }
             if (statusByte & IDE_STATUS_BUSY) {
                 KdPrint2((PRINT_PREFIX "  still BUSY, seems it is not our\n"));
-                return FALSE;
+                return INTERRUPT_REASON_IGNORE;
             }
         }
 
@@ -3880,9 +4477,9 @@ 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
+    } else 
     if(!(statusByte & (IDE_STATUS_DRQ | IDE_STATUS_DRDY))) {
         KdPrint2((PRINT_PREFIX "  no DRQ/DRDY set\n"));
         return OurInterrupt;
@@ -3890,7 +4487,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);
@@ -3898,9 +4495,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;
             }
         }
     }
@@ -3916,14 +4517,14 @@ 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;
     }
     //ASSERT(!chan->queue_depth || chan->cur_req);
 
     KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__: exit with TRUE\n"));
-    return TRUE;
+    return INTERRUPT_REASON_OUR;
 
 } // end AtapiCheckInterrupt__()
 
@@ -3950,12 +4551,15 @@ AtapiInterrupt__(
 
     BOOLEAN atapiDev = FALSE;
 
+#ifdef DBG
     UCHAR Channel;
+#endif //DBG
     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
@@ -3965,6 +4569,7 @@ AtapiInterrupt__(
 //    BOOLEAN RestoreUseDpc = FALSE;
     BOOLEAN DataOverrun = FALSE;
     BOOLEAN NoStartIo = TRUE;
+    BOOLEAN NoRetry = FALSE;
 
     KdPrint2((PRINT_PREFIX "AtapiInterrupt:\n"));
     if(InDpc) {
@@ -3976,24 +4581,28 @@ AtapiInterrupt__(
     UCHAR TargetId;
     UCHAR Lun;
     UCHAR OldReqState = REQ_STATE_NONE;
-    ULONG ldev;
+    //ULONG ldev;
     PHW_LU_EXTENSION LunExt;
 
     lChannel = c;
+
+#ifdef DBG
     Channel = (UCHAR)(deviceExtension->Channel + lChannel);
 
     KdPrint2((PRINT_PREFIX "  cntrlr %#x:%d, irql %#x, c %d\n", deviceExtension->DevIndex, Channel, KeGetCurrentIrql(), c));
+#endif //DBG
 
     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"));
     }
 
     if (srb) {
-        PathId   = srb->PathId;
+        PathId   = srb->PathId;  
         TargetId = srb->TargetId;
-        Lun      = srb->Lun;
+        Lun      = srb->Lun;     
     } else {
         PathId = (UCHAR)c;
         TargetId =
@@ -4001,9 +4610,9 @@ AtapiInterrupt__(
         goto enqueue_next_req;
     }
 
-    ldev = GET_LDEV2(PathId, TargetId, Lun);
-    DeviceNumber = (UCHAR)(ldev & 1);
-    LunExt = &(deviceExtension->lun[ldev]);
+    //ldev = GET_LDEV2(PathId, TargetId, Lun);
+    DeviceNumber = (UCHAR)(TargetId);
+    LunExt = chan->lun[DeviceNumber];
     atapiDev = (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE;
     KdPrint2((PRINT_PREFIX "  dev_type %s\n", atapiDev ? "ATAPI" : "IDE"));
 
@@ -4043,6 +4652,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"));
@@ -4094,6 +4704,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
@@ -4117,6 +4728,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,
@@ -4157,8 +4775,44 @@ ServiceInterrupt:
         AtapiStallExecution(10);
     }
 */
+
     /* clear interrupt and get status */
-    GetBaseStatus(chan, statusByte);
+    if(deviceExtension->HwFlags & UNIATA_AHCI) {
+        UniataAhciEndTransaction(HwDeviceExtension, lChannel, DeviceNumber, srb);
+        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) {
+                //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);
+    }
     if(atapiDev) {
         KdPrint3((PRINT_PREFIX "AtapiInterrupt: ATAPI Entered with status (%#x)\n", statusByte));
     } else {
@@ -4169,9 +4823,12 @@ ServiceInterrupt:
         KdPrint2((PRINT_PREFIX "  operate like in DPC\n"));
         InDpc = TRUE;
     }
-
+                                                                       
     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.
@@ -4206,10 +4863,10 @@ try_dpc_wait:
                 AtapiStallExecution(TimerValue);
                 goto ServiceInterrupt;
 #endif //UNIATA_CORE
-            } else
+            } else 
             if (InDpc && i == k) {
                 // reset the controller.
-                KdPrint2((PRINT_PREFIX
+                KdPrint2((PRINT_PREFIX 
                             "  Resetting due to BUSY on entry - %#x.\n",
                             statusByte));
                 goto IntrPrepareResetController;
@@ -4219,25 +4876,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"));
+        //if(chan->ChannelCtrlFlags & CTRFLAGS_DSC_BSY) {}
+/*
+#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"));
@@ -4249,13 +4930,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"));
@@ -4264,7 +4953,7 @@ try_dpc_wait:
         }
     }
 
-    if(AtaReq && DmaTransfer) {
+    if(AtaReq && DmaTransfer && !(deviceExtension->HwFlags & UNIATA_AHCI)) {
         switch(OldReqState) {
         case REQ_STATE_EARLY_INTR:
         case REQ_STATE_DPC_WAIT_BUSY0:
@@ -4282,7 +4971,34 @@ try_dpc_wait:
     if ((statusByte & IDE_STATUS_ERROR) ||
         (dma_status & BM_STATUS_ERR)) {
 
-        error = AtapiReadPort1(chan, IDX_IO1_i_Error);
+        if(deviceExtension->HwFlags & UNIATA_AHCI) {
+            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);
+        }
         KdPrint2((PRINT_PREFIX "AtapiInterrupt: Error %#x\n", error));
 /*
         if(error & IDE_STATUS_CORRECTED_ERROR) {
@@ -4297,7 +5013,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);
@@ -4311,9 +5029,9 @@ 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(100);
+                AtapiStallExecution(50);
             } else {
                 break;
             }
@@ -4329,11 +5047,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;
+                        if(!(deviceExtension->HwFlags & UNIATA_AHCI)) {
+                            AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
+                            AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
 //                        LunExt->DeviceFlags |= DFLAGS_FORCE_DOWNRATE;
+                        }
                         AtaReq->ReqState = REQ_STATE_QUEUED;
                         goto reenqueue_req;
                     }
@@ -4345,7 +5066,7 @@ 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(DmaTransfer && (chan->lun[DeviceNumber]->TransferMode > ATA_UDMA2) &&
@@ -4380,22 +5101,31 @@ continue_err:
         deviceExtension->HbaCtrlFlags |= HBAFLAGS_DMA_DISABLED_LBA48;
     } else
     if(AtaReq->Flags & REQ_FLAG_FORCE_DOWNRATE) {
-        KdPrint2((PRINT_PREFIX "Some higher mode doesn't work right :((\n"));
 #ifdef IO_STATISTICS
-        chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry]++;
-        if(chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry] >= chan->lun[DeviceNumber]->IoCount/3 ||
+        KdPrint2((PRINT_PREFIX "Some higher mode doesn't work right :((\n"));
+        KdPrint2((PRINT_PREFIX "Recovery stats[%d]: %d vs %d\n",
+              AtaReq->retry,
+              LunExt->RecoverCount[AtaReq->retry],
+              LunExt->BlockIoCount
+              ));
+        LunExt->RecoverCount[AtaReq->retry]++;
+        if(LunExt->RecoverCount[AtaReq->retry] >= chan->lun[DeviceNumber]->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
-    chan->lun[DeviceNumber]->IoCount++;
+    if(AtaReq->bcount) {
+        // we need stats for Read/Write operations
+        LunExt->BlockIoCount++;
+    }
+    LunExt->IoCount++;
 #endif //IO_STATISTICS
 
 continue_PIO:
@@ -4406,7 +5136,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;
@@ -4433,10 +5163,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;
@@ -4457,7 +5187,7 @@ continue_PIO:
 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;
                     }
@@ -4484,33 +5214,55 @@ 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 (interruptReason == 0x1 && (statusByte & IDE_STATUS_DRQ)) {
+    if(deviceExtension->HwFlags & UNIATA_AHCI) {
+        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 == ATAPI_IR_COD_Cmd && (statusByte & IDE_STATUS_DRQ)) {
         // 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);
         AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
 
         if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
             KdPrint2((PRINT_PREFIX "AtapiInterrupt: AtapiDmaStart().\n"));
-            AtapiDmaStart(HwDeviceExtension, ldev & 1, lChannel, srb);
+            AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, srb);
         }
 
         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) {
@@ -4520,14 +5272,14 @@ 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;
             KdPrint2((PRINT_PREFIX "AtapiInterrupt: get W wordCount %#x\n", wordCount));
 
             if (wordCount != AtaReq->WordsLeft) {
-                KdPrint2((PRINT_PREFIX
+                KdPrint2((PRINT_PREFIX 
                            "AtapiInterrupt: %d words requested; %d words xferred\n",
                            AtaReq->WordsLeft,
                            wordCount));
@@ -4536,7 +5288,7 @@ IntrPrepareResetController:
             // Verify this makes sense.
             if (wordCount > AtaReq->WordsLeft) {
                 wordCount = AtaReq->WordsLeft;
-                KdPrint2((PRINT_PREFIX
+                KdPrint2((PRINT_PREFIX 
                            "AtapiInterrupt: Write underrun\n"));
                 DataOverrun = TRUE;
             }
@@ -4545,28 +5297,39 @@ IntrPrepareResetController:
 
             // IDE path. Check if words left is at least DEV_BSIZE/2 = 256.
             if (AtaReq->WordsLeft < wordsThisInterrupt) {
-
                // Transfer only words requested.
                wordCount = AtaReq->WordsLeft;
-
             } else {
-
                // Transfer next block.
                wordCount = wordsThisInterrupt;
             }
         }
 
-        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) {
 
-           KdPrint2((PRINT_PREFIX
+           KdPrint2((PRINT_PREFIX 
                       "AtapiInterrupt: Write interrupt\n"));
 
            statusByte = WaitOnBusy(chan);
@@ -4586,8 +5349,8 @@ IntrPrepareResetController:
            }
         } else {
 
-            KdPrint3((PRINT_PREFIX
-                        "AtapiInterrupt: Int reason %#x, but srb is for a write %#x.\n",
+            KdPrint3((PRINT_PREFIX 
+                        "AtapiInterrupt: Int reason %#x, but srb is for a read %#x.\n",
                         interruptReason,
                         srb));
 
@@ -4595,10 +5358,10 @@ IntrPrepareResetController:
             status = SRB_STATUS_ERROR;
             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;
@@ -4606,7 +5369,7 @@ IntrPrepareResetController:
 
         goto ReturnEnableIntr;
 
-    } else if (interruptReason == 0x2 && (statusByte & IDE_STATUS_DRQ)) {
+    } else if (interruptReason == ATAPI_IR_IO_toHost && (statusByte & IDE_STATUS_DRQ)) {
 
 
         if (atapiDev) {
@@ -4616,12 +5379,12 @@ IntrPrepareResetController:
                 AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow) |
                 (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8);
 
-            // Covert bytes to words.
-            wordCount /= 2;
+            // Convert bytes to words.
+            wordCount >>= 1;
             KdPrint2((PRINT_PREFIX "AtapiInterrupt: get R wordCount %#x\n", wordCount));
 
             if (wordCount != AtaReq->WordsLeft) {
-                KdPrint2((PRINT_PREFIX
+                KdPrint2((PRINT_PREFIX 
                            "AtapiInterrupt: %d words requested; %d words xferred\n",
                            AtaReq->WordsLeft,
                            wordCount));
@@ -4637,19 +5400,29 @@ IntrPrepareResetController:
 
             // Check if words left is at least 256.
             if (AtaReq->WordsLeft < wordsThisInterrupt) {
-
                // Transfer only words requested.
                wordCount = AtaReq->WordsLeft;
-
             } else {
-
                // Transfer next block.
                wordCount = wordsThisInterrupt;
             }
         }
 
-        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;
@@ -4664,7 +5437,7 @@ IntrPrepareResetController:
             statusByte = WaitOnBusy(chan);
 
             if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
-                KdPrint2((PRINT_PREFIX
+                KdPrint2((PRINT_PREFIX 
                            "IdeIntr: Read %#x words\n", wordCount));
 
                 ReadBuffer(chan,
@@ -4677,16 +5450,27 @@ IntrPrepareResetController:
                     KdDump(AtaReq->DataBuffer, wordCount*2);
                 }
 
-                GetStatus(chan, statusByte);
+                GetBaseStatus(chan, statusByte);
                 KdPrint2((PRINT_PREFIX "  status re-check %#x\n", statusByte));
 
                 if(DataOverrun) {
                     KdPrint2((PRINT_PREFIX "  DataOverrun\n"));
                     AtapiSuckPort2(chan);
+                    GetBaseStatus(chan, statusByte);
+                }
+
+                if(statusByte & IDE_STATUS_BUSY) {
+                    for (i = 0; i < 2; i++) {
+                        AtapiStallExecution(10);
+                        GetBaseStatus(chan, statusByte);
+                        if (!(statusByte & IDE_STATUS_BUSY)) {
+                            break;
+                        }
+                    }
                 }
 
             } else {
-                KdPrint2((PRINT_PREFIX
+                KdPrint2((PRINT_PREFIX 
                           "IdeIntr: Read %#x Dwords\n", wordCount/2));
 
                 ReadBuffer2(chan,
@@ -4709,6 +5493,7 @@ IntrPrepareResetController:
         // 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) {
@@ -4732,6 +5517,19 @@ IntrPrepareResetController:
                     *((ULONG *) &(AtaReq->DataBuffer[2])) = 0x00080000;
                     AtaReq->DataBuffer += wordCount;
                 }
+
+                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));
+
+                    status = SRB_STATUS_SUCCESS;
+                    goto CompleteRequest;
+                }
+
             } else {
 
             /*
@@ -4751,24 +5549,45 @@ 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;
+                }
             }
         }
 
         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 os 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;
         }
+        //if (AtaReq->WordsLeft) {
+        //    status = SRB_STATUS_DATA_OVERRUN;
+        //} else {
+            status = SRB_STATUS_SUCCESS;
+        //}
 
 #ifdef UNIATA_DUMP_ATAPI
         if(srb &&
@@ -4821,8 +5640,14 @@ 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;
@@ -4879,7 +5704,7 @@ CompleteRequest:
                 if (status == SRB_STATUS_DATA_OVERRUN) {
                     // Check to see if we at least get mininum number of bytes
                     if ((srb->DataTransferLength - AtaReq->WordsLeft) >
-                        (offsetof (SENSE_DATA, AdditionalSenseLength) + sizeof(senseData->AdditionalSenseLength))) {
+                        (FIELD_OFFSET (SENSE_DATA, AdditionalSenseLength) + sizeof(senseData->AdditionalSenseLength))) {
                         status = SRB_STATUS_SUCCESS;
                     }
                 }
@@ -4889,6 +5714,7 @@ CompleteRequest:
                     if ((senseData->SenseKey != SCSI_SENSE_ILLEGAL_REQUEST) &&
                         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 (
@@ -4896,7 +5722,8 @@ CompleteRequest:
                                                               AtaReq->OriginalSrb);
                     } else {
 
-                        // last request was illegal.  No point trying again
+                        // last request was illegal.  No point trying again.
+                        // Do-nothing call ?
                         AtapiHwInitializeChanger (HwDeviceExtension,
                                                   srb,
                                                   (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
@@ -4939,6 +5766,7 @@ CompleteRequest:
 
             if (AtaReq->OriginalSrb) {
                 KdPrint2((PRINT_PREFIX "AtapiInterrupt: call AtapiHwInitializeChanger()\n"));
+                // Do-nothing call ?
                 AtapiHwInitializeChanger (HwDeviceExtension,
                                           srb,
                                           (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
@@ -4972,7 +5800,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;
                 }
@@ -4994,7 +5822,7 @@ PIO_wait_busy:
             if (i == 5*30) {
 
                 // reset the controller.
-                KdPrint2((PRINT_PREFIX
+                KdPrint2((PRINT_PREFIX 
                             "AtapiInterrupt: Resetting due to BSY still up - %#x.\n",
                             statusByte));
                 goto IntrPrepareResetController;
@@ -5030,7 +5858,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;
                     }
@@ -5067,7 +5895,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);
 
@@ -5093,7 +5922,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",
@@ -5142,31 +5974,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;
             }
@@ -5179,7 +6015,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;
@@ -5189,7 +6025,7 @@ IntrCompleteReq:
                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: Clear RDP\n"));
                     chan->RDP = FALSE;
                     goto CompleteRDP;
-                }
+                } 
                 AtapiStallExecution(50);
             }
         }
@@ -5221,7 +6057,7 @@ reenqueue_req:
                                  NULL);
         } else {
             ScsiPortNotification(NextLuRequest,
-                                 deviceExtension,
+                                 deviceExtension, 
                                  PathId,
                                  TargetId,
                                  Lun);
@@ -5245,11 +6081,20 @@ reenqueue_req:
                     interruptReason,
                     statusByte));
 
+        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"));
@@ -5319,34 +6164,32 @@ 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
+        KdPrint2((PRINT_PREFIX 
                     "IdeSendSmartCommand: bCommandReg != SMART_CMD\n"));
         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;
 
@@ -5354,11 +6197,19 @@ 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);
 
         if (statusByte & IDE_STATUS_BUSY) {
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                         "IdeSendSmartCommand: Returning BUSY status\n"));
             return SRB_STATUS_BUSY;
         }
@@ -5370,7 +6221,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,
@@ -5391,11 +6242,12 @@ IdeSendSmartCommand(
     case ENABLE_DISABLE_AUTOSAVE:
     case EXECUTE_OFFLINE_DIAGS:
     case SAVE_ATTRIBUTE_VALUES:
+    case AUTO_OFFLINE:
 
         statusByte = WaitOnBusy(chan);
 
         if (statusByte & IDE_STATUS_BUSY) {
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                         "IdeSendSmartCommand: Returning BUSY status\n"));
             return SRB_STATUS_BUSY;
         }
@@ -5407,7 +6259,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,
@@ -5418,6 +6270,7 @@ IdeSendSmartCommand(
 
         if(!(statusByte & IDE_STATUS_ERROR)) {
             // Wait for interrupt.
+            UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
             return SRB_STATUS_PENDING;
         }
         return SRB_STATUS_ERROR;
@@ -5433,7 +6286,7 @@ ULONGLONG
 NTAPI
 UniAtaCalculateLBARegs(
     PHW_LU_EXTENSION     LunExt,
-    ULONG                startingSector,
+    ULONGLONG            startingSector,
     PULONG               max_bcount
     )
 {
@@ -5441,8 +6294,6 @@ UniAtaCalculateLBARegs(
     USHORT               cylinder;
     ULONG                tmp;
 
-    (*max_bcount) = 0;
-
     if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
         if(LunExt->LimitedTransferMode >= ATA_DMA) {
             if(LunExt->DeviceExtension) {
@@ -5467,6 +6318,7 @@ 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()
@@ -5529,18 +6381,19 @@ IdeReadWrite(
     PHW_CHANNEL          chan = &(deviceExtension->chan[lChannel]);
     PHW_LU_EXTENSION     LunExt;
     PATA_REQ             AtaReq = (PATA_REQ)(Srb->SrbExtension);
-    ULONG                ldev = GET_LDEV(Srb);
-    UCHAR                DeviceNumber = (UCHAR)(ldev & 1);
-    ULONG                startingSector;
+    //ULONG                ldev = GET_LDEV(Srb);
+    UCHAR                DeviceNumber = GET_CDEV(Srb);;
+    ULONGLONG            startingSector=0;
     ULONG                max_bcount;
     ULONG                wordCount = 0;
     UCHAR                statusByte,statusByte2;
     UCHAR                cmd;
     ULONGLONG            lba;
     BOOLEAN              use_dma = FALSE;
+    ULONG                fis_size;
 
     AtaReq->Flags |= REQ_FLAG_REORDERABLE_CMD;
-    LunExt = &deviceExtension->lun[ldev];
+    LunExt = chan->lun[DeviceNumber];
 
     if((CmdAction & CMD_ACTION_PREPARE) &&
        (AtaReq->ReqState != REQ_STATE_READY_TO_TRANSFER)) {
@@ -5561,9 +6414,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,
@@ -5572,9 +6425,24 @@ 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_READ:
+            case SCSIOP_WRITE:
+                MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA);
+                MOV_SWP_DW2DD(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
+                break;
+            case SCSIOP_READ12:
+            case SCSIOP_WRITE12:
+                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));
@@ -5587,7 +6455,7 @@ 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));
@@ -5596,6 +6464,15 @@ IdeReadWrite(
 
         // 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
@@ -5605,7 +6482,31 @@ IdeReadWrite(
                 use_dma = FALSE;
             }
         }
+
+        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,
+                    lba,
+                     (USHORT)(AtaReq->bcount),
+                    0
+                    /*,(AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE*/
+                    );
+
+            if(!fis_size) {
+                KdPrint3((PRINT_PREFIX "IdeReadWrite: AHCI !FIS\n"));
+                return SRB_STATUS_ERROR;
+            }
+
+            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));
+        }
+
         AtaReq->ReqState = REQ_STATE_READY_TO_TRANSFER;
+
     } else { // exec_only
         KdPrint2((PRINT_PREFIX "IdeReadWrite (ExecOnly): \n"));
         lba = AtaReq->lba;
@@ -5615,12 +6516,13 @@ IdeReadWrite(
         }
     }
     if(!(CmdAction & CMD_ACTION_EXEC)) {
+
         return SRB_STATUS_PENDING;
     }
 
     // if this is queued request, reinit DMA and check
     // if DMA mode is still available
-    AtapiDmaReinit(deviceExtension, ldev, AtaReq);
+    AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
     if (/*EnableDma &&*/
         (LunExt->TransferMode >= ATA_DMA)) {
         use_dma = TRUE;
@@ -5663,15 +6565,24 @@ IdeReadWrite(
         }
     }
 
+    // Send IO command.
+    KdPrint2((PRINT_PREFIX "IdeReadWrite: Lba %#I64x, Count %#x(%#x)\n", lba, ((Srb->DataTransferLength + 0x1FF) / 0x200),
+                                                           ((wordCount*2 + DEV_BSIZE-1) / DEV_BSIZE)));
     if(use_dma) {
         chan->ChannelCtrlFlags |= CTRFLAGS_DMA_OPERATION;
     } else {
         chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
     }
 
-    // Send IO command.
-    KdPrint2((PRINT_PREFIX "IdeReadWrite: Lba %#I64x, Count %#x(%#x)\n", lba, ((Srb->DataTransferLength + 0x1FF) / 0x200),
-                                                           ((wordCount*2 + DEV_BSIZE-1) / DEV_BSIZE)));
+    if(deviceExtension->HwFlags & UNIATA_AHCI) {
+        // AHCI doesn't distinguish DMA and PIO
+        //AtapiDmaStart(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) {
@@ -5680,7 +6591,7 @@ IdeReadWrite(
                      (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) {
@@ -5701,9 +6612,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));
@@ -5716,23 +6627,23 @@ 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)) {
-        KdPrint2((PRINT_PREFIX
+        KdPrint2((PRINT_PREFIX 
                    "IdeReadWrite: Write %#x words\n", wordCount));
 
         WriteBuffer(chan,
@@ -5742,7 +6653,7 @@ IdeReadWrite(
 
     } else {
 
-        KdPrint2((PRINT_PREFIX
+        KdPrint2((PRINT_PREFIX 
                    "IdeReadWrite: Write %#x Dwords\n", wordCount/2));
 
         WriteBuffer2(chan,
@@ -5787,16 +6698,17 @@ IdeVerify(
     PHW_CHANNEL          chan = &(deviceExtension->chan[lChannel]);
     PATA_REQ             AtaReq = (PATA_REQ)(Srb->SrbExtension);
     PHW_LU_EXTENSION     LunExt;
-    ULONG                ldev = GET_LDEV(Srb);
+    //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 = &deviceExtension->lun[ldev];
+    LunExt = chan->lun[DeviceNumber];
     // Drive has these number sectors.
     if(!(sectors = (ULONG)(LunExt->NumOfSectors))) {
         sectors = LunExt->IdentifyData.SectorsPerTrack *
@@ -5809,18 +6721,30 @@ IdeVerify(
                 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) {
@@ -5830,7 +6754,7 @@ IdeVerify(
                     "IdeVerify: Truncating request to %#x blocks\n",
                     sectors - startingSector - 1));
 
-        sectorCount = (USHORT)(sectors - startingSector - 1);
+        sectorCount = (ULONG)(sectors - startingSector - 1);
 
     } else {
 
@@ -5850,9 +6774,9 @@ IdeVerify(
 
     lba = UniAtaCalculateLBARegs(LunExt, startingSector, &max_bcount);
 
-    statusByte = AtaCommand48(deviceExtension, ldev & 0x01, GET_CHANNEL(Srb),
+    statusByte = AtaCommand48(deviceExtension, LunExt->Lun, GET_CHANNEL(Srb),
                  IDE_COMMAND_VERIFY, lba,
-                 sectorCount,
+                 (USHORT)sectorCount,
                  0, ATA_IMMEDIATE);
 
     if(!(statusByte & IDE_STATUS_ERROR)) {
@@ -5889,18 +6813,24 @@ AtapiSendCommand(
     UCHAR                lChannel = GET_CHANNEL(Srb);
     PHW_CHANNEL          chan = &(deviceExtension->chan[lChannel]);
     PATA_REQ             AtaReq = (PATA_REQ)(Srb->SrbExtension);
-    ULONG                ldev = GET_LDEV(Srb);
-    ULONG i;
+    PHW_LU_EXTENSION     LunExt;
+    //ULONG                ldev = GET_LDEV(Srb);
+    ULONG                DeviceNumber = GET_CDEV(Srb);
     ULONG flags;
-    UCHAR statusByte,byteCountLow,byteCountHigh;
+    UCHAR statusByte,statusByte0,byteCountLow,byteCountHigh;
     BOOLEAN use_dma = FALSE;
     BOOLEAN dma_reinited = FALSE;
     BOOLEAN retried = FALSE;
+    ULONG                fis_size;
+    UCHAR FeatureReg=0;
+
+    LunExt = chan->lun[DeviceNumber];
 
     KdPrint3((PRINT_PREFIX "AtapiSendCommand: req state %#x, Action %x\n", AtaReq->ReqState, CmdAction));
     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;
@@ -5943,6 +6873,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;
@@ -5966,12 +6908,17 @@ 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;
         default:
@@ -5979,25 +6926,98 @@ AtapiSendCommand(
             return SRB_STATUS_BUSY;
         }
         //
-        if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_CHANGER_INITED) &&
+        if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED) &&
             !AtaReq->OriginalSrb) {
             KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_BUSY (2)\n"));
             return SRB_STATUS_BUSY;
         }
     }
 
+#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 {
+
+            // 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;
+
+            KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiHwInitializeChanger()\n"));
+            // Do-nothing call ?
+            AtapiHwInitializeChanger (HwDeviceExtension, Srb,
+                                      (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
+            // fall out
+        }
+    }
+#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:
 
@@ -6010,15 +7030,41 @@ 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(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
@@ -6027,15 +7073,23 @@ GetLba:
             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(AtapiDmaSetup(HwDeviceExtension, ldev & 1, lChannel, Srb,
+                    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
                                   /*((Srb->DataTransferLength + DEV_BSIZE-1) & ~(DEV_BSIZE-1))*/
@@ -6068,8 +7122,13 @@ call_dma_setup:
                 break;
             }
             // try setup DMA
+setup_dma:
             if(use_dma) {
-                if(!AtapiDmaSetup(HwDeviceExtension, ldev & 1, lChannel, Srb,
+                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)) {
                     KdPrint2((PRINT_PREFIX "AtapiSendCommand: no dma\n"));
@@ -6082,14 +7141,65 @@ call_dma_setup:
             KdPrint2((PRINT_PREFIX "AtapiSendCommand: zero transfer, no DMA setup\n"));
         }
 
+
+        if(deviceExtension->HwFlags & UNIATA_AHCI) {
+
+            UniataAhciSetupCmdPtr(AtaReq);
+
+            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 &&
+                   (Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
+                    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);
+
+            KdPrint2((PRINT_PREFIX "AtapiSendCommand ahci io flags %x: \n", AtaReq->ahci.io_cmd_flags));
+        }
+    
     } else {
         if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) {
             // if this is queued request, reinit DMA and check
             // if DMA mode is still available
             KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit()  (1)\n"));
-            AtapiDmaReinit(deviceExtension, ldev, AtaReq);
+            AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
             if (/*EnableDma &&*/
-                (deviceExtension->lun[ldev].TransferMode >= ATA_DMA)) {
+                (LunExt->TransferMode >= ATA_DMA)) {
                 KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma (2)\n"));
                 use_dma = TRUE;
             } else {
@@ -6105,22 +7215,22 @@ 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, ldev, AtaReq);
+        AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
     } if(AtaReq->TransferLength) {
         if(!dma_reinited) {
             KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit()\n"));
-            AtapiDmaReinit(deviceExtension, ldev, AtaReq);
+            AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
             if (/*EnableDma &&*/
-                (deviceExtension->lun[ldev].TransferMode >= ATA_DMA)) {
+                (LunExt->TransferMode >= ATA_DMA)) {
                 use_dma = TRUE;
             } else {
                 AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
@@ -6131,64 +7241,25 @@ 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, ldev, AtaReq);
+            AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
         }
     }
     KdPrint2((PRINT_PREFIX "AtapiSendCommand: use_dma=%d\n", use_dma));
     if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) {
         KdPrint2((PRINT_PREFIX "  REQ_FLAG_DMA_OPERATION\n"));
     }
-
+    
     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 (!(deviceExtension->lun[ldev].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.
-        deviceExtension->lun[ldev].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 = deviceExtension->lun[ldev].DeviceFlags;
+    flags = LunExt->DeviceFlags;
     if(flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) {
-        if((Srb->Lun) > (deviceExtension->lun[ldev].DiscsPresent - 1)) {
+        if((Srb->Lun) > (LunExt->DiscsPresent - 1)) {
 
             // Indicate no device found at this address.
             AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
@@ -6204,14 +7275,14 @@ call_dma_setup:
         return SRB_STATUS_SELECTION_TIMEOUT;
     }
 retry:
-    // Select device 0 or 1.
-    SelectDrive(chan, ldev & 0x1);
+    // 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;
     }
@@ -6225,6 +7296,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) {
 
@@ -6260,6 +7341,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) {
@@ -6268,26 +7351,26 @@ retry:
                 break;
             }
         }
-
-        if (i == 0x10000) {
+*/
+        if (statusByte & IDE_STATUS_DRQ) {
 make_reset:
             KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ still asserted.Status (%#x)\n", statusByte));
 
             AtapiDisableInterrupts(deviceExtension, lChannel);
 
-            AtapiSoftReset(chan, ldev & 1);
+            AtapiSoftReset(chan, DeviceNumber);
 
             KdPrint2((PRINT_PREFIX "AtapiSendCommand: Issued soft reset to Atapi device. \n"));
             // Re-initialize Atapi device.
-            CheckDevice(HwDeviceExtension, GET_CHANNEL(Srb), ldev & 1, TRUE);
+            CheckDevice(HwDeviceExtension, GET_CHANNEL(Srb), DeviceNumber, TRUE);
 /*
-            IssueIdentify(HwDeviceExtension, ldev & 1, GET_CHANNEL(Srb),
+            IssueIdentify(HwDeviceExtension, DeviceNumber, GET_CHANNEL(Srb),
                           IDE_COMMAND_ATAPI_IDENTIFY, FALSE);
 */
             // 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);
@@ -6325,12 +7408,27 @@ 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 &&
+           (Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
+            FeatureReg |= ATA_F_DMAREAD;
+        }
+    }
+
+    AtapiWritePort1(chan, IDX_IO1_o_Feature, FeatureReg);
 
     // Write transfer byte count to registers.
     byteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
@@ -6350,7 +7448,7 @@ make_reset:
         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);
@@ -6361,37 +7459,42 @@ make_reset:
         KdPrint3((PRINT_PREFIX "AtapiSendCommand: return SRB_STATUS_PENDING (DRQ)\n"));
         return SRB_STATUS_PENDING;
 
-    } else {
+    }
 
-        // This device quickly sets DRQ when ready to receive the packet.
+    // 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));
+    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);
+    UniataExpectChannelInterrupt(chan, TRUE);
+    AtaReq->ReqState = REQ_STATE_ATAPI_DO_NOTHING_INTR;
+    InterlockedExchange(&(chan->CheckIntr),
+                                  CHECK_INTR_IDLE);
 
-        //AtapiDisableInterrupts(deviceExtension, lChannel);
+    if(g_opt_AtapiSendDisableIntr) {
+        AtapiDisableInterrupts(deviceExtension, lChannel);
+    }
+    // remember status. Later we may check if error appeared after cmd packet 
+    statusByte0 = statusByte;
 
-        // Write ATAPI packet command.
-        AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET);
+    // Write ATAPI packet command.
+    AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET);
 
-        // Wait for DRQ.
-        WaitOnBusy(chan);
-        statusByte = WaitForDrq(chan);
+    // Wait for DRQ.
+    WaitOnBusy(chan);
+    statusByte = WaitForDrq(chan);
 
-        // Need to read status register and clear interrupt (if any)
-        GetBaseStatus(chan, statusByte);
+    // Need to read status register and clear interrupt (if any)
+    GetBaseStatus(chan, statusByte);
 
-        if (!(statusByte & IDE_STATUS_DRQ)) {
+    if (!(statusByte & IDE_STATUS_DRQ)) {
 
+        if(g_opt_AtapiSendDisableIntr) {
             AtapiEnableInterrupts(deviceExtension, lChannel);
-            KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ never asserted (%#x)\n", statusByte));
-            AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
-            return SRB_STATUS_ERROR;
         }
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ never asserted (%#x)\n", statusByte));
+        AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
+        return SRB_STATUS_ERROR;
     }
 
     GetStatus(chan, statusByte);
@@ -6401,22 +7504,56 @@ make_reset:
     statusByte = WaitOnBaseBusy(chan);
 
     // Indicate expecting an interrupt and wait for it.
-    chan->ExpectingInterrupt = TRUE;
+    UniataExpectChannelInterrupt(chan, TRUE);
     InterlockedExchange(&(chan->CheckIntr),
                                   CHECK_INTR_IDLE);
     AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
 
     GetBaseStatus(chan, statusByte);
 
-    //AtapiEnableInterrupts(deviceExtension, lChannel);
+    if(g_opt_AtapiSendDisableIntr) {
+        AtapiEnableInterrupts(deviceExtension, lChannel);
+    }
 
     WriteBuffer(chan,
                 (PUSHORT)Srb->Cdb,
-                6,
+                LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
                 0);
 
+    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) {
+        UCHAR interruptReason;
+
+        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_DSC) {
+        KdPrint3((PRINT_PREFIX "AtapiSendCommand: DSC 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, ldev & 1, lChannel, Srb);
+        AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
     }
 
     KdPrint3((PRINT_PREFIX "AtapiSendCommand: ExpectingInterrupt (%#x)\n", chan->ExpectingInterrupt));
@@ -6467,15 +7604,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 ldev;
+    ULONG DeviceNumber;
     PATA_REQ AtaReq;
+    UCHAR command;
+
     SetCheckPoint(5);
     //ULONG __ebp__ = 0;
 
@@ -6507,26 +7649,41 @@ IdeSendCommand(
 
     lChannel = GET_CHANNEL(Srb);
     chan = &(deviceExtension->chan[lChannel]);
-    ldev = GET_LDEV(Srb);
+    //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;
@@ -6540,14 +7697,12 @@ 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 > 2) /*||
-            (!deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)*/) {
+            (Srb->TargetId >= deviceExtension->NumberLuns)) {
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "IdeSendCommand: SCSIOP_INQUIRY rejected\n"));
             // Indicate no device found at this address.
             status = SRB_STATUS_SELECTION_TIMEOUT;
@@ -6555,15 +7710,15 @@ IdeSendCommand(
 
         } else {
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "IdeSendCommand: SCSIOP_INQUIRY ok\n"));
             PINQUIRYDATA    inquiryData  = (PINQUIRYDATA)(Srb->DataBuffer);
-            PIDENTIFY_DATA2 identifyData = &(deviceExtension->lun[ldev].IdentifyData);
-
-            if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+            PIDENTIFY_DATA2 identifyData = &(LunExt->IdentifyData);
 
-                if(!CheckDevice(HwDeviceExtension, lChannel, ldev & 1, FALSE)) {
-                    KdPrint2((PRINT_PREFIX
+            if (!(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+                
+                if(!CheckDevice(HwDeviceExtension, lChannel, DeviceNumber, FALSE)) {
+                    KdPrint2((PRINT_PREFIX 
                                "IdeSendCommand: SCSIOP_INQUIRY rejected (2)\n"));
                     // Indicate no device found at this address.
 #ifndef NAVO_TEST
@@ -6571,11 +7726,11 @@ IdeSendCommand(
                     break;
                 }
             } else {
-                if(!UniataAnybodyHome(HwDeviceExtension, lChannel, ldev & 1)) {
-                    KdPrint2((PRINT_PREFIX
+                if(!UniataAnybodyHome(HwDeviceExtension, lChannel, DeviceNumber)) {
+                    KdPrint2((PRINT_PREFIX 
                                "IdeSendCommand: SCSIOP_INQUIRY device have gone\n"));
                     // Indicate no device found at this address.
-                    UniataForgetDevice(&(deviceExtension->lun[ldev]));
+                    UniataForgetDevice(chan->lun[DeviceNumber]);
 #endif //NAVO_TEST
                     status = SRB_STATUS_SELECTION_TIMEOUT;
                     break;
@@ -6589,15 +7744,15 @@ IdeSendCommand(
             inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
 
             // Set the removable bit, if applicable.
-            if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_REMOVABLE_DRIVE) {
-                KdPrint2((PRINT_PREFIX
+            if (LunExt->DeviceFlags & DFLAGS_REMOVABLE_DRIVE) {
+                KdPrint2((PRINT_PREFIX 
                            "RemovableMedia\n"));
                 inquiryData->RemovableMedia = 1;
             }
             // Set the Relative Addressing (LBA) bit, if applicable.
-            if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_LBA_ENABLED) {
+            if (LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
                 inquiryData->RelativeAddressing = 1;
-                KdPrint2((PRINT_PREFIX
+                KdPrint2((PRINT_PREFIX 
                            "RelativeAddressing\n"));
             }
             // Set the CommandQueue bit
@@ -6605,7 +7760,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.
@@ -6624,24 +7779,86 @@ 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 (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
+        
+        if(cdb->MODE_SENSE.PageCode == MODE_PAGE_POWER_CONDITION) {
+            PMODE_POWER_CONDITION_PAGE modeData;
 
-            SelectDrive(chan, ldev & 0x1);
-            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;
+                modeData->PageLength = sizeof(MODE_PAGE_POWER_CONDITION)-sizeof(MODE_PARAMETER_HEADER);
+                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;
@@ -6652,7 +7869,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;
@@ -6674,20 +7891,20 @@ IdeSendCommand(
 
     case SCSIOP_TEST_UNIT_READY:
 
-        KdPrint2((PRINT_PREFIX
+        KdPrint2((PRINT_PREFIX 
                    "IdeSendCommand: SCSIOP_TEST_UNIT_READY PATH:LUN:TID = %#x:%#x:%#x\n",
                    Srb->PathId, Srb->Lun, Srb->TargetId));
-        if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
+        if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
 
             // Select device 0 or 1.
-            SelectDrive(chan, ldev & 0x1);
-            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;
@@ -6699,7 +7916,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;
@@ -6707,7 +7924,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;
@@ -6721,19 +7938,20 @@ IdeSendCommand(
 
     case SCSIOP_READ_CAPACITY:
 
-        KdPrint2((PRINT_PREFIX
+        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_CAPACITY_DATA));
         MOV_DD_SWP( ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock, i );
 
         // Calculate last sector.
-        if(!(i = (ULONG)deviceExtension->lun[ldev].NumOfSectors)) {
-            i = deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack *
-                deviceExtension->lun[ldev].IdentifyData.NumberOfHeads *
-                deviceExtension->lun[ldev].IdentifyData.NumberOfCylinders;
+        if(!(i = (ULONG)LunExt->NumOfSectors)) {
+            i = LunExt->IdentifyData.SectorsPerTrack *
+                LunExt->IdentifyData.NumberOfHeads *
+                LunExt->IdentifyData.NumberOfCylinders;
         }
         i--;
 
@@ -6743,20 +7961,56 @@ IdeSendCommand(
 
         MOV_DD_SWP( ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress, i );
 
-        KdPrint2((PRINT_PREFIX
+        KdPrint2((PRINT_PREFIX 
                    "** IDE disk %#x - #sectors %#x, #heads %#x, #cylinders %#x\n",
                    Srb->TargetId,
-                   deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack,
-                   deviceExtension->lun[ldev].IdentifyData.NumberOfHeads,
-                   deviceExtension->lun[ldev].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
+        KdPrint2((PRINT_PREFIX 
                    "IdeSendCommand: SCSIOP_VERIFY PATH:LUN:TID = %#x:%#x:%#x\n",
                    Srb->PathId, Srb->Lun, Srb->TargetId));
         status = IdeVerify(HwDeviceExtension,Srb);
@@ -6765,60 +8019,149 @@ IdeSendCommand(
 
     case SCSIOP_READ:
     case SCSIOP_WRITE:
+    case SCSIOP_READ12:
+    case SCSIOP_WRITE12:
+    case SCSIOP_READ16:
+    case SCSIOP_WRITE16:
 
-        KdPrint2((PRINT_PREFIX
+        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;
 
     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));
+        KdPrint2((PRINT_PREFIX 
+                   "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, ldev & 0x1);
-            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, ldev & 0x1);
-       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:
 
-        SelectDrive(chan, ldev & 0x1);
+        SelectDrive(chan, DeviceNumber);
         AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_FLUSH_CACHE);
         status = SRB_STATUS_SUCCESS;
 //        status = SRB_STATUS_PENDING;
@@ -6830,10 +8173,10 @@ IdeSendCommand(
         // this function makes sense buffers to report the results
         // of the original GET_MEDIA_STATUS command
 
-        KdPrint2((PRINT_PREFIX
+        KdPrint2((PRINT_PREFIX 
                    "IdeSendCommand: SCSIOP_REQUEST_SENSE PATH:LUN:TID = %#x:%#x:%#x\n",
                    Srb->PathId, Srb->Lun, Srb->TargetId));
-        if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
+        if (LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
             status = IdeBuildSenseBuffer(HwDeviceExtension,Srb);
             break;
         }
@@ -6846,28 +8189,62 @@ IdeSendCommand(
         PIDEREGS_EX regs;
         BOOLEAN use_dma = FALSE;
         ULONG to_lim;
-
+        
         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",
+            KdPrint2((PRINT_PREFIX 
+                       "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;
@@ -6875,7 +8252,7 @@ IdeSendCommand(
                 }
             }
 
-            AtapiWritePort1(chan, IDX_IO1_o_DriveSelect,  regs->bDriveHeadReg);
+            AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, regs->bDriveHeadReg);
             AtapiStallExecution(10);
 
             if((regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) == 0) {      // execute ATA command
@@ -6897,26 +8274,17 @@ IdeSendCommand(
                 AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, regs->bCylHighReg);
             }
             AtapiWritePort1(chan, IDX_IO1_o_Command,      regs->bCommandReg);
-
+            
             if(use_dma) {
                 GetBaseStatus(chan, statusByte);
                 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);
@@ -6937,7 +8305,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)) {
@@ -6977,42 +8345,41 @@ 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:
-
-        KdPrint2((PRINT_PREFIX
+default_abort:
+        KdPrint2((PRINT_PREFIX 
                    "IdeSendCommand: Unsupported command %#x\n",
                    Srb->Cdb[0]));
 
@@ -7050,23 +8417,24 @@ NTAPI
 IdeMediaStatus(
     BOOLEAN EnableMSN,
     IN PVOID HwDeviceExtension,
-    UCHAR ldev
+    IN ULONG lChannel,
+    IN ULONG DeviceNumber
     )
 {
     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
     PHW_CHANNEL          chan;
-    UCHAR lChannel = ldev >> 1;
     UCHAR statusByte,errorByte;
 
     chan = &(deviceExtension->chan[lChannel]);
+    SelectDrive(chan, DeviceNumber);
 
     if (EnableMSN == TRUE){
 
         // If supported enable Media Status Notification support
-        if ((deviceExtension->lun[ldev].DeviceFlags & DFLAGS_REMOVABLE_DRIVE)) {
+        if ((chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_REMOVABLE_DRIVE)) {
 
             // enable
-            statusByte = AtaCommand(deviceExtension, ldev & 1, lChannel,
+            statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel,
                                 IDE_COMMAND_SET_FEATURES, 0, 0, 0,
                                 0, ATA_C_F_ENAB_MEDIASTAT, ATA_WAIT_BASE_READY);
 
@@ -7074,12 +8442,12 @@ IdeMediaStatus(
                 // Read the error register.
                 errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
 
-                KdPrint2((PRINT_PREFIX
+                KdPrint2((PRINT_PREFIX 
                             "IdeMediaStatus: Error enabling media status. Status %#x, error byte %#x\n",
                              statusByte,
                              errorByte));
             } else {
-                deviceExtension->lun[ldev].DeviceFlags |= DFLAGS_MEDIA_STATUS_ENABLED;
+                chan->lun[DeviceNumber]->DeviceFlags |= DFLAGS_MEDIA_STATUS_ENABLED;
                 KdPrint2((PRINT_PREFIX "IdeMediaStatus: Media Status Notification Supported\n"));
                 chan->ReturningMediaStatus = 0;
 
@@ -7089,12 +8457,12 @@ IdeMediaStatus(
     } else { // end if EnableMSN == TRUE
 
         // disable if previously enabled
-        if ((deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)) {
+        if ((chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)) {
 
-            statusByte = AtaCommand(deviceExtension, ldev & 1, lChannel,
+            statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel,
                                 IDE_COMMAND_SET_FEATURES, 0, 0, 0,
                                 0, ATA_C_F_DIS_MEDIASTAT, ATA_WAIT_BASE_READY);
-            deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_MEDIA_STATUS_ENABLED;
+            chan->lun[DeviceNumber]->DeviceFlags &= ~DFLAGS_MEDIA_STATUS_ENABLED;
         }
 
 
@@ -7178,22 +8546,24 @@ NTAPI
 UniataUserDeviceReset(
     PHW_DEVICE_EXTENSION deviceExtension,
     PHW_LU_EXTENSION LunExt,
-    ULONG PathId,
-    ULONG ldev
+    ULONG lChannel
     )
 {
-    AtapiDisableInterrupts(deviceExtension, PathId);
-    if (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
+    ULONG i;
+    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]), ldev & 1);
+        AtapiSoftReset(&(deviceExtension->chan[lChannel]), LunExt->Lun);
     } else {
         KdPrint2((PRINT_PREFIX "UniataUserDeviceReset: Reset IDE -> reset entire channel\n"));
-        AtapiResetController__(deviceExtension, PathId, RESET_COMPLETE_NONE);
-        deviceExtension->chan[PathId].lun[0]->DeviceFlags |= DFLAGS_REINIT_DMA;
-        deviceExtension->chan[PathId].lun[1]->DeviceFlags |= DFLAGS_REINIT_DMA;
+        AtapiResetController__(deviceExtension, lChannel, RESET_COMPLETE_NONE);
+        for(i=0; i<deviceExtension->NumberLuns; i++) {
+            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()
 
@@ -7239,6 +8609,7 @@ Routine Description:
 
     This routine is called from the SCSI port driver synchronized
     with the kernel to start an IO request.
+    ->HwStartIo
 
 Arguments:
 
@@ -7271,8 +8642,10 @@ AtapiStartIo__(
     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
     UCHAR                lChannel;
     PHW_CHANNEL          chan;
+    PHW_LU_EXTENSION     LunExt;
     ULONG status;
-    ULONG ldev;
+    //ULONG ldev;
+    ULONG DeviceNumber;
     UCHAR PathId;
     UCHAR TargetId;
     UCHAR Lun;
@@ -7291,24 +8664,28 @@ AtapiStartIo__(
 
 /*                KeBugCheckEx(0xc000000e,
                              (Srb->PathId<<16) | (Srb->TargetId<<8) | (Srb->Lun),
-                             Srb->Function,
+                             Srb->Function, 
                              TopLevel, 0x80000001);
 */
     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);
-        chan = &(deviceExtension->chan[lChannel]);
-        ldev = GET_LDEV(Srb);
+        //ldev = GET_LDEV(Srb);
+        chan = NULL;
+        LunExt = NULL;
+        DeviceNumber = GET_CDEV(Srb);
+        commPort = FALSE;
 
         //ASSERT(deviceExtension);
         //ASSERT(chan);
 
-        KdPrint2((PRINT_PREFIX
+        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));
@@ -7318,10 +8695,19 @@ AtapiStartIo__(
            ((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 
@@ -7340,37 +8726,49 @@ AtapiStartIo__(
             commPort = TRUE;
             /* Pass IOCTL request down */
         } else
-        if(GET_CDEV(Srb) >= 2 ||
-           ldev >= deviceExtension->NumberChannels*2 ||
-           lChannel >= deviceExtension->NumberChannels ||
-           Srb->Lun) {
+        if(lChannel >= deviceExtension->NumberChannels ||
+            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, ldev & 1, FALSE)) {
-                KdPrint3((PRINT_PREFIX
+            //if(!CheckDevice(HwDeviceExtension, lChannel, DeviceNumber, FALSE)) {
+            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;
         }
 
-        atapiDev = (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE;
+        if(!commPort) {
+            chan = &(deviceExtension->chan[lChannel]);
+            LunExt = chan->lun[DeviceNumber];
+            if(!LunExt) {
+                goto reject_srb;
+            }
+            atapiDev = (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE;
+        } else {
+            atapiDev = FALSE;
+        }
 
 #ifdef _DEBUG
-        if(!commPort && !(chan->lun[ldev & 1])) {
+        if(!commPort && !LunExt) {
 #if 0
             PrintNtConsole("de = %#x, chan = %#x , dev %#x, nchan %#x\n",
                 deviceExtension,
-                chan, ldev & 1,
+                chan, DeviceNumber,
                 deviceExtension->NumberChannels);
-            PrintNtConsole("lchan = %#x, ldev %#x, cdev %#x, lun0 %#x\n",
-                lChannel, ldev, GET_CDEV(Srb), deviceExtension->chan[0].lun[0]);
+            PrintNtConsole("lchan = %#x, cdev %#x, lun0 %#x\n",
+                lChannel, GET_CDEV(Srb), deviceExtension->chan[0].lun[0]);
             PrintNtConsole("Function %#x, PATH:LUN:TID = %#x:%#x:%#x\n",
                        Srb->Function, Srb->PathId, Srb->Lun, Srb->TargetId);
 #endif //0
@@ -7389,7 +8787,7 @@ reject_srb:
 
         case SRB_FUNCTION_EXECUTE_SCSI:
 
-            if(!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+            if(!LunExt || !(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
                 if(Srb->Cdb[0] == SCSIOP_ATA_PASSTHROUGH) {
                     // let passthrough go
                 } else
@@ -7397,8 +8795,8 @@ reject_srb:
                     // let INQUIRY go
                 } else {
 
-                //if(!CheckDevice(HwDeviceExtension, lChannel, ldev & 1, FALSE)) {
-                    KdPrint2((PRINT_PREFIX
+                //if(!CheckDevice(HwDeviceExtension, lChannel, DeviceNumber, FALSE)) {
+                    KdPrint2((PRINT_PREFIX 
                                "AtapiStartIo: EXECUTE_SCSI rejected (2)\n"));
                     // Indicate no device found at this address.
                     KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
@@ -7406,6 +8804,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 {
@@ -7441,27 +8842,28 @@ reject_srb:
                 }
                 /*KeBugCheckEx(0xc000000e,
                              (Srb->PathId<<16) | (Srb->TargetId<<8) | (Srb->Lun),
-                             Srb->Function,
+                             Srb->Function, 
                              status, 0x80000001);*/
                 if(status == SRB_STATUS_BUSY)
                     status = SRB_STATUS_PENDING;
                 // Insert requests AFTER they have been initialized on
                 // CMD_ACTION_PREPARE stage
                 // we should not check TopLevel here (it is always TRUE)
-                //ASSERT(chan->lun[GET_LDEV(Srb) & 1]);
+                //ASSERT(chan->lun[GET_CDEV(Srb)]);
                 UniataQueueRequest(chan, 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);
                     KdPrint2((PRINT_PREFIX "TopLevel (3), AtaReq %#x\n", AtaReq));
                     //ASSERT(!AtaReq->Flags);
-                    //ASSERT(chan->lun[GET_LDEV(Srb) & 1]);
+                    //ASSERT(chan->lun[GET_CDEV(Srb)]);
                     UniataQueueRequest(chan, Srb);
 //                    AtaReq = (PATA_REQ)(Srb->SrbExtension);
                     //ASSERT(!AtaReq->Flags);
@@ -7470,14 +8872,17 @@ reject_srb:
                 }
 
 #ifndef NAVO_TEST
-                if(!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+                if(!LunExt || !(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+                    if(!LunExt) {
+                        goto reject_srb;
+                    }
                     if(Srb->Cdb[0] == SCSIOP_INQUIRY) {
-                        if(UniataAnybodyHome(deviceExtension, chan->lChannel, ldev & 1)) {
-                            if(!CheckDevice(HwDeviceExtension, chan->lChannel, ldev & 1, TRUE)) {
+                        if(UniataAnybodyHome(deviceExtension, chan->lChannel, DeviceNumber)) {
+                            if(!CheckDevice(HwDeviceExtension, chan->lChannel, DeviceNumber, TRUE)) {
                                 goto reject_srb;
                             }
                         }
-                        if(!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+                        if(!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
                             goto reject_srb;
                         }
                     } else
@@ -7490,8 +8895,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"));
@@ -7512,7 +8918,7 @@ reject_srb:
                 }
 /*                KeBugCheckEx(0xc000000e,
                              (Srb->PathId<<16) | (Srb->TargetId<<8) | (Srb->Lun),
-                             Srb->Function,
+                             Srb->Function, 
                              status, 0x80000002);*/
 
             }
@@ -7589,9 +8995,9 @@ 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, &(deviceExtension->lun[ldev]), lChannel, ldev);
+            UniataUserDeviceReset(deviceExtension, LunExt, lChannel);
             status = SRB_STATUS_SUCCESS;
             break;
 
@@ -7621,9 +9027,9 @@ do_bus_reset:
         case SRB_FUNCTION_SHUTDOWN:
 
             KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown\n"));
-            if(!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+            if(!LunExt || !(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
                 KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown - no such device\n"));
-            }
+            } else
             if(atapiDev) {
                 // FLUSH ATAPI device - do nothing
                 KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown - ATAPI device\n"));
@@ -7631,35 +9037,35 @@ do_bus_reset:
                 // FLUSH IDE/ATA device
                 KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown - IDE device\n"));
                 AtapiDisableInterrupts(deviceExtension, lChannel);
-                status = AtaCommand(deviceExtension, ldev & 1, GET_CHANNEL(Srb),
+                status = AtaCommand(deviceExtension, DeviceNumber, GET_CHANNEL(Srb),
                            IDE_COMMAND_FLUSH_CACHE, 0, 0, 0, 0, 0, ATA_WAIT_IDLE);
                 // If supported & allowed, reset write cacheing
-                if(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_WCACHE_ENABLED) {
+                if(LunExt->DeviceFlags & DFLAGS_WCACHE_ENABLED) {
 
                     // Disable write cache
-                    status = AtaCommand(deviceExtension, ldev & 1, lChannel,
+                    status = AtaCommand(deviceExtension, DeviceNumber, lChannel,
                                         IDE_COMMAND_SET_FEATURES, 0, 0, 0,
                                         0, ATA_C_F_DIS_WCACHE, ATA_WAIT_BASE_READY);
                     // Check for errors.
                     if (status & IDE_STATUS_ERROR) {
-                        KdPrint2((PRINT_PREFIX
+                        KdPrint2((PRINT_PREFIX 
                                     "AtapiHwInitialize: Disable write cacheing on Device %d failed\n",
-                                    ldev));
+                                    DeviceNumber));
                     }
-                    deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
+                    LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
 
                     // Re-enable write cache
-                    status = AtaCommand(deviceExtension, ldev & 1, lChannel,
+                    status = AtaCommand(deviceExtension, DeviceNumber, lChannel,
                                         IDE_COMMAND_SET_FEATURES, 0, 0, 0,
                                         0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY);
                     // Check for errors.
                     if (status & IDE_STATUS_ERROR) {
-                        KdPrint2((PRINT_PREFIX
+                        KdPrint2((PRINT_PREFIX 
                                     "AtapiHwInitialize: Enable write cacheing on Device %d failed\n",
-                                    ldev));
-                        deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
+                                    DeviceNumber));
+                        LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
                     } else {
-                        deviceExtension->lun[ldev].DeviceFlags |= DFLAGS_WCACHE_ENABLED;
+                        LunExt->DeviceFlags |= DFLAGS_WCACHE_ENABLED;
                     }
                 }
 
@@ -7675,35 +9081,6 @@ do_bus_reset:
             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 (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) {
-                status = SRB_STATUS_SUCCESS;
-            } else {
-                status = AtaCommand(deviceExtension, ldev & 1, 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_IO_CONTROL: {
 
             ULONG len;
@@ -7714,44 +9091,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 (!(deviceExtension->lun[ldev].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
@@ -7762,17 +9217,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 << ldev;
+                            deviceNumberMap = 1 << DeviceNumber;
                         } else {
-                            deviceNumber = 4 << ldev;
+                            deviceNumberMap = 4 << DeviceNumber;
                         }
                     } else {
-                        deviceNumber = 1 << ldev;
+                        deviceNumberMap = 1 << (DeviceNumber+lChannel*2);
                     }
 
-                    versionParameters->bIDEDeviceMap = deviceNumber;
+                    versionParameters->bIDEDeviceMap = deviceNumberMap;
 
                     status = SRB_STATUS_SUCCESS;
                     break;
@@ -7782,34 +9241,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);
@@ -7825,9 +9274,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;
@@ -7841,7 +9302,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:
@@ -7850,14 +9311,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);
@@ -7876,63 +9338,75 @@ 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)) {
 
                 PUNIATA_CTL AtaCtl = (PUNIATA_CTL)(Srb->DataBuffer);
-                ULONG ldev = GET_LDEV2(AtaCtl->addr.PathId, AtaCtl->addr.TargetId, 0);
-                PHW_LU_EXTENSION LunExt;
+                //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 ||
-                   ldev >= deviceExtension->NumberChannels*2 ||
+                   AtaCtl->addr.TargetId >= deviceExtension->NumberLuns || 
                    AtaCtl->addr.PathId >= deviceExtension->NumberChannels) {
 
+                    chan = NULL;
                     bad_ldev = TRUE;
                     LunExt = NULL;
 
                 } else {
                     bad_ldev = FALSE;
-                    LunExt = &(deviceExtension->lun[ldev]);
                     lChannel = AtaCtl->addr.PathId;
                     chan = &(deviceExtension->chan[lChannel]);
+                    LunExt = chan->lun[DeviceNumber];
                 }
 
-                KdPrint2((PRINT_PREFIX "AtapiStartIo: -UNIATA- %#x, ldev %#x\n", AtaCtl->hdr.ControlCode, ldev));
+                KdPrint2((PRINT_PREFIX "AtapiStartIo: -UNIATA- %#x, dev %#x\n", AtaCtl->hdr.ControlCode, DeviceNumber));
 
                 /* check for valid LUN */
                 switch (AtaCtl->hdr.ControlCode) {
                 case  IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES:
                 case  IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE:
+                    // this would be BUS reset
                     if(bad_ldev &&
                        (AtaCtl->addr.PathId >= deviceExtension->NumberChannels ||
                         AtaCtl->addr.TargetId != 0xff ||
                         AtaCtl->addr.Lun != 0
                         )) {
                         if(AtaCtl->hdr.ControlCode == IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES &&
-                           ldev < deviceExtension->NumberChannels*2) { // AtaCtl->addr.TargetId != 0xff
-                            LunExt = &(deviceExtension->lun[ldev]);
+                           DeviceNumber < deviceExtension->NumberLuns) { // AtaCtl->addr.TargetId != 0xff
+                            lChannel = AtaCtl->addr.PathId;
+                            chan = &(deviceExtension->chan[lChannel]);
+                            LunExt = chan->lun[DeviceNumber];
                             // OK
                         } else {
                             goto handle_bad_ldev;
                         }
+                    } else {
+                        lChannel = AtaCtl->addr.PathId;
+                        chan = &(deviceExtension->chan[lChannel]);
                     }
-                    // this would be BUS reset
-                    lChannel = AtaCtl->addr.PathId;
-                    chan = &(deviceExtension->chan[lChannel]);
                     break;
                 case  IOCTL_SCSI_MINIPORT_UNIATA_DELETE_DEVICE:
                 case  IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE:
@@ -7956,6 +9430,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;
                     }
@@ -7986,10 +9465,15 @@ 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) {
-                            deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_HIDDEN;
+                            LunExt->DeviceFlags &= ~DFLAGS_HIDDEN;
                         } else {
                         }
                     }
@@ -8010,10 +9494,16 @@ uata_ctl_queue:
 
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: remove %#x:%#x\n", AtaCtl->addr.PathId, AtaCtl->addr.TargetId));
 
-                    deviceExtension->lun[ldev].DeviceFlags = 0;
+                    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"));
-                        deviceExtension->lun[ldev].DeviceFlags |= DFLAGS_HIDDEN;
+                        //LunExt->DeviceFlags |= DFLAGS_HIDDEN;
+                        UniataForgetDevice(LunExt);
                     }
 
                     for(i=0; i<AtaCtl->FindDelDev.WaitForPhysicalLink && i<30; i++) {
@@ -8027,6 +9517,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);
                     }
@@ -8043,10 +9538,10 @@ uata_ctl_queue:
 
                     LunExt->DeviceFlags |= DFLAGS_REINIT_DMA;  // force PIO/DMA reinit
                     if(AtaCtl->SetMode.ApplyImmediately) {
-                        AtapiDmaInit__(deviceExtension, ldev);
+                        AtapiDmaInit__(deviceExtension, LunExt);
                     }
-/*                    deviceExtension->lun[ldev].TransferMode =
-                    deviceExtension->lun[ldev].LimitedTransferMode = (UCHAR)(setTransferMode->Mode);*/
+/*                    LunExt->TransferMode =
+                    LunExt->LimitedTransferMode = (UCHAR)(setTransferMode->Mode);*/
                     status = SRB_STATUS_SUCCESS;
                     break;
                 }
@@ -8054,9 +9549,33 @@ 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;
+                }
+                case  IOCTL_SCSI_MINIPORT_UNIATA_GET_VERSION: {
+
+                    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;
+                    AtaCtl->Version.SubVerMj    = UNIATA_VER_SUB_MJ;
+                    AtaCtl->Version.SubVerMn    = UNIATA_VER_SUB_MN;
 
                     status = SRB_STATUS_SUCCESS;
                     break;
@@ -8065,14 +9584,12 @@ uata_ctl_queue:
 
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: Get adapter info\n"));
 
-                    AtaCtl->AdapterInfo.HeaderLength = offsetof(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;
@@ -8092,19 +9609,48 @@ uata_ctl_queue:
                     AtaCtl->AdapterInfo.InterruptMode = deviceExtension->InterruptMode;
                     AtaCtl->AdapterInfo.BusInterruptVector = deviceExtension->BusInterruptVector;
                     AtaCtl->AdapterInfo.NumberChannels = deviceExtension->NumberChannels;
+                    AtaCtl->AdapterInfo.NumberLuns = (UCHAR)deviceExtension->NumberLuns;
                     AtaCtl->AdapterInfo.AdapterInterfaceType = deviceExtension->AdapterInterfaceType;
                     if(deviceExtension->FullDevName) {
                         strncpy(AtaCtl->AdapterInfo.DeviceName, deviceExtension->FullDevName, 64);
                     }
                     AtaCtl->AdapterInfo.ChanInfoValid = FALSE;
-
-                    RtlZeroMemory(&AtaCtl->AdapterInfo.Chan, sizeof(AtaCtl->AdapterInfo.Chan));
+                    AtaCtl->AdapterInfo.LunInfoValid = FALSE;
+                    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;
                 }
                 case  IOCTL_SCSI_MINIPORT_UNIATA_RESETBB: {
-
+                    
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: Forget BB list\n"));
 
                     ForgetBadBlocks(LunExt);
@@ -8119,7 +9665,7 @@ uata_ctl_queue:
                     if(bad_ldev) {
                         goto do_bus_reset;
                     } else {
-                        UniataUserDeviceReset(deviceExtension, LunExt, AtaCtl->addr.PathId, ldev);
+                        UniataUserDeviceReset(deviceExtension, LunExt, AtaCtl->addr.PathId);
                     }
 
                     status = SRB_STATUS_SUCCESS;
@@ -8161,7 +9707,7 @@ complete_req:
 
         if (status != SRB_STATUS_PENDING) {
 
-            KdPrint2((PRINT_PREFIX
+            KdPrint2((PRINT_PREFIX 
                        "AtapiStartIo: Srb %#x complete with status %#x\n",
                        Srb,
                        status));
@@ -8169,13 +9715,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);
@@ -8185,6 +9737,7 @@ complete_req:
                     Srb = NULL;
                 }
             }
+            KdPrint2((PRINT_PREFIX "AtapiStartIo: chan %x, Src %x\n", chan, Srb));
             if(!chan) {
                 //ASSERT(TopLevel);
             }
@@ -8200,7 +9753,7 @@ complete_req:
                          NULL);
 
     ScsiPortNotification(NextLuRequest,
-                         deviceExtension,
+                         deviceExtension, 
                          PathId,
                          TargetId,
                          Lun);
@@ -8225,7 +9778,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:
@@ -8246,11 +9799,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:
+            //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:
@@ -8263,13 +9824,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 */
 
@@ -8284,10 +9842,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) {
@@ -8316,11 +9887,42 @@ 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;
     }
@@ -8355,7 +9957,10 @@ DriverEntry(
     ULONG                  statusToReturn, newStatus;
     PUNICODE_STRING        RegistryPath = (PUNICODE_STRING)Argument2;
     BOOLEAN                ReEnter = FALSE;
-    WCHAR                  a;
+//    WCHAR                  a;
+#ifndef USE_REACTOS_DDK
+    NTSTATUS               status;
+#endif
 
     PCONFIGURATION_INFORMATION GlobalConfig = IoGetConfigurationInformation();
     BOOLEAN PrimaryClaimed   = FALSE;
@@ -8365,7 +9970,7 @@ DriverEntry(
 
     Connect_DbgPrint();
     KdPrint2((PRINT_PREFIX "%s", (PCCHAR)ver_string));
-    a = (WCHAR)strlen(ver_string);
+    //a = (WCHAR)strlen(ver_string);
 
     g_opt_Verbose = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"PrintLogo", 0);
     if(g_opt_Verbose) {
@@ -8374,7 +9979,21 @@ DriverEntry(
 
     if(!SavedDriverObject) {
         SavedDriverObject = (PDRIVER_OBJECT)DriverObject;
+#ifdef USE_REACTOS_DDK
         KdPrint(("UniATA Init: OS should be ReactOS\n"));
+        MajorVersion=0x04;
+        MinorVersion=0x01;
+        BuildNumber=1;
+#else
+        // we are here for the 1st time
+        // init CrossNT and get OS version
+        if(!NT_SUCCESS(status = CrNtInit(SavedDriverObject, RegistryPath))) {
+            KdPrint(("UniATA Init: CrNtInit failed with status %#x\n", status));
+            //HalDisplayString((PUCHAR)"DbgPrnHkInitialize: CrNtInit failed\n");
+            return status;
+        }
+#endif // USE_REACTOS_DDK
+        KdPrint(("UniATA Init: OS ver %x.%x (%d), %d CPU(s)\n", MajorVersion, MinorVersion, BuildNumber, KeNumberProcessors));
 
         KeQuerySystemTime(&t0);
         do {
@@ -8388,7 +10007,6 @@ DriverEntry(
         } while(t0.QuadPart == t1.QuadPart);
         g_PerfDt = (ULONG)((t1.QuadPart - t0.QuadPart)/10);
         KdPrint(("Performance calibration: dt=%d, counter=%I64d\n", g_PerfDt, g_Perf ));
-
     } else {
         KdPrint(("UniATA Init: ReEnter\n"));
         ReEnter = TRUE;
@@ -8462,7 +10080,49 @@ DriverEntry(
     KdPrint2((PRINT_PREFIX "\n\nATAPI IDE enum supported BusMaster Devices\n"));
 
     if(!ReEnter) {
+
+        g_opt_VirtualMachine = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"VirtualMachineType", g_opt_VirtualMachine);
+        if(g_opt_VirtualMachine > VM_MAX_KNOWN) {
+            g_opt_VirtualMachine = 0;
+        }
+        if(AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"VirtualBox", (g_opt_VirtualMachine == VM_VBOX))) {
+            g_opt_VirtualMachine = VM_VBOX;
+        }
+        // Pre-scan PCI bus, also check if we are under VM
         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_WaitBusyLongCount = 20000;
+            g_opt_MaxIsrWait = 200;
+            g_opt_AtapiSendDisableIntr = 0;
+            g_opt_AtapiDmaRawRead = FALSE;
+            break;
+        }
+
+        if(!hasPCI) {
+            KdPrint2((PRINT_PREFIX "old slow machine, adjust timings\n"));
+            // old slow machine, adjust timings
+            g_opt_WaitBusyCount = 20000;
+            g_opt_WaitBusyDelay = 150;
+            g_opt_WaitDrqDelay  = 100;
+            g_opt_WaitBusyLongCount = 20000;
+            g_opt_MaxIsrWait = 200;
+        }
+
+        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_WaitBusyLongCount = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyLongCount", g_opt_WaitBusyLongCount); // 2000 vs 20000
+        g_opt_WaitBusyLongDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyLongDelay", g_opt_WaitBusyLongDelay); // 250 vs 250
+        g_opt_AtapiSendDisableIntr = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiSendDisableIntr",  g_opt_AtapiSendDisableIntr);  // 1 vs 0
+        g_opt_AtapiDmaRawRead      = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiDmaRawRead",       g_opt_AtapiDmaRawRead);       // 1 vs 0
+        g_opt_MaxIsrWait    = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"MaxIsrWait",       g_opt_MaxIsrWait);       // 40 vs xxx
     }
 
     // Look for legacy ISA-bridged PCI IDE controller (onboard)
@@ -8486,16 +10146,27 @@ DriverEntry(
             }
             continue;
         }
-        BMList[i].AltInitMasterDev = (UCHAR)0xff;
+        //BMList[i].AltInitMasterDev = (UCHAR)0xff;
 
         if(GlobalConfig->AtDiskPrimaryAddressClaimed)
             PrimaryClaimed = TRUE;
         if(GlobalConfig->AtDiskSecondaryAddressClaimed)
             SecondaryClaimed = TRUE;
 
+        if(!WinVer_WDM_Model && !PrimaryClaimed && !SecondaryClaimed &&
+            !(BMList[i].ChanInitOk & 0x80)) {
+            newStatus = UniataClaimLegacyPCIIDE(i);
+            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++) {
@@ -8544,12 +10215,20 @@ DriverEntry(
                                                Argument2,
                                                &hwInitializationData.comm,
                                                (PVOID)(i | (alt ? 0x80000000 : 0)));
-                KdPrint2((PRINT_PREFIX "Status %#x\n", newStatus));
+                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()
@@ -8558,43 +10237,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 "Status %#x\n", newStatus));
-        }
-#endif //0
         if(g_opt_Verbose) {
             if(BMList[i].ChanInitOk & 0x03) {
                 _PrintNtConsole("  OK\n");
@@ -8607,7 +10271,7 @@ DriverEntry(
 
 /*    KeBugCheckEx(0xc000000e,
                  (i << 16) | BMList[0].ChanInitOk,
-                 c,
+                 c, 
                  newStatus, statusToReturn);*/
 
     // Look for PCI IDE controller
@@ -8632,9 +10296,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*/;
@@ -8646,6 +10310,21 @@ DriverEntry(
                                        Argument2,
                                        &hwInitializationData.comm,
                                        (PVOID)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
+            // It stops scanning PCI bus when reaches empty PCI Function inside Slot
+            // However, this PCI Slot may have higher non-empty Functions
+            // UniATA will perform all staff instead of ScsiPort under NT,
+            // but for ReactOS it is better to patch ScsiPort.
+            KdPrint2((PRINT_PREFIX "STATUS_DEVICE_DOES_NOT_EXIST, try workaround\n"));
+            hwInitializationData.comm.AdapterInterfaceType = Isa;
+            newStatus = ScsiPortInitialize(DriverObject,
+                                           Argument2,
+                                           &hwInitializationData.comm,
+                                           (PVOID)(i | 0x80000000));
+            KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x (2)\n", newStatus));
+        }
         if (newStatus < statusToReturn)
             statusToReturn = newStatus;
 
@@ -8671,6 +10350,12 @@ 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.
 
@@ -8689,6 +10374,7 @@ DriverEntry(
                                         Argument2,
                                         &hwInitializationData.comm,
                                         &adapterCount);
+        KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
         if (newStatus < statusToReturn)
             statusToReturn = newStatus;
     }
@@ -8702,12 +10388,13 @@ DriverEntry(
                                         Argument2,
                                         &hwInitializationData.comm,
                                         &adapterCount);
+        KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
         if (newStatus < statusToReturn)
             statusToReturn = newStatus;
     }
     InDriverEntry = FALSE;
 
-    KdPrint2((PRINT_PREFIX "\n\nLeave ATAPI IDE MiniPort DriverEntry with status %#x\n", statusToReturn));
+    KdPrint2((PRINT_PREFIX "\n\nLeave UNIATA MiniPort DriverEntry with status %#x\n", statusToReturn));
 
     return statusToReturn;
 
@@ -8751,6 +10438,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()
 
@@ -8793,6 +10482,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()
 
@@ -9029,13 +10720,13 @@ AtapiRegCheckParameterValue(
     RtlZeroMemory(paramPath.Buffer, paramPath.MaximumLength);
     RtlAppendUnicodeToString(&paramPath, RegistryPath->Buffer);
     RtlAppendUnicodeToString(&paramPath, L"\\");
-    RtlAppendUnicodeToString(&paramPath, PathSuffix);
+    RtlAppendUnicodeToString(&paramPath, REGRTL_STR_PTYPE PathSuffix);
 
     // Check for the Xxx value.
     RtlZeroMemory(parameters, (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY));
 
     parameters[0].Flags         = RTL_QUERY_REGISTRY_DIRECT;
-    parameters[0].Name          = Name;
+    parameters[0].Name          = REGRTL_STR_PTYPE Name;
     parameters[0].EntryContext  = &doRun;
     parameters[0].DefaultType   = REG_DWORD;
     parameters[0].DefaultData   = &zero;
@@ -9043,7 +10734,9 @@ 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);
 
@@ -9111,7 +10804,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;
@@ -9124,15 +10817,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;
@@ -9157,6 +10852,8 @@ HalDisplayString (
     PUCHAR String
     );
 
+#define DEBUG_MSG_BUFFER_SIZE   512
+
 extern "C"
 VOID
 _cdecl
@@ -9165,20 +10862,26 @@ _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;
 
+    //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()
 
-