[uniata]
[reactos.git] / reactos / drivers / storage / ide / uniata / id_dma.cpp
index 64d8d0b..2f04ff4 100644 (file)
@@ -1,6 +1,6 @@
 /*++
 
-Copyright (c) 2002-2010 Alexander A. Telyatnikov (Alter)
+Copyright (c) 2002-2014 Alexander A. Telyatnikov (Alter)
 
 Module Name:
     id_dma.cpp
@@ -91,15 +91,13 @@ hpt_cable80(
     IN ULONG channel            // physical channel number (0-1)
     );
 
-#define ATAPI_DEVICE(de, ldev)    (de->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE)
-
 ULONG
 NTAPI
 AtapiVirtToPhysAddr_(
     IN PVOID HwDeviceExtension,
     IN PSCSI_REQUEST_BLOCK Srb,
     IN PUCHAR data,
-    IN PULONG count,
+   OUT PULONG count, /* bytes */
    OUT PULONG ph_addru
     )
 {
@@ -185,28 +183,52 @@ err_1:
 
 
     if(deviceExtension->HwFlags & UNIATA_AHCI) {
-        if(chan->AHCI_CL) {
+        KdPrint2((PRINT_PREFIX "AtapiDmaAlloc: AHCI\n" ));
+        if(chan->AhciCtlBlock) {
+            KdPrint2((PRINT_PREFIX "  already initialized %x\n", chan->AhciCtlBlock));
             return;
         }
-        chan->AHCI_CL = (PIDE_AHCI_CMD_LIST)MmAllocateContiguousMemory(sizeof(IDE_AHCI_CMD_LIST)*ATA_AHCI_MAX_TAGS+sizeof(IDE_AHCI_RCV_FIS), ph4gb);
-        if(chan->AHCI_CL) {
-            chan->AHCI_CL_PhAddr = AtapiVirtToPhysAddr(HwDeviceExtension, NULL, (PUCHAR)(chan->AHCI_CL), &i, &ph_addru);
-            if(!chan->AHCI_CL_PhAddr || !i || ((LONG)(chan->AHCI_CL_PhAddr) == -1)) {
+        // Need 1K-byte alignment
+        chan->AhciCtlBlock0 = (PIDE_AHCI_CHANNEL_CTL_BLOCK)MmAllocateContiguousMemory(
+                sizeof(IDE_AHCI_CHANNEL_CTL_BLOCK)+AHCI_CLB_ALIGNEMENT_MASK,
+                ph4gb);
+        if(chan->AhciCtlBlock0) {
+            union {
+                PUCHAR AhciCtlBlock;
+                ULONGLONG AhciCtlBlock64;
+            };
+            AhciCtlBlock64 = 0;
+            AhciCtlBlock = (PUCHAR)chan->AhciCtlBlock0;
+
+            KdPrint2((PRINT_PREFIX "AtapiDmaAlloc: CLP BASE %I64x\n", AhciCtlBlock64));
+
+            AhciCtlBlock64 += AHCI_CLB_ALIGNEMENT_MASK;
+            AhciCtlBlock64 &= ~AHCI_CLB_ALIGNEMENT_MASK;
+
+            KdPrint2((PRINT_PREFIX "AtapiDmaAlloc: CLP BASE 1k-aligned %I64x\n", AhciCtlBlock64));
+
+            chan->AhciCtlBlock = (PIDE_AHCI_CHANNEL_CTL_BLOCK)AhciCtlBlock;
+
+            chan->AHCI_CTL_PhAddr = AtapiVirtToPhysAddr(HwDeviceExtension, NULL, (PUCHAR)(chan->AhciCtlBlock), &i, &ph_addru);
+            KdPrint2((PRINT_PREFIX "AtapiDmaAlloc: CLP Phys BASE %I64x\n", chan->AHCI_CTL_PhAddr));
+            if(!chan->AHCI_CTL_PhAddr || !i || ((LONG)(chan->AHCI_CTL_PhAddr) == -1)) {
                 KdPrint2((PRINT_PREFIX "AtapiDmaAlloc: No AHCI CLP BASE\n" ));
-                chan->AHCI_CL = NULL;
-                chan->AHCI_CL_PhAddr = 0;
+                chan->AhciCtlBlock = NULL;
+                chan->AHCI_CTL_PhAddr = 0;
                 return;
             }
             if(ph_addru) {
                 KdPrint2((PRINT_PREFIX "AtapiDmaAlloc: No AHCI CLP below 4Gb\n" ));
-                MmFreeContiguousMemory(chan->AHCI_CL);
-                chan->AHCI_CL = NULL;
-                chan->AHCI_CL_PhAddr = 0;
+                MmFreeContiguousMemory(chan->AhciCtlBlock0);
+                chan->AhciCtlBlock = NULL;
+                chan->AHCI_CTL_PhAddr = 0;
                 return;
             }
+        } else {
+            KdPrint2((PRINT_PREFIX "AtapiDmaAlloc: Can't alloc AHCI CLP\n"));
         }
     }
-    #endif //USE_OWN_DMA
+#endif //USE_OWN_DMA
     return;
 } // end AtapiDmaAlloc()
 
@@ -218,25 +240,34 @@ AtapiDmaSetup(
     IN ULONG lChannel,          // logical channel,
     IN PSCSI_REQUEST_BLOCK Srb,
     IN PUCHAR data,
-    IN ULONG count
+    IN ULONG count  /* bytes */
     )
 {
     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
     ULONG dma_count, dma_base, dma_baseu;
+    ULONG dma_count0, dma_base0;
     ULONG i;
     PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
     PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
     BOOLEAN use_DB_IO = FALSE;
-    //BOOLEAN use_AHCI = FALSE;
+    BOOLEAN use_AHCI = (deviceExtension->HwFlags & UNIATA_AHCI) ? TRUE : FALSE;
     ULONG orig_count = count;
-    ULONG max_entries = (deviceExtension->HwFlags & UNIATA_AHCI) ? ATA_AHCI_DMA_ENTRIES : ATA_DMA_ENTRIES;
+    ULONG max_entries = use_AHCI ? ATA_AHCI_DMA_ENTRIES : ATA_DMA_ENTRIES;
+    //ULONG max_frag = use_AHCI ? (0x3fffff+1) : (4096); // DEBUG, replace 4096 for procer chipset-specific value
+    ULONG max_frag = deviceExtension->DmaSegmentLength;
+    ULONG seg_align = deviceExtension->DmaSegmentAlignmentMask;
 
+    if(AtaReq->dma_entries) {
+        KdPrint2((PRINT_PREFIX "AtapiDmaSetup: already setup, %d entries\n", AtaReq->dma_entries));
+        return TRUE;
+    }
+    AtaReq->ata.dma_base = 0;
     AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
 
     KdPrint2((PRINT_PREFIX "AtapiDmaSetup: mode %#x, data %x, count %x, lCh %x, dev %x\n",
-        deviceExtension->lun[lChannel*2+DeviceNumber].TransferMode,
+        chan->lun[DeviceNumber]->TransferMode,
         data, count, lChannel, DeviceNumber ));
-    if(deviceExtension->lun[lChannel*2+DeviceNumber].TransferMode < ATA_DMA) {
+    if(chan->lun[DeviceNumber]->TransferMode < ATA_DMA) {
         KdPrint2((PRINT_PREFIX "AtapiDmaSetup: Not DMA mode, assume this is just preparation\n" ));
         //return FALSE;
     }
@@ -251,15 +282,21 @@ AtapiDmaSetup(
         return FALSE;
     }
     //KdPrint2((PRINT_PREFIX "  checkpoint 3\n" ));
-    if((ULONG_PTR)data & deviceExtension->AlignmentMask) {
+    if((ULONG)data & deviceExtension->AlignmentMask) {
         KdPrint2((PRINT_PREFIX "AtapiDmaSetup: unaligned data: %#x (%#x)\n", data, deviceExtension->AlignmentMask));
         return FALSE;
     }
 
     //KdPrint2((PRINT_PREFIX "  checkpoint 4\n" ));
-    KdPrint2((PRINT_PREFIX "  get Phys(PRD=%x)\n", &(AtaReq->dma_tab) ));
-    dma_base = AtapiVirtToPhysAddr(HwDeviceExtension, NULL, (PUCHAR)&(AtaReq->dma_tab) /*chan->dma_tab*/, &i, &dma_baseu);
-    if(dma_baseu) {
+    if(use_AHCI) {
+        KdPrint2((PRINT_PREFIX "  get Phys(AHCI_CMD=%x)\n", AtaReq->ahci.ahci_cmd_ptr ));
+        dma_base = AtapiVirtToPhysAddr(HwDeviceExtension, NULL, (PUCHAR)(AtaReq->ahci.ahci_cmd_ptr), &i, &dma_baseu);
+        AtaReq->ahci.ahci_base64 = 0; // clear before setup
+    } else {
+        KdPrint2((PRINT_PREFIX "  get Phys(PRD=%x)\n", &(AtaReq->dma_tab) ));
+        dma_base = AtapiVirtToPhysAddr(HwDeviceExtension, NULL, (PUCHAR)&(AtaReq->dma_tab) /*chan->dma_tab*/, &i, &dma_baseu);
+    }
+    if(dma_baseu && i) {
         KdPrint2((PRINT_PREFIX "AtapiDmaSetup: SRB built-in PRD above 4Gb: %8.8x%8.8x\n", dma_baseu, dma_base));
         if(!deviceExtension->Host64) {
             dma_base = chan->DB_PRD_PhAddr;
@@ -271,53 +308,78 @@ AtapiDmaSetup(
         KdPrint2((PRINT_PREFIX "AtapiDmaSetup: No BASE\n" ));
         return FALSE;
     }
-    AtaReq->dma_base = dma_base;
+    AtaReq->ata.dma_base = dma_base; // aliased to AtaReq->ahci.ahci_base64
 
-    KdPrint2((PRINT_PREFIX "  get Phys(data=%x)\n", data ));
+    KdPrint2((PRINT_PREFIX "  get Phys(data[0]=%x)\n", data ));
     dma_base = AtapiVirtToPhysAddr(HwDeviceExtension, Srb, data, &dma_count, &dma_baseu);
-    if(dma_baseu) {
-        KdPrint2((PRINT_PREFIX "AtapiDmaSetup: 1st block of buffer above 4Gb: %8.8x%8.8x\n", dma_baseu, dma_base));
+    if(dma_baseu && dma_count) {
+        KdPrint2((PRINT_PREFIX "AtapiDmaSetup: 1st block of buffer above 4Gb: %8.8x%8.8x cnt=%x\n", dma_baseu, dma_base, dma_count));
         if(!deviceExtension->Host64) {
 retry_DB_IO:
             use_DB_IO = TRUE;
             dma_base = chan->DB_IO_PhAddr;
             data = (PUCHAR)(chan->DB_IO);
         } else {
-            AtaReq->ahci_base64 = (ULONGLONG)dma_base | ((ULONGLONG)dma_baseu << 32);
+            AtaReq->ahci.ahci_base64 = (ULONGLONG)dma_base | ((ULONGLONG)dma_baseu << 32);
         }
     } else
     if(!dma_count || ((LONG)(dma_base) == -1)) {
         KdPrint2((PRINT_PREFIX "AtapiDmaSetup: No 1st block\n" ));
         //AtaReq->dma_base = NULL;
-        AtaReq->ahci_base64 = NULL;
+        AtaReq->ahci.ahci_base64 = NULL;
         return FALSE;
     }
 
-    dma_count = min(count, (PAGE_SIZE - ((ULONG_PTR)data & PAGE_MASK)));
+    dma_count = min(count, (PAGE_SIZE - ((ULONG)data & PAGE_MASK)));
     data += dma_count;
     count -= dma_count;
     i = 0;
 
+    dma_count0 = dma_count;
+    dma_base0 = dma_base;
+
     while (count) {
-        if(deviceExtension->HwFlags & UNIATA_AHCI) {
-            AtaReq->ahci_cmd.prd_tab[i].base   = dma_base;
-            AtaReq->ahci_cmd.prd_tab[i].baseu  = dma_baseu;
-            AtaReq->ahci_cmd.prd_tab[i].DBC    = ((dma_count-1) & 0x3fffff);
+/*        KdPrint2((PRINT_PREFIX " segments %#x+%#x == %#x && %#x+%#x <= %#x\n",
+             dma_base0, dma_count0, dma_base,
+             dma_count0, dma_count, max_frag));*/
+        if(dma_base0+dma_count0 == dma_base &&
+           dma_count0+dma_count <= max_frag) {
+            // 'i' should be always > 0 here
+            // for BM we cannot cross 64k boundary
+            if(dma_base & seg_align) {
+                //KdPrint2((PRINT_PREFIX "  merge segments\n" ));
+                ASSERT(i);
+                //BrutePoint();
+                i--;
+                dma_base = dma_base0;
+                dma_count += dma_count0;
+            }
+        }
+        if(use_AHCI) {
+            AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].base   = dma_base;
+            AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].baseu  = dma_baseu;
+            AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].Reserved1 = 0;
+            *((PULONG)&(AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].DBC_ULONG)) = ((dma_count-1) & 0x3fffff);
+/*            AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].Reserved2 = 0;
+            AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].I = 0;*/
+            KdPrint2((PRINT_PREFIX "  ph data[%d]=%x:%x (%x)\n", i, dma_baseu, dma_base, AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].DBC));
         } else {
             AtaReq->dma_tab[i].base  = dma_base;
             AtaReq->dma_tab[i].count = (dma_count & 0xffff);
         }
+        dma_count0 = dma_count;
+        dma_base0 = dma_base;
         i++; 
         if (i >= max_entries) {
             KdPrint2((PRINT_PREFIX "too many segments in DMA table\n" ));
             //AtaReq->dma_base = NULL;
-            AtaReq->ahci_base64 = NULL;
+            AtaReq->ahci.ahci_base64 = NULL;
             return FALSE;
         }
-        KdPrint2((PRINT_PREFIX "  get Phys(data[n]=%x)\n", data ));
+        KdPrint2((PRINT_PREFIX "  get Phys(data[n=%d]=%x)\n", i, data ));
         dma_base = AtapiVirtToPhysAddr(HwDeviceExtension, Srb, data, &dma_count, &dma_baseu);
-        if(dma_baseu) {
-            KdPrint2((PRINT_PREFIX "AtapiDmaSetup: block of buffer above 4Gb: %8.8x%8.8x\n", dma_baseu, dma_base));
+        if(dma_baseu && dma_count) {
+            KdPrint2((PRINT_PREFIX "AtapiDmaSetup: block of buffer above 4Gb: %8.8x%8.8x, cnt=%x\n", dma_baseu, dma_base, dma_count));
             if(!deviceExtension->Host64) {
                 if(use_DB_IO) {
                     KdPrint2((PRINT_PREFIX "AtapiDmaSetup: *ERROR* special buffer above 4Gb: %8.8x%8.8x\n", dma_baseu, dma_base));
@@ -329,7 +391,7 @@ retry_DB_IO:
         } else
         if(!dma_count || !dma_base || ((LONG)(dma_base) == -1)) {
             //AtaReq->dma_base = NULL;
-            AtaReq->ahci_base64 = 0;
+            AtaReq->ahci.ahci_base64 = 0;
             KdPrint2((PRINT_PREFIX "AtapiDmaSetup: No NEXT block\n" ));
             return FALSE;
         }
@@ -339,15 +401,45 @@ retry_DB_IO:
         count -= min(count, PAGE_SIZE);
     }
     KdPrint2((PRINT_PREFIX "  set TERM\n" ));
-    if(deviceExtension->HwFlags & UNIATA_AHCI) {
-        AtaReq->ahci_cmd.prd_tab[i].base   = dma_base;
-        AtaReq->ahci_cmd.prd_tab[i].baseu  = dma_baseu;
-        AtaReq->ahci_cmd.prd_tab[i].DBC    = ((dma_count-1) & 0x3fffff);
+/*    KdPrint2((PRINT_PREFIX " segments %#x+%#x == %#x && #x+%#x <= %#x\n",
+         dma_base0, dma_count0, dma_base,
+         dma_count0, dma_count, max_frag));*/
+    if(dma_base0+dma_count0 == dma_base &&
+       dma_count0+dma_count <= max_frag) {
+        // 'i' should be always > 0 here
+        if(dma_base & seg_align) {
+            //KdPrint2((PRINT_PREFIX "  merge segments\n" ));
+            //BrutePoint();
+            ASSERT(i);
+            i--;
+            dma_base = dma_base0;
+            dma_count += dma_count0;
+        }
+    }
+    if(use_AHCI) {
+        AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].base   = dma_base;
+        AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].baseu  = dma_baseu;
+        AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].Reserved1 = 0;
+        //AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].DBC    = ((dma_count-1) & 0x3fffff);
+        //AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].Reserved2 = 0;
+        *((PULONG)&(AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].DBC_ULONG)) = ((dma_count-1) & 0x3fffff);
+        //AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].I      = 1; // interrupt when ready
+        KdPrint2((PRINT_PREFIX "  ph data[%d]=%x:%x (%x)\n", i, dma_baseu, dma_base, AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].DBC));
+        if(((ULONG)&(AtaReq->ahci.ahci_cmd_ptr->prd_tab) & ~PAGE_MASK) != ((ULONG)&(AtaReq->ahci.ahci_cmd_ptr->prd_tab[i]) & ~PAGE_MASK)) {
+            KdPrint2((PRINT_PREFIX "PRD table crosses page boundary! %x vs %x\n",
+                &AtaReq->ahci.ahci_cmd_ptr->prd_tab, &(AtaReq->ahci.ahci_cmd_ptr->prd_tab[i]) ));
+            //AtaReq->Flags |= REQ_FLAG_DMA_DBUF_PRD;
+        }
     } else {
         AtaReq->dma_tab[i].base = dma_base;
         AtaReq->dma_tab[i].count = (dma_count & 0xffff) | ATA_DMA_EOT;
+        if(((ULONG)&(AtaReq->dma_tab) & ~PAGE_MASK) != ((ULONG)&(AtaReq->dma_tab[i]) & ~PAGE_MASK)) {
+            KdPrint2((PRINT_PREFIX "DMA table crosses page boundary! %x vs %x\n",
+                &AtaReq->dma_tab, &(AtaReq->dma_tab[i]) ));
+            //AtaReq->Flags |= REQ_FLAG_DMA_DBUF_PRD;
+        }
     }
-    AtaReq->dma_entries = i;
+    AtaReq->dma_entries = i+1;
 
     if(use_DB_IO) {
         AtaReq->Flags |= REQ_FLAG_DMA_DBUF;
@@ -466,15 +558,15 @@ AtapiDmaStart(
         (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "read" : "write",
         lChannel, DeviceNumber ));
 
-    if(!AtaReq->dma_base) {
-        KdPrint2((PRINT_PREFIX "AtapiDmaStart: *** !AtaReq->dma_base\n"));
+    if(!AtaReq->ata.dma_base) {
+        KdPrint2((PRINT_PREFIX "AtapiDmaStart: *** !AtaReq->ata.dma_base\n"));
         return;
     }
     if(AtaReq->Flags & REQ_FLAG_DMA_DBUF_PRD) {
         KdPrint2((PRINT_PREFIX "  DBUF_PRD\n"));
         ASSERT(FALSE);
         if(deviceExtension->HwFlags & UNIATA_AHCI) {
-            RtlCopyMemory(chan->DB_PRD, &(AtaReq->ahci_cmd), sizeof(AtaReq->ahci_cmd));
+            RtlCopyMemory(chan->DB_PRD, AtaReq->ahci.ahci_cmd_ptr, sizeof(AtaReq->ahci_cmd0));
         } else {
             RtlCopyMemory(chan->DB_PRD, &(AtaReq->dma_tab), sizeof(AtaReq->dma_tab));
         }
@@ -495,10 +587,10 @@ AtapiDmaStart(
         if(ChipType == PRNEW) {
             ULONG Channel = deviceExtension->Channel + lChannel;
             if(chan->ChannelCtrlFlags & CTRFLAGS_LBA48) {
-                AtapiWritePortEx1(chan, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0),0x11,
-                      AtapiReadPortEx1(chan, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0),0x11) |
+                AtapiWritePortEx1(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x11,
+                      AtapiReadPortEx1(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x11) |
                           (Channel ? 0x08 : 0x02));
-                AtapiWritePortEx4(chan, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0),(Channel ? 0x24 : 0x20),
+                AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),(Channel ? 0x24 : 0x20),
                       ((Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? 0x05000000 : 0x06000000) | (Srb->DataTransferLength >> 1)
                       );
             }
@@ -519,7 +611,7 @@ AtapiDmaStart(
 
     // set pointer to Pointer Table
     AtapiWritePort4(chan, IDX_BM_PRD_Table,
-          AtaReq->dma_base
+          AtaReq->ata.dma_base
           );
     // set transfer direction
     AtapiWritePort1(chan, IDX_BM_Command,
@@ -557,15 +649,20 @@ AtapiDmaDone(
 
     KdPrint2((PRINT_PREFIX "AtapiDmaDone: dev %d\n", DeviceNumber));
 
+    if(deviceExtension->HwFlags & UNIATA_AHCI) {
+        KdPrint2((PRINT_PREFIX "  ACHTUNG! should not be called for AHCI!\n"));
+        return IDE_STATUS_WRONG;
+    }
+
     switch(VendorID) {
     case ATA_PROMISE_ID:
         if(ChipType == PRNEW) {
             ULONG Channel = deviceExtension->Channel + lChannel;
             if(chan->ChannelCtrlFlags & CTRFLAGS_LBA48) {
-                AtapiWritePortEx1(chan, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0),0x11,
-                      AtapiReadPortEx1(chan, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0),0x11) &
+                AtapiWritePortEx1(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x11,
+                      AtapiReadPortEx1(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x11) &
                           ~(Channel ? 0x08 : 0x02));
-                AtapiWritePortEx4(chan, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0),(Channel ? 0x24 : 0x20),
+                AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),(Channel ? 0x24 : 0x20),
                       0
                       );
             }
@@ -604,23 +701,36 @@ VOID
 NTAPI
 AtapiDmaReinit(
     IN PHW_DEVICE_EXTENSION deviceExtension,
-    IN ULONG ldev,
+    IN PHW_LU_EXTENSION LunExt,
     IN PATA_REQ AtaReq
     )
 {
-    PHW_LU_EXTENSION LunExt = &(deviceExtension->lun[ldev]);
     SCHAR apiomode;
 
+    if((deviceExtension->HwFlags & UNIATA_AHCI) &&
+      !(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
+        // skip unnecessary checks
+        KdPrint2((PRINT_PREFIX "AtapiDmaReinit: ahci, nothing to do for HDD\n"));
+        return;
+    }
+
     apiomode = (CHAR)AtaPioMode(&(LunExt->IdentifyData));
 
     if(!(AtaReq->Flags & REQ_FLAG_DMA_OPERATION)) {
         KdPrint2((PRINT_PREFIX
-                    "AtapiDmaReinit: !(AtaReq->Flags & REQ_FLAG_DMA_OPERATION), fall to PIO on Device %d\n", ldev & 1));
+                    "AtapiDmaReinit: !(AtaReq->Flags & REQ_FLAG_DMA_OPERATION), fall to PIO on Device %d\n", LunExt->Lun));
         goto limit_pio;
     }
-    if(!AtaReq->dma_base) {
+    if(deviceExtension->HwFlags & UNIATA_AHCI) {
+        if(!AtaReq->ahci.ahci_base64) {
+            KdPrint2((PRINT_PREFIX
+                        "AtapiDmaReinit: no AHCI PRD, fatal on Device %d\n", LunExt->Lun));
+            goto exit;
+        }
+    } else
+    if(!AtaReq->ata.dma_base) {
         KdPrint2((PRINT_PREFIX
-                    "AtapiDmaReinit: no PRD, fall to PIO on Device %d\n", ldev & 1));
+                    "AtapiDmaReinit: no PRD, fall to PIO on Device %d\n", LunExt->Lun));
         goto limit_pio;
     }
 
@@ -628,14 +738,14 @@ AtapiDmaReinit(
        (AtaReq->lba >= (LONGLONG)ATA_MAX_LBA28) &&
        (LunExt->TransferMode > ATA_PIO5) ) {
         KdPrint2((PRINT_PREFIX
-                    "AtapiDmaReinit: FORCE_DOWNRATE on Device %d for LBA48\n", ldev & 1));
+                    "AtapiDmaReinit: FORCE_DOWNRATE on Device %d for LBA48\n", LunExt->Lun));
         goto limit_lba48;
     }
 
 
     if(AtaReq->Flags & REQ_FLAG_FORCE_DOWNRATE) {
         KdPrint2((PRINT_PREFIX
-                    "AtapiDmaReinit: FORCE_DOWNRATE on Device %d\n", ldev & 1));
+                    "AtapiDmaReinit: FORCE_DOWNRATE on Device %d\n", LunExt->Lun));
         if(AtaReq->lba >= (LONGLONG)ATA_MAX_LBA28) {
 limit_lba48:
             LunExt->DeviceFlags |= REQ_FLAG_FORCE_DOWNRATE_LBA48;
@@ -645,16 +755,16 @@ limit_pio:
                (LunExt->TransferMode > ATA_PIO5) && (LunExt->TransferMode != ATA_PIO0+apiomode)
                ) {
                 KdPrint2((PRINT_PREFIX 
-                            "AtapiDmaReinit: set PIO mode on Device %d (%x -> %x)\n", ldev & 1, LunExt->TransferMode, ATA_PIO0+apiomode));
-                AtapiDmaInit(deviceExtension, ldev & 1, ldev >> 1,
+                            "AtapiDmaReinit: set PIO mode on Device %d (%x -> %x)\n", LunExt->Lun, LunExt->TransferMode, ATA_PIO0+apiomode));
+                AtapiDmaInit(deviceExtension, LunExt->Lun, LunExt->chan->lChannel,
                              apiomode,
                              -1,
                              -1 );
             } else
             if(LunExt->LimitedTransferMode < LunExt->TransferMode) {
                 KdPrint2((PRINT_PREFIX 
-                            "AtapiDmaReinit: set PIO mode on Device %d (%x -> %x) (2)\n", ldev & 1, LunExt->TransferMode, LunExt->LimitedTransferMode));
-                AtapiDmaInit(deviceExtension, ldev & 1, ldev >> 1,
+                            "AtapiDmaReinit: set PIO mode on Device %d (%x -> %x) (2)\n", LunExt->Lun, LunExt->TransferMode, LunExt->LimitedTransferMode));
+                AtapiDmaInit(deviceExtension, LunExt->Lun, LunExt->chan->lChannel,
                              LunExt->LimitedTransferMode-ATA_PIO0, 
                              -1,
                              -1 );
@@ -662,8 +772,8 @@ limit_pio:
 
         } else {
             KdPrint2((PRINT_PREFIX
-                        "AtapiDmaReinit: set MAX mode on Device %d\n", ldev & 1));
-            AtapiDmaInit(deviceExtension, ldev & 1, ldev >> 1,
+                        "AtapiDmaReinit: set MAX mode on Device %d\n", LunExt->Lun));
+            AtapiDmaInit(deviceExtension, LunExt->Lun, LunExt->chan->lChannel,
                          apiomode,
                          min( retry_Wdma[AtaReq->retry],
                               (CHAR)AtaWmode(&(LunExt->IdentifyData)) ),
@@ -672,29 +782,31 @@ limit_pio:
         }
 //            LunExt->DeviceFlags &= ~DFLAGS_FORCE_DOWNRATE;
     } else
-    if(/*!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_FORCE_DOWNRATE) &&*/
+    if(/*!(LunExt->DeviceFlags & DFLAGS_FORCE_DOWNRATE) &&*/
         (LunExt->LimitedTransferMode >
          LunExt->TransferMode) ||
          (LunExt->DeviceFlags & DFLAGS_REINIT_DMA)) {
         // restore IO mode
         KdPrint2((PRINT_PREFIX
-                    "AtapiDmaReinit: restore IO mode on Device %d\n", ldev & 1));
-        AtapiDmaInit__(deviceExtension, ldev);
+                    "AtapiDmaReinit: restore IO mode on Device %d\n", LunExt->Lun));
+        AtapiDmaInit__(deviceExtension, LunExt);
     }
+
+exit:
+    return;
 } // end AtapiDmaReinit()
 
 VOID
 NTAPI
 AtapiDmaInit__(
     IN PHW_DEVICE_EXTENSION deviceExtension,
-    IN ULONG ldev
+    IN PHW_LU_EXTENSION LunExt
     )
 {
-    PHW_LU_EXTENSION LunExt = &(deviceExtension->lun[ldev]);
-
-    if(LunExt->IdentifyData.SupportDma) {
+    if(LunExt->IdentifyData.SupportDma ||
+       (LunExt->IdentifyData.AtapiDMA.DMASupport && (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE))) {
         KdPrint2((PRINT_PREFIX
-                    "AtapiDmaInit__: Set (U)DMA on Device %d\n", ldev & 1));
+                    "AtapiDmaInit__: Set (U)DMA on Device %d\n", LunExt->Lun));
 /*        for(i=AtaUmode(&(LunExt->IdentifyData)); i>=0; i--) {
             AtapiDmaInit(deviceExtension, ldev & 1, ldev >> 1,
                          (CHAR)AtaPioMode(&(LunExt->IdentifyData)),
@@ -707,14 +819,14 @@ AtapiDmaInit__(
                          (CHAR)AtaWmode(&(LunExt->IdentifyData)),
                          UDMA_MODE0+(CHAR)i );
         }*/
-        AtapiDmaInit(deviceExtension, ldev & 1, ldev >> 1,
+        AtapiDmaInit(deviceExtension, LunExt->Lun, LunExt->chan->lChannel,
                      (CHAR)AtaPioMode(&(LunExt->IdentifyData)),
                      (CHAR)AtaWmode(&(LunExt->IdentifyData)),
                      (CHAR)AtaUmode(&(LunExt->IdentifyData)) );
     } else {
         KdPrint2((PRINT_PREFIX
-                    "AtapiDmaInit__: Set PIO on Device %d\n", ldev & 1));
-        AtapiDmaInit(deviceExtension, ldev & 1, ldev >> 1,
+                    "AtapiDmaInit__: Set PIO on Device %d\n", LunExt->Lun));
+        AtapiDmaInit(deviceExtension, LunExt->Lun, LunExt->chan->lChannel,
                      (CHAR)AtaPioMode(&(LunExt->IdentifyData)), -1, -1);
     }
 } // end AtapiDmaInit__()
@@ -734,9 +846,19 @@ AtaSetTransferMode(
     LONG statusByte = 0;
     CHAR apiomode;
 
-    statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel,
-                        IDE_COMMAND_SET_FEATURES, 0, 0, 0,
-                        (UCHAR)((mode > ATA_UDMA6) ? ATA_UDMA6 : mode), ATA_C_F_SETXFER, ATA_WAIT_BASE_READY);
+    if(LunExt->DeviceFlags & DFLAGS_MANUAL_CHS) {
+        statusByte = mode <= ATA_PIO2 ? IDE_STATUS_IDLE : IDE_STATUS_ERROR;
+    } else {
+        if(deviceExtension->HwFlags & UNIATA_AHCI) {
+            AtapiDisableInterrupts(deviceExtension, lChannel);
+        }
+        statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel,
+                            IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+                            (UCHAR)((mode > ATA_UDMA6) ? ATA_UDMA6 : mode), ATA_C_F_SETXFER, ATA_WAIT_BASE_READY);
+        if(deviceExtension->HwFlags & UNIATA_AHCI) {
+            AtapiEnableInterrupts(deviceExtension, lChannel);
+        }
+    }
     if(statusByte & IDE_STATUS_ERROR) {
         KdPrint3((PRINT_PREFIX "  wait ready after error\n"));
         if(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
@@ -757,9 +879,23 @@ AtaSetTransferMode(
         KdPrint3((PRINT_PREFIX "  assume that drive doesn't support mode swithing using PIO%d\n", apiomode));
         mode = ATA_PIO0 + apiomode;
     }
-    //if(mode <= ATA_UDMA6) {
-        LunExt->TransferMode = (UCHAR)mode;
-    //}
+    // SATA sets actual transfer rate in LunExt on init.
+    // There is no run-time SATA rate adjustment yet.
+    // On the other hand, we may turn SATA device in PIO mode
+    LunExt->TransferMode = (UCHAR)mode;
+    if(deviceExtension->HwFlags & UNIATA_SATA) {
+        if(mode < ATA_SA150) { 
+            LunExt->PhyTransferMode = max(LunExt->PhyTransferMode, LunExt->TransferMode);
+        } else {
+            LunExt->PhyTransferMode = LunExt->TransferMode;
+        }
+    } else {
+        if(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
+            LunExt->PhyTransferMode = max(LunExt->LimitedTransferMode, LunExt->TransferMode);
+        } else {
+            LunExt->PhyTransferMode = LunExt->TransferMode;
+        }
+    }
     return TRUE;
 } // end AtaSetTransferMode()
 
@@ -779,12 +915,14 @@ AtapiDmaInit(
     ULONG Channel = deviceExtension->Channel + lChannel;
     PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
     //LONG statusByte = 0;
-    ULONG dev = Channel*2 + DeviceNumber;
-    ULONG ldev = lChannel*2 + DeviceNumber;
+    ULONG dev = Channel*2 + DeviceNumber;       // for non-SATA/AHCI only!
+    //ULONG ldev = lChannel*2 + DeviceNumber;     // for non-SATA/AHCI only!
+    BOOLEAN isAtapi = ATAPI_DEVICE(chan, DeviceNumber);
     ULONG slotNumber = deviceExtension->slotNumber;
     ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
     LONG i;
-    PHW_LU_EXTENSION LunExt = &(deviceExtension->lun[ldev]);
+    PHW_LU_EXTENSION LunExt = chan->lun[DeviceNumber];
+    UCHAR ModeByte;
 
     ULONG VendorID  =  deviceExtension->DevID        & 0xffff;
     //ULONG DeviceID  = (deviceExtension->DevID >> 16) & 0xffff;
@@ -806,19 +944,19 @@ AtapiDmaInit(
     }
 
     // Limit transfer mode (controller limitation)
-    if((LONG)deviceExtension->MaxTransferMode >= ATA_UDMA) {
-        KdPrint2((PRINT_PREFIX "AtapiDmaInit: deviceExtension->MaxTransferMode >= ATA_UDMA\n"));
-        udmamode = min( udmamode, (CHAR)(deviceExtension->MaxTransferMode - ATA_UDMA));
+    if((LONG)chan->MaxTransferMode >= ATA_UDMA) {
+        KdPrint2((PRINT_PREFIX "AtapiDmaInit: chan->MaxTransferMode >= ATA_UDMA\n"));
+        udmamode = min( udmamode, (CHAR)(chan->MaxTransferMode - ATA_UDMA));
     } else
-    if((LONG)deviceExtension->MaxTransferMode >= ATA_WDMA) {
-        KdPrint2((PRINT_PREFIX "AtapiDmaInit: deviceExtension->MaxTransferMode >= ATA_WDMA\n"));
+    if((LONG)chan->MaxTransferMode >= ATA_WDMA) {
+        KdPrint2((PRINT_PREFIX "AtapiDmaInit: chan->MaxTransferMode >= ATA_WDMA\n"));
         udmamode = -1;
-        wdmamode = min( wdmamode, (CHAR)(deviceExtension->MaxTransferMode - ATA_WDMA));
+        wdmamode = min( wdmamode, (CHAR)(chan->MaxTransferMode - ATA_WDMA));
     } else
-    if((LONG)deviceExtension->MaxTransferMode >= ATA_PIO0) {
+    if((LONG)chan->MaxTransferMode >= ATA_PIO0) {
         KdPrint2((PRINT_PREFIX "AtapiDmaInit: NO DMA\n"));
         wdmamode = udmamode = -1;
-        apiomode = min( apiomode, (CHAR)(deviceExtension->MaxTransferMode - ATA_PIO0));
+        apiomode = min( apiomode, (CHAR)(chan->MaxTransferMode - ATA_PIO0));
     } else {
         KdPrint2((PRINT_PREFIX "AtapiDmaInit: PIO0\n"));
         wdmamode = udmamode = -1;
@@ -849,48 +987,51 @@ AtapiDmaInit(
         apiomode = 0;
     }
 
-    SelectDrive(chan, DeviceNumber);
-    GetStatus(chan, statusByte);
-    // we can see here IDE_STATUS_ERROR status after previous operation
-    if(statusByte & IDE_STATUS_ERROR) {
-        KdPrint2((PRINT_PREFIX "IDE_STATUS_ERROR detected on entry, statusByte = %#x\n", statusByte));
-        //GetBaseStatus(chan, statusByte);
-    }
-    if(statusByte && UniataIsIdle(deviceExtension, statusByte & ~IDE_STATUS_ERROR) != IDE_STATUS_IDLE) {
-        KdPrint2((PRINT_PREFIX "Can't setup transfer mode: statusByte = %#x\n", statusByte));
-        return;
-    }
+    //if(!(ChipFlags & UNIATA_AHCI)) {
 
-    if(deviceExtension->UnknownDev) {
-        KdPrint2((PRINT_PREFIX "Unknown chip, omit Vendor/Dev checks\n"));
-        goto try_generic_dma;
-    }
+    // this is necessary for future PM support
+        SelectDrive(chan, DeviceNumber);
+        GetStatus(chan, statusByte);
+        // we can see here IDE_STATUS_ERROR status after previous operation
+        if(statusByte & IDE_STATUS_ERROR) {
+            KdPrint2((PRINT_PREFIX "IDE_STATUS_ERROR detected on entry, statusByte = %#x\n", statusByte));
+            //GetBaseStatus(chan, statusByte);
+        }
+        if(statusByte && UniataIsIdle(deviceExtension, statusByte & ~IDE_STATUS_ERROR) != IDE_STATUS_IDLE) {
+            KdPrint2((PRINT_PREFIX "Can't setup transfer mode: statusByte = %#x\n", statusByte));
+            return;
+        }
+    //}
 
-    if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
-    //if(ChipFlags & UNIATA_SATA) {
+    if(UniataIsSATARangeAvailable(deviceExtension, lChannel) ||
+        (ChipFlags & UNIATA_AHCI) || (chan->MaxTransferMode >= ATA_SA150)
+       ) {
+    //if(ChipFlags & (UNIATA_SATA | UNIATA_AHCI)) {
         /****************/
         /* SATA Generic */
         /****************/
-        UCHAR ModeByte;
 
         KdPrint2((PRINT_PREFIX "SATA Generic\n"));
-        if(udmamode > 5) {
-            if(LunExt->IdentifyData.SataCapabilities != 0x0000 &&
-               LunExt->IdentifyData.SataCapabilities != 0xffff) {
+        if((udmamode >= 5) || (ChipFlags & UNIATA_AHCI) || ((udmamode >= 0) && (chan->MaxTransferMode >= ATA_SA150))) {
+            /* some drives report UDMA6, some UDMA5 */
+            /* ATAPI may not have SataCapabilities set in IDENTIFY DATA */
+            if(ata_is_sata(&(LunExt->IdentifyData))) {
                 //udmamode = min(udmamode, 6);
-                if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_SA150)) {
+                KdPrint2((PRINT_PREFIX "LunExt->LimitedTransferMode %x, LunExt->OrigTransferMode %x\n",
+                    LunExt->LimitedTransferMode, LunExt->OrigTransferMode));
+                if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, min(LunExt->LimitedTransferMode, LunExt->OrigTransferMode))) {
                     return;
                 }
-                udmamode = min(udmamode, 5);
+                udmamode = min(udmamode, 6);
 
             } else {
                 KdPrint2((PRINT_PREFIX "SATA -> PATA adapter ?\n"));
-                if (udmamode > 2 && !LunExt->IdentifyData.HwResCableId) {
+                if (udmamode > 2 && (!LunExt->IdentifyData.HwResCableId && (LunExt->IdentifyData.HwResValid == IDENTIFY_CABLE_ID_VALID) )) {
                     KdPrint2((PRINT_PREFIX "AtapiDmaInit: DMA limited to UDMA33, non-ATA66 compliant cable\n"));
                     udmamode = 2;
                     apiomode = min( apiomode, (CHAR)(LunExt->LimitedTransferMode - ATA_PIO0));
                 } else {
-                    udmamode = min(udmamode, 5);
+                    udmamode = min(udmamode, 6);
                 }
             }
         }
@@ -909,10 +1050,20 @@ AtapiDmaInit(
         AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ModeByte);
         return;
     }
-    if(udmamode > 2 && !LunExt->IdentifyData.HwResCableId) {
-        KdPrint2((PRINT_PREFIX "AtapiDmaInit: DMA limited to UDMA33, non-ATA66 compliant cable\n"));
-        udmamode = 2;
-        apiomode = min( apiomode, (CHAR)(LunExt->LimitedTransferMode - ATA_PIO));
+
+    if(deviceExtension->UnknownDev) {
+        KdPrint2((PRINT_PREFIX "Unknown chip, omit Vendor/Dev checks\n"));
+        goto try_generic_dma;
+    }
+
+    if(udmamode > 2 && (!LunExt->IdentifyData.HwResCableId && (LunExt->IdentifyData.HwResValid == IDENTIFY_CABLE_ID_VALID)) ) {
+        if(ata_is_sata(&(LunExt->IdentifyData))) {
+            KdPrint2((PRINT_PREFIX "AtapiDmaInit: SATA beyond adapter or Controller compat mode\n"));
+        } else {
+            KdPrint2((PRINT_PREFIX "AtapiDmaInit: DMA limited to UDMA33, non-ATA66 compliant cable\n"));
+            udmamode = 2;
+            apiomode = min( apiomode, (CHAR)(LunExt->LimitedTransferMode - ATA_PIO));
+        }
     }
 
     KdPrint2((PRINT_PREFIX "Setup chip a:w:u=%d:%d:%d\n",
@@ -980,8 +1131,8 @@ set_new_acard:
         /* the older Aladdin doesn't support ATAPI DMA on both master & slave */
         if ((ChipFlags & ALIOLD) &&
             (udmamode >= 0 || wdmamode >= 0)) {
-            if(ATAPI_DEVICE(deviceExtension, lChannel*2) &&
-               ATAPI_DEVICE(deviceExtension, lChannel*2 + 1)) {
+            if(ATAPI_DEVICE(chan, 0) &&
+               ATAPI_DEVICE(chan, 1)) {
                 // 2 devices on this channel - NO DMA
                 chan->MaxTransferMode =
                     min(chan->MaxTransferMode, ATA_PIO4);
@@ -1093,18 +1244,18 @@ set_new_acard:
             apiomode = 4;
         for(i=udmamode; i>=0; i--) {
             if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) {
-                AtapiWritePortEx4(chan, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0), mode_reg, cyr_udmatiming[udmamode]);
+                AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0), mode_reg, cyr_udmatiming[udmamode]);
                 return;
             }
         }
         for(i=wdmamode; i>=0; i--) {
             if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) {
-                AtapiWritePortEx4(chan, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0), mode_reg, cyr_wdmatiming[wdmamode]);
+                AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0), mode_reg, cyr_wdmatiming[wdmamode]);
                 return;
             }
         }
         if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode)) {
-            AtapiWritePortEx4(chan, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0), mode_reg, cyr_piotiming[apiomode]);
+            AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0), mode_reg, cyr_piotiming[apiomode]);
             return;
         }
         return;
@@ -1235,6 +1386,7 @@ set_new_acard:
         UCHAR  new44  = 0;
         UCHAR  intel_timings[] = { 0x00, 0x00, 0x10, 0x21, 0x23, 0x10, 0x21, 0x23,
                                   0x23, 0x23, 0x23, 0x23, 0x23, 0x23 };
+        UCHAR  intel_utimings[] = { 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02 };
 
         if(deviceExtension->DevID == ATA_I82371FB) {
             if (wdmamode >= 2 && apiomode >= 4) {
@@ -1317,16 +1469,24 @@ set_new_acard:
         for(i=udmamode; i>=0; i--) {
             if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) {
 
+               /* Set UDMA reference clock (33 MHz or more). */
                 SetPciConfig1(0x48, reg48 | (0x0001 << dev));
                 if(!(ChipFlags & ICH4_FIX)) {
-                    SetPciConfig2(0x4a, (reg4a & ~(0x3 << (dev<<2))) |
-                                        (0x01 + !(i & 0x01))  );
+                    if(deviceExtension->MaxTransferMode == ATA_UDMA3) {
+                        // Special case (undocumented overclock !) for PIIX4e
+                        SetPciConfig2(0x4a, (reg4a | (0x03 << (dev<<2)) ) );
+                    } else {
+                        SetPciConfig2(0x4a, (reg4a & ~(0x03 << (dev<<2))) |
+                                                      (((USHORT)(intel_utimings[i])) << (dev<<2) )  );
+                    }
                 }
-                if(i >= 2) {
+               /* Set UDMA reference clock (66 MHz or more). */
+                if(i > 2) {
                     reg54 |= (0x1 << dev);
                 } else {
                     reg54 &= ~(0x1 << dev);
                 }
+               /* Set UDMA reference clock (133 MHz). */
                 if(i >= 5) {
                     reg54 |= (0x1000 << dev);
                 } else {
@@ -1369,13 +1529,12 @@ set_new_acard:
         GetPciConfig4(0x40, reg40);
         GetPciConfig1(0x44, reg44);
 
+       /* Allow PIO/WDMA timing controls. */
         mask40 = 0x000000ff;
-
+       /* Set PIO/WDMA timings. */
         if(!(DeviceNumber & 1)) {
             mask40 |= 0x00003300;
             new40 = ((USHORT)(intel_timings[idx]) << 8);
-            //mask44 = 0x00; // already done on init
-            //new44  = 0x00;
         } else {
             mask44 = 0x0f;
             new44 = ((intel_timings[idx] & 0x30) >> 2) |
@@ -1400,7 +1559,7 @@ set_new_acard:
         /* Promise */
         /***********/
         if(ChipType < PRTX) {
-            if (ATAPI_DEVICE(deviceExtension, ldev)) {
+            if (isAtapi) {
                 udmamode =
                 wdmamode = -1;
             }
@@ -1566,7 +1725,7 @@ l_ATA_SILICON_IMAGE_ID:
                 { 0xc2, 0x82, 0x042, 0x8a, 0x4a, 0x0a } };
             static const UCHAR cmd_wdma_modes[] = { 0x87, 0x32, 0x3f };
             static const UCHAR cmd_pio_modes[] = { 0xa9, 0x57, 0x44, 0x32, 0x3f };
-            ULONG treg = 0x54 + (dev < 3) ? (dev << 1) : 7;
+            ULONG treg = 0x54 + ((dev < 3) ? (dev << 1) : 7);
 
             udmamode = min(udmamode, 5);
             /* enable UDMA mode */
@@ -1878,12 +2037,12 @@ setup_drive_ite:
             reg40 &= 0xff00;
             reg40 |= 0x4033;
 
-            if(!(ldev & 1)) {
-                reg40 |= (ATAPI_DEVICE(deviceExtension, ldev) ? 0x04 : 0x00);
+            if(!(DeviceNumber & 1)) {
+                reg40 |= (isAtapi ? 0x04 : 0x00);
                 mask40 = 0x3300;
                 new40 = timing << 8;
             } else {
-                reg40 |= (ATAPI_DEVICE(deviceExtension, ldev) ? 0x40 : 0x00);
+                reg40 |= (isAtapi ? 0x40 : 0x00);
                 mask44 = 0x0f;
                 new44 = ((timing & 0x30) >> 2) |
                         (timing & 0x03);
@@ -1905,6 +2064,33 @@ setup_drive_ite:
             AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode);
         }
         return;
+    case ATA_JMICRON_ID: {
+
+        UCHAR reg40;
+        GetPciConfig1(0x40, reg40);
+
+        if(reg40 & 0x08) {
+            // 80-pin check
+            udmamode = min(udmamode, 2);
+        }
+       /* Nothing to do to setup mode, the controller snoop SET_FEATURE cmd. */
+        if(apiomode >= 4)
+            apiomode = 4;
+        for(i=udmamode; i>=0; i--) {
+            if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) {
+                return;
+            }
+        }
+        for(i=wdmamode; i>=0; i--) {
+            if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) {
+                return;
+            }
+        }
+        if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode)) {
+            return;
+        }
+        return;
+        break; }
     }
 
 try_generic_dma:
@@ -1912,7 +2098,7 @@ try_generic_dma:
     /* unknown controller chip */
 
     /* better not try generic DMA on ATAPI devices it almost never works */
-    if (ATAPI_DEVICE(deviceExtension, ldev)) {
+    if (isAtapi) {
         KdPrint2((PRINT_PREFIX "ATAPI on unknown controller -> PIO\n"));
         udmamode =
         wdmamode = -1;
@@ -1921,9 +2107,9 @@ try_generic_dma:
     /* if controller says its setup for DMA take the easy way out */
     /* the downside is we dont know what DMA mode we are in */
     if ((udmamode >= 0 || /*wdmamode > 1*/ wdmamode >= 0) &&
-         /*deviceExtension->BaseIoAddressBM[lChannel]*/ deviceExtension->BusMaster &&
+         /*deviceExtension->BaseIoAddressBM[lChannel]*/ (deviceExtension->BusMaster==DMA_MODE_BM) &&
         (GetDmaStatus(deviceExtension, lChannel) &
-         (!(ldev & 1) ?
+         (!(DeviceNumber & 1) ?
           BM_STATUS_DRIVE_0_DMA : BM_STATUS_DRIVE_1_DMA))) {
 //        LunExt->TransferMode = ATA_DMA;
 //        return;
@@ -1977,8 +2163,8 @@ cyrix_timing(
     case ATA_WDMA2:       reg24 = 0x00002020; break;
     case ATA_UDMA2:       reg24 = 0x00911030; break;
     }
-    AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0),(dev*8) + 0x20, reg20);
-    AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0),(dev*8) + 0x24, reg24);
+    AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),(dev*8) + 0x20, reg20);
+    AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),(dev*8) + 0x24, reg24);
 } // cyrix_timing()
 
 VOID
@@ -2244,4 +2430,3 @@ via82c_timing(
     SetPciConfig1(0x4b-dev, (FIT(active - 1, 0, 0xf) << 4) | FIT(recover - 1, 0, 0xf) );
 } // end via82c_timing()
 
-