[uniata]
[reactos.git] / reactos / drivers / storage / ide / uniata / id_init.cpp
index 526a60d..cb07c29 100644 (file)
@@ -1,6 +1,6 @@
 /*++
 
-Copyright (c) 2004-2010 Alexandr A. Telyatnikov (Alter)
+Copyright (c) 2004-2012 Alexandr A. Telyatnikov (Alter)
 
 Module Name:
     id_init.cpp
@@ -43,6 +43,12 @@ Revision History:
 
 #include "stdafx.h"
 
+static BUSMASTER_CONTROLLER_INFORMATION const AtiSouthAdapters[] = {
+    PCI_DEV_HW_SPEC_BM( 4385, 1002, 0x00, ATA_MODE_NOT_SPEC, "ATI South", 0 ),
+    PCI_DEV_HW_SPEC_BM( ffff, ffff, 0xff, BMLIST_TERMINATOR, NULL      , BMLIST_TERMINATOR )
+    };
+
+
 BOOLEAN
 NTAPI
 UniataChipDetectChannels(
@@ -54,7 +60,7 @@ UniataChipDetectChannels(
 {
     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
     //ULONG slotNumber = deviceExtension->slotNumber;
-    //ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
+    ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
     ULONG VendorID =  deviceExtension->DevID        & 0xffff;
     //ULONG DeviceID = (deviceExtension->DevID >> 16) & 0xffff;
     //ULONG RevID    =  deviceExtension->RevID;
@@ -63,6 +69,21 @@ UniataChipDetectChannels(
 
     KdPrint2((PRINT_PREFIX "UniataChipDetectChannels:\n" ));
 
+    if(ChipFlags & (UNIATA_SATA | UNIATA_AHCI)) {
+        if(!deviceExtension->NumberChannels) {
+            KdPrint2((PRINT_PREFIX "uninitialized SATA/AHCI port number -> 1\n"));
+            deviceExtension->NumberChannels = 1;
+        }
+        if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreAhciPM", 1 /* DEBUG */)) {
+            KdPrint2((PRINT_PREFIX "SATA/AHCI w/o PM, max luns 1 or 2\n"));
+            deviceExtension->NumberLuns = 2; // we may be in Legacy mode
+            //chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
+        } else {
+            KdPrint2((PRINT_PREFIX "SATA/AHCI -> possible PM, max luns %d\n", SATA_MAX_PM_UNITS));
+            deviceExtension->NumberLuns = SATA_MAX_PM_UNITS;
+            //deviceExtension->NumberLuns = 1;
+        }
+    }
     if(deviceExtension->MasterDev) {
         KdPrint2((PRINT_PREFIX "MasterDev -> 1 chan\n"));
         deviceExtension->NumberChannels = 1;
@@ -82,16 +103,26 @@ UniataChipDetectChannels(
         if(ChipType != PRMIO) {
             break;
         }
-        deviceExtension->NumberChannels = 4;
-        KdPrint2((PRINT_PREFIX "Promise 4 chan\n"));
+        if(!(ChipFlags & UNIATA_SATA)) {
+            deviceExtension->NumberChannels = 4;
+            KdPrint2((PRINT_PREFIX "Promise up to 4 chan\n"));
+        } else
+        if(ChipFlags & PRCMBO) {
+            deviceExtension->NumberChannels = 3;
+            KdPrint2((PRINT_PREFIX "Promise 3 chan\n"));
+        } else {
+            deviceExtension->NumberChannels = 4;
+            KdPrint2((PRINT_PREFIX "Promise 4 chan\n"));
+        }
         break;
     case ATA_MARVELL_ID:
         KdPrint2((PRINT_PREFIX "Marvell\n"));
+        /* AHCI part has own DevID-based workaround */
         switch(deviceExtension->DevID) {
         case 0x610111ab: 
             /* 88SX6101 only have 1 PATA channel */
             if(BMList[deviceExtension->DevIndex].channel) {
-                KdPrint2((PRINT_PREFIX "88SX6101 has no 2nd PATA chan\n"));
+                KdPrint2((PRINT_PREFIX "88SX6101/11 has no 2nd PATA chan\n"));
                 return FALSE;
             }
             deviceExtension->NumberChannels = 1;
@@ -102,9 +133,9 @@ UniataChipDetectChannels(
     case ATA_ATI_ID:
         KdPrint2((PRINT_PREFIX "ATI\n"));
         switch(deviceExtension->DevID) {
-        case 0x438c1002: 
-        case 0x439c1002:
-            /* IXP600 & IXP700 only have 1 PATA channel */
+        case ATA_ATI_IXP600:    
+            KdPrint2((PRINT_PREFIX "  IXP600\n"));
+            /* IXP600 only have 1 PATA channel */
             if(BMList[deviceExtension->DevIndex].channel) {
                 KdPrint2((PRINT_PREFIX "New ATI no 2nd PATA chan\n"));
                 return FALSE;
@@ -112,11 +143,60 @@ UniataChipDetectChannels(
             deviceExtension->NumberChannels = 1;
             KdPrint2((PRINT_PREFIX "New ATI PATA 1 chan\n"));
             break;
+
+        case ATA_ATI_IXP700: {
+            UCHAR satacfg = 0;
+            PCI_SLOT_NUMBER slotData;
+            ULONG i, slotNumber;
+                 
+            KdPrint2((PRINT_PREFIX "  IXP700\n"));
+            /*
+             * When "combined mode" is enabled, an additional PATA channel is
+             * emulated with two SATA ports and appears on this device.
+             * This mode can only be detected via SMB controller.
+             */
+            i = AtapiFindListedDev((BUSMASTER_CONTROLLER_INFORMATION*)&AtiSouthAdapters[0], -1, HwDeviceExtension, SystemIoBusNumber, PCISLOTNUM_NOT_SPECIFIED, &slotData);
+            if(i != BMLIST_TERMINATOR) {
+                slotNumber = slotData.u.AsULONG;
+
+                GetPciConfig1(0xad, satacfg);
+                KdPrint(("SATA controller %s (%s%s channel)\n",
+                    (satacfg & 0x01) == 0 ? "disabled" : "enabled",
+                    (satacfg & 0x08) == 0 ? "" : "combined mode, ",
+                    (satacfg & 0x10) == 0 ? "primary" : "secondary"));
+                /*
+                 * If SATA controller is enabled but combined mode is disabled,
+                 * we have only one PATA channel. Ignore a non-existent channel.
+                 */
+                if ((satacfg & 0x09) == 0x01) {
+                    if(BMList[deviceExtension->DevIndex].channel) {
+                        KdPrint2((PRINT_PREFIX "New ATI no 2nd PATA chan\n"));
+                        return FALSE;
+                    }
+                    deviceExtension->NumberChannels = 1;
+                    KdPrint2((PRINT_PREFIX "New ATI PATA 1 chan\n"));
+                    break;
+                } else {
+                    KdPrint2((PRINT_PREFIX "New ATI 2 chan\n"));
+                    deviceExtension->NumberChannels = 2;
+                    /*
+                    if (BMList[deviceExtension->DevIndex].channel != ((satacfg & 0x10) >> 4)) {
+                        ;
+                    }
+                    */
+
+                }
+            }
+
+            break; }
         }
-        break;
+        /* FALLTHROUGH */
     case ATA_SILICON_IMAGE_ID:
 
         if(ChipFlags & SIIBUG) {
+            /* work around errata in early chips */
+            deviceExtension->DmaSegmentLength = 15 * DEV_BSIZE;
+            deviceExtension->DmaSegmentAlignmentMask = 8192-1;
         }
         if(ChipType != SIIMIO) {
             break;
@@ -142,6 +222,12 @@ UniataChipDetectChannels(
             deviceExtension->NumberChannels = 3;
             KdPrint2((PRINT_PREFIX "VIA 3 chan\n"));
         }
+        if(ChipFlags & VIASATA) {
+            /* 2 SATA without SATA registers on first channel + 1 PATA on second */
+            // do nothing, generic PATA INIT
+            KdPrint2((PRINT_PREFIX "VIA SATA without SATA regs -> no PM\n"));
+            deviceExtension->NumberLuns = 1;
+        }
         break;
     case ATA_ITE_ID:
         /* ITE ATA133 controller */
@@ -154,9 +240,11 @@ UniataChipDetectChannels(
             KdPrint2((PRINT_PREFIX "New ITE PATA 1 chan\n"));
         }
         break;
+#if 0
     case ATA_INTEL_ID:
         /* New Intel PATA controllers */
-        if(/*deviceExtension->DevID == 0x27df8086 ||
+        if(g_opt_VirtualMachine != VM_VBOX &&
+           /*deviceExtension->DevID == 0x27df8086 ||
            deviceExtension->DevID == 0x269e8086 ||
            deviceExtension->DevID == ATA_I82801HBM*/
            ChipFlags & I1CH) { 
@@ -168,6 +256,7 @@ UniataChipDetectChannels(
             KdPrint2((PRINT_PREFIX "New Intel PATA 1 chan\n"));
         }
         break;
+#endif // this code is removed from newer FreeBSD
     case ATA_JMICRON_ID:
         /* New JMicron PATA controllers */
         if(deviceExtension->DevID == ATA_JMB361 ||
@@ -214,6 +303,7 @@ UniataChipDetect(
     ULONG BaseIoAddress2;
     ULONG BaseIoAddressBM;
     BOOLEAN MemIo = FALSE;
+    BOOLEAN IsPata = FALSE;
 
     KdPrint2((PRINT_PREFIX "UniataChipDetect:\n" ));
     KdPrint2((PRINT_PREFIX "HwFlags: %#x\n", deviceExtension->HwFlags));
@@ -230,13 +320,26 @@ UniataChipDetect(
     deviceExtension->MaxTransferMode = BaseIoAddressBM ? ATA_DMA : ATA_PIO4;
     ConfigInfo->MaximumTransferLength = DEV_BSIZE*256;
     deviceExtension->MaximumDmaTransferLength = ConfigInfo->MaximumTransferLength;
+    //deviceExtension->NumberOfPhysicalBreaks = min(deviceExtension->MaximumDmaTransferLength/PAGE_SIZE+1, ATA_DMA_ENTRIES);
+    deviceExtension->DmaSegmentLength = 0x10000;
+    deviceExtension->DmaSegmentAlignmentMask = 0xffff;
 
     KdPrint2((PRINT_PREFIX "i: %#x\n", i));
     if(i != BMLIST_TERMINATOR) {
         DevTypeInfo = (PBUSMASTER_CONTROLLER_INFORMATION)&BusMasterAdapters[i];
     } else {
 unknown_dev:
-        KdPrint2((PRINT_PREFIX "  unknown dev, BM addr %#x", BaseIoAddressBM));
+        if(Ata_is_ahci_dev(pciData)) {
+            KdPrint2((PRINT_PREFIX "  AHCI candidate"));
+
+            deviceExtension->NumberChannels = 0;
+            if(!UniataAhciDetect(HwDeviceExtension, pciData, ConfigInfo)) {
+                KdPrint2((PRINT_PREFIX "  AHCI init failed - not detected\n"));
+                return STATUS_UNSUCCESSFUL;
+            }
+            KdPrint2((PRINT_PREFIX "  unknown AHCI dev, addr %#x ", deviceExtension->BaseIoAHCI_0.Addr));
+        }
+        KdPrint2((PRINT_PREFIX "  unknown dev, BM addr %#x ", BaseIoAddressBM));
         DevTypeInfo = NULL;
         KdPrint2((PRINT_PREFIX "  MaxTransferMode %#x\n", deviceExtension->MaxTransferMode));
 
@@ -246,11 +349,15 @@ unknown_dev:
         if(!UniataAllocateLunExt(deviceExtension, UNIATA_ALLOCATE_NEW_LUNS)) {
             return STATUS_UNSUCCESSFUL;
         }
-
-        return STATUS_NOT_FOUND;
+        // DEBUG, we shall return success when AHCI is completly supported
+        //return STATUS_NOT_FOUND;
+        return STATUS_SUCCESS;
     }
 
     static BUSMASTER_CONTROLLER_INFORMATION const SiSAdapters[] = {
+        PCI_DEV_HW_SPEC_BM( 1183, 1039, 0x00, ATA_UDMA6, "SiS 1183" , SIS133NEW),
+        PCI_DEV_HW_SPEC_BM( 1182, 1039, 0x00, ATA_SA150, "SiS 1182" , SISSATA   | UNIATA_SATA),
+        PCI_DEV_HW_SPEC_BM( 0183, 1039, 0x00, ATA_SA150, "SiS 183"  , SISSATA   | UNIATA_SATA),
         PCI_DEV_HW_SPEC_BM( 0182, 1039, 0x00, ATA_SA150, "SiS 182"  , SISSATA   | UNIATA_SATA),
         PCI_DEV_HW_SPEC_BM( 0181, 1039, 0x00, ATA_SA150, "SiS 181"  , SISSATA   | UNIATA_SATA),
         PCI_DEV_HW_SPEC_BM( 0180, 1039, 0x00, ATA_SA150, "SiS 180"  , SISSATA   | UNIATA_SATA),
@@ -313,14 +420,15 @@ unknown_dev:
         PCI_DEV_HW_SPEC_BM( 8324, 1106, 0x00, ATA_SA150, "VIA CX700"  , VIA133 | VIASATA),
         PCI_DEV_HW_SPEC_BM( 8353, 1106, 0x00, ATA_SA150, "VIA VX800"  , VIA133 | VIASATA),
         PCI_DEV_HW_SPEC_BM( 8409, 1106, 0x00, ATA_UDMA6, "VIA VX855"  , VIA133 | 0x00 ),
+        PCI_DEV_HW_SPEC_BM( 8410, 1106, 0x00, ATA_SA300, "VIA VX900"  , VIA133 | VIASATA),
         PCI_DEV_HW_SPEC_BM( ffff, ffff, 0xff, BMLIST_TERMINATOR       , NULL         , BMLIST_TERMINATOR )
         };
 
     static BUSMASTER_CONTROLLER_INFORMATION const ViaSouthAdapters[] = {
-        PCI_DEV_HW_SPEC_BM( 3112, 1106, 0x00, -1, "VIA 8361", VIASOUTH ),
-        PCI_DEV_HW_SPEC_BM( 0305, 1106, 0x00, -1, "VIA 8363", VIASOUTH ),
-        PCI_DEV_HW_SPEC_BM( 0391, 1106, 0x00, -1, "VIA 8371", VIASOUTH ),
-        PCI_DEV_HW_SPEC_BM( 3102, 1106, 0x00, -1, "VIA 8662", VIASOUTH ),
+        PCI_DEV_HW_SPEC_BM( 3112, 1106, 0x00, ATA_MODE_NOT_SPEC, "VIA 8361", VIASOUTH ),
+        PCI_DEV_HW_SPEC_BM( 0305, 1106, 0x00, ATA_MODE_NOT_SPEC, "VIA 8363", VIASOUTH ),
+        PCI_DEV_HW_SPEC_BM( 0391, 1106, 0x00, ATA_MODE_NOT_SPEC, "VIA 8371", VIASOUTH ),
+        PCI_DEV_HW_SPEC_BM( 3102, 1106, 0x00, ATA_MODE_NOT_SPEC, "VIA 8662", VIASOUTH ),
         PCI_DEV_HW_SPEC_BM( ffff, ffff, 0xff, BMLIST_TERMINATOR, NULL      , BMLIST_TERMINATOR )
         };
 
@@ -329,6 +437,10 @@ unknown_dev:
     switch(VendorID) {
 
     case ATA_SIS_ID:
+        /*
+           We shall get here for all SIS controllers, even unlisted.
+           Then perform bus scan to find SIS bridge and decide what to do with controller
+         */
         KdPrint2((PRINT_PREFIX "ATA_SIS_ID\n"));
         DevTypeInfo = (BUSMASTER_CONTROLLER_INFORMATION*)&SiSAdapters[0];
         i = AtapiFindListedDev(DevTypeInfo, -1, HwDeviceExtension, SystemIoBusNumber, PCISLOTNUM_NOT_SPECIFIED, NULL);
@@ -342,7 +454,9 @@ unknown_dev:
         // New chips have own DeviceId
         if(deviceExtension->DevID != ATA_VIA82C571 &&
            deviceExtension->DevID != ATA_VIACX700IDE &&
-           deviceExtension->DevID != ATA_VIASATAIDE) {
+           deviceExtension->DevID != ATA_VIASATAIDE &&
+           deviceExtension->DevID != ATA_VIASATAIDE2 &&
+           deviceExtension->DevID != ATA_VIASATAIDE3) {
             KdPrint2((PRINT_PREFIX "Via new\n"));
             break;
         }
@@ -409,7 +523,7 @@ unknown_dev:
                                        deviceExtension->BaseIoAddressBM_0);
 
             deviceExtension->BaseIoAddressBM_0 = 0;
-            deviceExtension->BusMaster = FALSE;
+            deviceExtension->BusMaster = DMA_MODE_NONE;
             deviceExtension->MaxTransferMode = ATA_PIO4;
             break;
 
@@ -461,6 +575,7 @@ for_ugly_chips:
     if(deviceExtension->MaxTransferMode >= ATA_SA150) {
         deviceExtension->HwFlags |= UNIATA_SATA;
     }
+
 /*
     ConfigInfo->MaximumTransferLength = DEV_BSIZE*256;
     deviceExtension->MaximumDmaTransferLength = ConfigInfo->MaximumTransferLength;
@@ -468,9 +583,36 @@ for_ugly_chips:
     ChipType  = deviceExtension->HwFlags & CHIPTYPE_MASK;
     ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK;
 
+    /* for even more ugly AHCI-capable chips */
+    if(ChipFlags & UNIATA_AHCI) {
+        /* 
+           Seems, some chips may have inoperable/alternative BAR5 in SATA mode
+           This can be detected via PCI SubClass
+         */
+        switch(VendorID) {
+        case ATA_NVIDIA_ID: 
+        case ATA_ATI_ID: 
+            KdPrint2((PRINT_PREFIX "ATA_xxx_ID check AHCI subclass\n"));
+            if((pciData)->SubClass == PCI_DEV_SUBCLASS_IDE) {
+                KdPrint2((PRINT_PREFIX "Non-AHCI mode\n"));
+                ChipFlags &= ~UNIATA_AHCI;
+                deviceExtension->HwFlags &= ~UNIATA_AHCI;
+            }
+            break;
+        }
+    }
+
+    if(ChipFlags & UNIATA_AHCI) {
+        deviceExtension->NumberChannels = 0;
+        if(!UniataAhciDetect(HwDeviceExtension, pciData, ConfigInfo)) {
+            KdPrint2((PRINT_PREFIX "  AHCI detect failed\n"));
+            return STATUS_UNSUCCESSFUL;
+        }
+    } else
     if(!UniataChipDetectChannels(HwDeviceExtension, pciData, DeviceNumber, ConfigInfo)) {
         return STATUS_UNSUCCESSFUL;
     }
+    // UniataAhciDetect() sets proper number of channels
     if(!UniataAllocateLunExt(deviceExtension, UNIATA_ALLOCATE_NEW_LUNS)) {
         return STATUS_UNSUCCESSFUL;
     }
@@ -516,6 +658,9 @@ for_ugly_chips:
             BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber,
                                     5, 0, ((ChipFlags & NV4OFF) ? 0x400 : 0) + 0x40*2);
             KdPrint2((PRINT_PREFIX "BaseMemAddress %x\n", BaseMemAddress));
+            if(!BaseMemAddress) {
+                return STATUS_UNSUCCESSFUL;
+            }
             if((*ConfigInfo->AccessRanges)[5].RangeInMemory) {
                 KdPrint2((PRINT_PREFIX "MemIo\n"));
                 MemIo = TRUE;
@@ -545,26 +690,57 @@ for_ugly_chips:
             break;
         }
         deviceExtension->AltRegMap = TRUE; // inform generic resource allocator
+
+        /* BAR4 -> res1 */
         BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber,
                                 4, 0, 0x4000);
-        KdPrint2((PRINT_PREFIX "BaseMemAddress %x\n", BaseMemAddress));
+        KdPrint2((PRINT_PREFIX "BaseMemAddress[4] %x\n", BaseMemAddress));
+        if(!BaseMemAddress) {
+            return STATUS_UNSUCCESSFUL;
+        }
         if((*ConfigInfo->AccessRanges)[4].RangeInMemory) {
             KdPrint2((PRINT_PREFIX "MemIo\n"));
             MemIo = TRUE;
         }
+        deviceExtension->BaseIoAddressSATA_0.Addr  = BaseMemAddress;
+        deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo;
+
+        /* BAR3 -> res2 */
+        BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber,
+                                3, 0, 0xd0000);
+        KdPrint2((PRINT_PREFIX "BaseMemAddress[3] %x\n", BaseMemAddress));
+        if(!BaseMemAddress) {
+            return STATUS_UNSUCCESSFUL;
+        }
+        if((*ConfigInfo->AccessRanges)[3].RangeInMemory) {
+            KdPrint2((PRINT_PREFIX "MemIo\n"));
+            MemIo = TRUE;
+        }
         deviceExtension->BaseIoAddressBM_0.Addr  = BaseMemAddress;
         deviceExtension->BaseIoAddressBM_0.MemIo = MemIo;
+
+        if(!(ChipFlags & UNIATA_SATA)) {
+            UCHAR reg48;
+
+            reg48 = AtapiReadPortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x48);
+            deviceExtension->NumberChannels = ((reg48 & 0x01) ? 1 : 0) +
+                                              ((reg48 & 0x02) ? 1 : 0) +
+                                              2;
+            KdPrint2((PRINT_PREFIX "Channels -> %d\n", deviceExtension->NumberChannels));
+        }
+
         for(c=0; c<deviceExtension->NumberChannels; c++) {
 
-            ULONG offs12, offs7;
+            /* res2-based */
+            ULONG offs8, offs7;
 
             chan = &deviceExtension->chan[c];
 
-            offs12 = c << 12;
-            offs7  = c << 7;
+            offs8 = c << 8;
+            offs7 = c << 7;
 
             for (i=0; i<=IDX_IO1_SZ; i++) {
-                chan->RegTranslation[IDX_IO1+i].Addr           = BaseMemAddress + 0x200 + (i << 2) + offs12;
+                chan->RegTranslation[IDX_IO1+i].Addr           = BaseMemAddress + 0x200 + (i << 2) + offs7;
                 chan->RegTranslation[IDX_IO1+i].MemIo          = MemIo;
             }
             chan->RegTranslation[IDX_IO2_AltStatus].Addr       = BaseMemAddress + 0x238 + offs7;
@@ -578,11 +754,38 @@ for_ugly_chips:
             chan->RegTranslation[IDX_BM_PRD_Table].MemIo       = MemIo;
             chan->RegTranslation[IDX_BM_DeviceSpecific0].Addr  = BaseMemAddress + (c << 2);
             chan->RegTranslation[IDX_BM_DeviceSpecific0].MemIo = MemIo;
+
+            if((ChipFlags & PRSATA) ||
+               ((ChipFlags & PRCMBO) && c<2)) {
+                KdPrint2((PRINT_PREFIX "Promise SATA\n"));
+
+                chan->RegTranslation[IDX_SATA_SStatus].Addr        = BaseMemAddress + 0x400 + offs7;
+                chan->RegTranslation[IDX_SATA_SStatus].MemIo       = MemIo;
+                chan->RegTranslation[IDX_SATA_SError].Addr         = BaseMemAddress + 0x404 + offs7;
+                chan->RegTranslation[IDX_SATA_SError].MemIo        = MemIo;
+                chan->RegTranslation[IDX_SATA_SControl].Addr       = BaseMemAddress + 0x408 + offs7;
+                chan->RegTranslation[IDX_SATA_SControl].MemIo      = MemIo;
+
+                chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
+            } else {
+                KdPrint2((PRINT_PREFIX "Promise PATA\n"));
+                chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA6);
+            }
         }
         break;
 
     case ATA_ATI_ID:
         KdPrint2((PRINT_PREFIX "ATI\n"));
+        if(ChipType == ATI700) {
+            KdPrint2((PRINT_PREFIX "ATI700\n"));
+            if(!(ChipFlags & UNIATA_AHCI)) {
+                KdPrint2((PRINT_PREFIX "IXP700 PATA\n"));
+                chan = &deviceExtension->chan[0];
+                chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA5);
+            }
+            break;
+        }
+        /* FALLTHROUGH */
     case ATA_SILICON_IMAGE_ID: {
 
         if(ChipFlags & SIIBUG) {
@@ -605,6 +808,9 @@ for_ugly_chips:
         BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber,
                                 5, 0, 0x800);
         KdPrint2((PRINT_PREFIX "BaseMemAddress %x\n", BaseMemAddress));
+        if(!BaseMemAddress) {
+            return STATUS_UNSUCCESSFUL;
+        }
         if((*ConfigInfo->AccessRanges)[5].RangeInMemory) {
             KdPrint2((PRINT_PREFIX "MemIo\n"));
             MemIo = TRUE;
@@ -641,6 +847,10 @@ for_ugly_chips:
                 chan->RegTranslation[IDX_BM_DeviceSpecific1].MemIo = MemIo;
             }
 
+            if(chan->MaxTransferMode < ATA_SA150) {
+                // do nothing for PATA part
+                KdPrint2((PRINT_PREFIX "No SATA regs for PATA part\n"));
+            } else
             if(ChipFlags & UNIATA_SATA) {
                 chan->RegTranslation[IDX_SATA_SStatus].Addr        = BaseMemAddress + 0x104 + (unit01 << 7) + (unit10 << 8);
                 chan->RegTranslation[IDX_SATA_SStatus].MemIo       = MemIo;
@@ -669,6 +879,9 @@ for_ugly_chips:
         BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber,
                                 5, 0, 0x400);
         KdPrint2((PRINT_PREFIX "BaseMemAddress %x\n", BaseMemAddress));
+        if(!BaseMemAddress) {
+            return STATUS_UNSUCCESSFUL;
+        }
         if((*ConfigInfo->AccessRanges)[5].RangeInMemory) {
             KdPrint2((PRINT_PREFIX "MemIo\n"));
             MemIo = TRUE;
@@ -707,7 +920,7 @@ for_ugly_chips:
         break; }
 
     case ATA_SIS_ID: {
-        //if(ChipType != SIS_SOUTH) {
+        //if(ChipType != SIS_SOUTH) {}
         BOOLEAN SIS_182=FALSE;
 
         if(!(ChipFlags & SIS_BASE)) {
@@ -729,9 +942,9 @@ for_ugly_chips:
             ChangePciConfig1(0x57, (a | 0x80));
         } else {
             static BUSMASTER_CONTROLLER_INFORMATION const SiSSouthAdapters[] = {
-                PCI_DEV_HW_SPEC_BM( 0008, 1039, 0x10, -1, "SiS 961", 0 ),
-//                PCI_DEV_HW_SPEC_BM( 0008, 1039, 0x00, -1, "SiS 961", 0 ),
-                PCI_DEV_HW_SPEC_BM( ffff, ffff, 0xff, -1, NULL     , -1 )
+                PCI_DEV_HW_SPEC_BM( 0008, 1039, 0x10, ATA_MODE_NOT_SPEC, "SiS 961", 0 ),
+//                PCI_DEV_HW_SPEC_BM( 0008, 1039, 0x00, ATA_MODE_NOT_SPEC, "SiS 961", 0 ),
+                PCI_DEV_HW_SPEC_BM( ffff, ffff, 0xff, ATA_MODE_NOT_SPEC, NULL     , -1 )
                 };
             // Save settings
             GetPciConfig1(0x4a, tmp8);
@@ -742,11 +955,12 @@ for_ugly_chips:
                      -1, HwDeviceExtension, SystemIoBusNumber, PCISLOTNUM_NOT_SPECIFIED, NULL); 
                 if(i != BMLIST_TERMINATOR) {
                     deviceExtension->HwFlags = (deviceExtension->HwFlags & ~CHIPTYPE_MASK) | SIS133OLD;
-                    //deviceExtension->MaxTransferMode = ATA_UDMA6;
-                    deviceExtension->MaxTransferMode = SiSSouthAdapters[i].MaxTransferMode;
+                    deviceExtension->MaxTransferMode = ATA_UDMA6;
+                    //deviceExtension->MaxTransferMode = SiSSouthAdapters[i].MaxTransferMode;
                     if(SiSSouthAdapters[i].RaidFlags & UNIATA_SATA) {
                         deviceExtension->HwFlags |= UNIATA_SATA;
-                        if(SiSSouthAdapters[i].nDeviceId == 0x1182) {
+                        if(SiSSouthAdapters[i].nDeviceId == 0x1182 ||
+                           SiSSouthAdapters[i].nDeviceId == 0x1183) {
                             SIS_182 = TRUE;
                         }
                     }
@@ -771,25 +985,27 @@ for_ugly_chips:
                 BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber,
                                         5, 0, 0x400);
                 KdPrint2((PRINT_PREFIX "BaseMemAddress %x\n", BaseMemAddress));
-                if((*ConfigInfo->AccessRanges)[5].RangeInMemory) {
-                    KdPrint2((PRINT_PREFIX "MemIo\n"));
-                    MemIo = TRUE;
-                }
-                deviceExtension->BaseIoAddressSATA_0.Addr  = BaseMemAddress;
-                deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo;
+                if(BaseMemAddress) {
+                    if((*ConfigInfo->AccessRanges)[5].RangeInMemory) {
+                        KdPrint2((PRINT_PREFIX "MemIo\n"));
+                        MemIo = TRUE;
+                    }
+                    deviceExtension->BaseIoAddressSATA_0.Addr  = BaseMemAddress;
+                    deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo;
 
-                for(c=0; c<deviceExtension->NumberChannels; c++) {
-                    ULONG offs = c << (SIS_182 ? 5 : 6);
+                    for(c=0; c<deviceExtension->NumberChannels; c++) {
+                        ULONG offs = c << (SIS_182 ? 5 : 6);
 
-                    chan = &deviceExtension->chan[c];
-                    chan->RegTranslation[IDX_SATA_SStatus].Addr        = BaseMemAddress + 0 + offs;
-                    chan->RegTranslation[IDX_SATA_SStatus].MemIo       = MemIo;
-                    chan->RegTranslation[IDX_SATA_SError].Addr         = BaseMemAddress + 4 + offs;
-                    chan->RegTranslation[IDX_SATA_SError].MemIo        = MemIo;
-                    chan->RegTranslation[IDX_SATA_SControl].Addr       = BaseMemAddress + 8 + offs;
-                    chan->RegTranslation[IDX_SATA_SControl].MemIo      = MemIo;
+                        chan = &deviceExtension->chan[c];
+                        chan->RegTranslation[IDX_SATA_SStatus].Addr        = BaseMemAddress + 0 + offs;
+                        chan->RegTranslation[IDX_SATA_SStatus].MemIo       = MemIo;
+                        chan->RegTranslation[IDX_SATA_SError].Addr         = BaseMemAddress + 4 + offs;
+                        chan->RegTranslation[IDX_SATA_SError].MemIo        = MemIo;
+                        chan->RegTranslation[IDX_SATA_SControl].Addr       = BaseMemAddress + 8 + offs;
+                        chan->RegTranslation[IDX_SATA_SControl].MemIo      = MemIo;
 
-                    chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
+                        chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
+                    }
                 }
             }
         }
@@ -885,7 +1101,6 @@ for_ugly_chips:
         break; }
     case ATA_INTEL_ID: {
 
-        BOOLEAN IsPata;
         if(!(ChipFlags & UNIATA_SATA)) {
             break;
         }
@@ -897,6 +1112,9 @@ for_ugly_chips:
             KdPrint2((PRINT_PREFIX "UniataChipDetect: Intel 31244, DPA mode\n"));
             BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber,
                                     0, 0, 0x0c00);
+            if(!BaseMemAddress) {
+                return STATUS_UNSUCCESSFUL;
+            }
             if((*ConfigInfo->AccessRanges)[0].RangeInMemory) {
                 KdPrint2((PRINT_PREFIX "MemIo\n"));
                 MemIo = TRUE;
@@ -953,6 +1171,7 @@ for_ugly_chips:
         }
         if(deviceExtension->MaxTransferMode >= ATA_SA150) {
             GetPciConfig1(0x90, tmp8);
+            KdPrint2((PRINT_PREFIX "Intel chip config: %x\n", tmp8));
             /* SATA parts can be either compat or AHCI */
             if(ChipFlags & UNIATA_AHCI) {
 
@@ -967,11 +1186,18 @@ for_ugly_chips:
             deviceExtension->HwFlags &= ~UNIATA_AHCI;
 
             /* if BAR(5) is IO it should point to SATA interface registers */
-            BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber,
+            if(deviceExtension->DevID == 0x28288086 &&
+                pciData->u.type0.SubVendorID == 0x106b) {
+                /* Skip BAR(5) on ICH8M Apples, system locks up on access. */
+                KdPrint2((PRINT_PREFIX "Ignore BAR5 on ICH8M Apples\n"));
+                BaseMemAddress = 0;
+            } else {
+                BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber,
                                     5, 0, 0x10);
-            if(BaseMemAddress && (*ConfigInfo->AccessRanges)[5].RangeInMemory) {
-                KdPrint2((PRINT_PREFIX "MemIo\n"));
-                MemIo = TRUE;
+                if(BaseMemAddress && (*ConfigInfo->AccessRanges)[5].RangeInMemory) {
+                    KdPrint2((PRINT_PREFIX "MemIo\n"));
+                    MemIo = TRUE;
+                }
             }
             deviceExtension->BaseIoAddressSATA_0.Addr  = BaseMemAddress;
             deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo;
@@ -980,62 +1206,35 @@ for_ugly_chips:
                 chan = &deviceExtension->chan[c];
                 IsPata = FALSE;
                 if(ChipFlags & ICH5) {
+                    KdPrint2((PRINT_PREFIX "ICH5\n"));
                     if ((tmp8 & 0x04) == 0) {
-                        //ch->flags |= ATA_SATA;
-                        //ch->flags |= ATA_NO_SLAVE;
-                        //smap[0] = (map & 0x01) ^ ch->unit;
-                        //smap[1] = 0;
                         chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
-                        chan->lun[0]->SATA_lun_map = (tmp8 & 0x01) ^ c;
-                        chan->lun[1]->SATA_lun_map = 0;
                     } else if ((tmp8 & 0x02) == 0) {
-                               //ch->flags |= ATA_SATA;
-                               //smap[0] = (map & 0x01) ? 1 : 0;
-                               //smap[1] = (map & 0x01) ? 0 : 1;
-                        if(c == 0) {
-                            chan->lun[0]->SATA_lun_map = (tmp8 & 0x01) ? 1 : 0;
-                            chan->lun[1]->SATA_lun_map = (tmp8 & 0x01) ? 0 : 1;
-                        } else {
+                        if(c != 0) {
                             IsPata = TRUE;
                             //chan->ChannelCtrlFlags |= CTRFLAGS_PATA;
                         }
                     } else if ((tmp8 & 0x02) != 0) {
-                               //ch->flags |= ATA_SATA;
-                               //smap[0] = (map & 0x01) ? 1 : 0;
-                               //smap[1] = (map & 0x01) ? 0 : 1;
-                        if(c == 1) {
-                            chan->lun[0]->SATA_lun_map = (tmp8 & 0x01) ? 1 : 0;
-                            chan->lun[1]->SATA_lun_map = (tmp8 & 0x01) ? 0 : 1;
-                        } else {
+                        if(c != 1) {
                             IsPata = TRUE;
                             //chan->ChannelCtrlFlags |= CTRFLAGS_PATA;
                         }
                     }
                 } else
                 if(ChipFlags & I6CH2) {
+                    KdPrint2((PRINT_PREFIX "I6CH2\n"));
                     chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
-                    chan->lun[0]->SATA_lun_map = c ? 4 : 5;
-                    chan->lun[1]->SATA_lun_map = 0;
                 } else {
+                    KdPrint2((PRINT_PREFIX "other Intel\n"));
                     switch(tmp8 & 0x03) {
-                    case 0:
-                        chan->lun[0]->SATA_lun_map = 0+c;
-                        chan->lun[1]->SATA_lun_map = 2+c;
-                        break;
                     case 2:
-                        if(c==0) {
-                            chan->lun[0]->SATA_lun_map = 0;
-                            chan->lun[1]->SATA_lun_map = 2;
-                        } else {
+                        if(c!=0) {
                             // PATA
                             IsPata = TRUE;
                         }
                         break;
                     case 1:
-                        if(c==1) {
-                            chan->lun[0]->SATA_lun_map = 1;
-                            chan->lun[1]->SATA_lun_map = 3;
-                        } else {
+                        if(c!=1) {
                             // PATA
                             IsPata = TRUE;
                         }
@@ -1045,9 +1244,11 @@ for_ugly_chips:
 
                 if(IsPata) {
                     chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA5);
+                    KdPrint2((PRINT_PREFIX "PATA part\n"));
                 } else {
 
-                    if((ChipFlags & ICH5) && BaseMemAddress) {
+                    if(!(ChipFlags & ICH7) && BaseMemAddress) {
+                        KdPrint2((PRINT_PREFIX "BaseMemAddress[5] -> indexed\n"));
                         chan->RegTranslation[IDX_INDEXED_ADDR].Addr        = BaseMemAddress + 0;
                         chan->RegTranslation[IDX_INDEXED_ADDR].MemIo       = MemIo;
                         chan->RegTranslation[IDX_INDEXED_DATA].Addr        = BaseMemAddress + 4;
@@ -1055,16 +1256,20 @@ for_ugly_chips:
                     }
                     if((ChipFlags & ICH5) || BaseMemAddress) {
 
+                        KdPrint2((PRINT_PREFIX "io proc()\n"));
                         // Rather interesting way of register access...
                         ChipType = INTEL_IDX;
                         deviceExtension->HwFlags &= ~CHIPTYPE_MASK;
                         deviceExtension->HwFlags |= ChipType;
 
-                        chan->RegTranslation[IDX_SATA_SStatus].Addr        = 0x200*c + 0;
+                        if(ChipFlags & ICH7) {
+                            KdPrint2((PRINT_PREFIX "ICH7 way\n"));
+                        }
+                        chan->RegTranslation[IDX_SATA_SStatus].Addr        = 0x200*c + 0; // this is fake non-zero value
                         chan->RegTranslation[IDX_SATA_SStatus].Proc        = 1;
-                        chan->RegTranslation[IDX_SATA_SError].Addr         = 0x200*c + 2;
+                        chan->RegTranslation[IDX_SATA_SError].Addr         = 0x200*c + 2; // this is fake non-zero value
                         chan->RegTranslation[IDX_SATA_SError].Proc         = 1;
-                        chan->RegTranslation[IDX_SATA_SControl].Addr       = 0x200*c + 1;
+                        chan->RegTranslation[IDX_SATA_SControl].Addr       = 0x200*c + 1; // this is fake non-zero value
                         chan->RegTranslation[IDX_SATA_SControl].Proc       = 1;
                     }
                 }
@@ -1082,10 +1287,25 @@ for_ugly_chips:
             deviceExtension->MaximumDmaTransferLength = 63*1024;
         }
         break;
-    }
-
-    if(ChipFlags & UNIATA_AHCI) {
-        return UniataAhciInit(HwDeviceExtension) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
+    case ATA_JMICRON_ID:
+        /* New JMicron PATA controllers */
+        GetPciConfig1(0xdf, tmp8);
+        if(tmp8 & 0x40) {
+            KdPrint(("  Check JMicron AHCI\n"));
+            if(Ata_is_ahci_dev(pciData)) {
+                ChipFlags |= UNIATA_AHCI;
+                deviceExtension->HwFlags |= UNIATA_AHCI;
+            } else {
+                KdPrint(("  JMicron PATA\n"));
+            }
+        } else {
+            /* set controller configuration to a combined setup we support */
+            SetPciConfig4(0x40, 0x80c0a131);
+            SetPciConfig4(0x80, 0x01200000);
+            //KdPrint(("  JMicron Combined (not supported yet)\n"));
+            //return STATUS_NOT_FOUND;
+        }
+        break;
     }
 
     return STATUS_SUCCESS;
@@ -1297,10 +1517,11 @@ hpt_cable80(
     GetPciConfig1(0x5a, res);
     res = res & (channel ? 0x01 : 0x02);
     SetPciConfig1(reg, val);
+    KdPrint2((PRINT_PREFIX "hpt_cable80(%d) = %d\n", channel, !res));
     return !res;
 } // end hpt_cable80()
 
-
+/*
 ULONG
 NTAPI
 via_cable80(
@@ -1345,9 +1566,11 @@ via_cable80(
             res |= TRUE; //(1 << (1 - (i >> 4)));
         }
     }
+    KdPrint2((PRINT_PREFIX "via_cable80(%d) = %d\n", channel, res));
     return res;
 
 } // end via_cable80()
+*/
 
 BOOLEAN
 NTAPI
@@ -1362,6 +1585,11 @@ generic_cable80(
     ULONG slotNumber = deviceExtension->slotNumber;
     ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
 
+    if(deviceExtension->MaxTransferMode <= ATA_UDMA2) {
+        KdPrint2((PRINT_PREFIX "generic_cable80(%d, %#x, %d) <= UDMA2\n", channel, pci_reg, bit_offs));
+        return FALSE;
+    }
+
     //ULONG ChipType  = deviceExtension->HwFlags & CHIPTYPE_MASK;
     PHW_CHANNEL chan;
     ULONG  c; // logical channel (for Compatible Mode controllers)
@@ -1373,9 +1601,11 @@ generic_cable80(
     GetPciConfig1(pci_reg, tmp8);
     if(!(tmp8 & (1 << (channel << bit_offs)))) {
         chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2);
+        KdPrint2((PRINT_PREFIX "generic_cable80(%d, %#x, %d) = 0\n", channel, pci_reg, bit_offs));
         return FALSE;
     }
 
+    KdPrint2((PRINT_PREFIX "generic_cable80(%d, %#x, %d) = 1\n", channel, pci_reg, bit_offs));
     return TRUE;
 } // end generic_cable80()
 
@@ -1384,7 +1614,7 @@ NTAPI
 UniAtaReadLunConfig(
     IN PHW_DEVICE_EXTENSION deviceExtension,
     IN ULONG channel,  // physical channel
-    IN ULONG ldev
+    IN ULONG DeviceNumber
     )
 {
     ULONG tmp32;
@@ -1395,37 +1625,86 @@ UniAtaReadLunConfig(
     c = channel - deviceExtension->Channel; // logical channel
 
     chan = &deviceExtension->chan[c];
-    ldev &= 0x01;
-    LunExt = &(deviceExtension->lun[c*2+ldev]);
+    DeviceNumber = (DeviceNumber % deviceExtension->NumberLuns);
+    LunExt = chan->lun[DeviceNumber];
 
-    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, ldev, L"ReadCacheEnable", 1);
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"ReadCacheEnable", 1);
     LunExt->opt_ReadCacheEnable = tmp32 ? TRUE : FALSE;
 
-    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, ldev, L"WriteCacheEnable", 1);
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"WriteCacheEnable", 1);
     LunExt->opt_WriteCacheEnable = tmp32 ? TRUE : FALSE;
 
-    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, ldev, L"MaxTransferMode", chan->MaxTransferMode);
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"MaxTransferMode", chan->MaxTransferMode);
     LunExt->opt_MaxTransferMode = tmp32;
 
-    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, ldev, L"PreferedTransferMode", 0xffffffff);
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"PreferedTransferMode", 0xffffffff);
     LunExt->opt_PreferedTransferMode = tmp32;
 
-    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, ldev, L"ReadOnly", 0);
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"AdvancedPowerMode", ATA_C_F_APM_CNT_MIN_NO_STANDBY);
+    if(tmp32 > 0xfe) {
+        tmp32 = 0xfe; // max. performance
+    }
+    LunExt->opt_AdvPowerMode = (UCHAR)tmp32;
+
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"AcousticMgmt", ATA_C_F_AAM_CNT_MAX_POWER_SAVE);
+    if(tmp32 > 0xfe) {
+        tmp32 = 0xfe; // max. performance
+    } else
+    if(tmp32 < 0x80) {
+        tmp32 = 0x0; // disable feature
+    }
+    LunExt->opt_AcousticMode = (UCHAR)tmp32;
+
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"StandbyTimer", 0);
+    if(tmp32 == 0xfe) {
+        tmp32 = 0xff;
+    }
+    LunExt->opt_StandbyTimer = (UCHAR)tmp32;
+
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"ReadOnly", 0);
     if(tmp32 <= 2) {
         LunExt->opt_ReadOnly = (UCHAR)tmp32;
     }
 
-    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, ldev, L"GeomType", 0xffffffff);
-    if(tmp32 > 2) {
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"GeomType", 0xffffffff);
+    if(tmp32 > GEOM_MANUAL) {
         tmp32 = 0xffffffff;
     }
     LunExt->opt_GeomType = tmp32;
+    if(tmp32 == GEOM_MANUAL) {
+        LunExt->DeviceFlags |= DFLAGS_MANUAL_CHS;
+        LunExt->opt_GeomType = GEOM_ORIG;
+        // assume IdentifyData is already zero-filled
+        tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"C", 0);
+        LunExt->IdentifyData.NumberOfCurrentCylinders =
+        LunExt->IdentifyData.NumberOfCylinders = (USHORT)tmp32;
+        tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"H", 0);
+        LunExt->IdentifyData.NumberOfCurrentHeads = 
+        LunExt->IdentifyData.NumberOfHeads = (USHORT)tmp32;
+        tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"S", 0);
+        LunExt->IdentifyData.CurrentSectorsPerTrack =
+        LunExt->IdentifyData.SectorsPerTrack = (USHORT)tmp32;
+        memcpy(LunExt->IdentifyData.ModelNumber, "SEIDH DD", 8); // ESDI HDD
+        memcpy(LunExt->IdentifyData.SerialNumber, ".10", 4);
+        memcpy(LunExt->IdentifyData.FirmwareRevision, ".10", 4);
+        if(!LunExt->IdentifyData.SectorsPerTrack ||
+           !LunExt->IdentifyData.NumberOfCylinders ||
+           !LunExt->IdentifyData.NumberOfHeads) {
+            // ERROR
+            KdPrint2((PRINT_PREFIX "Wrong CHS\n"));
+            LunExt->opt_GeomType = GEOM_AUTO;
+        } else {
+            LunExt->DeviceFlags |= DFLAGS_MANUAL_CHS;
+            LunExt->opt_GeomType = GEOM_ORIG;
+        }
+    }
 
-    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, ldev, L"Hidden", 0);
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"Hidden", 0);
     if(tmp32) {
         LunExt->DeviceFlags |= DFLAGS_HIDDEN;
     }
 
+
     return;
 } // end UniAtaReadLunConfig()
 
@@ -1441,6 +1720,7 @@ AtapiReadChipConfig(
     PHW_CHANNEL chan;
     ULONG  tmp32;
     ULONG  c; // logical channel (for Compatible Mode controllers)
+    ULONG  i;
 
     KdPrint2((PRINT_PREFIX "AtapiReadChipConfig: devExt %#x\n", deviceExtension ));
     ASSERT(deviceExtension);
@@ -1459,7 +1739,7 @@ AtapiReadChipConfig(
         }
         deviceExtension->opt_AtapiDmaZeroTransfer = FALSE;
         deviceExtension->opt_AtapiDmaControlCmd   = FALSE;
-        deviceExtension->opt_AtapiDmaRawRead      = FALSE;//TRUE; // Disabling that for VirtualBox
+        deviceExtension->opt_AtapiDmaRawRead      = g_opt_AtapiDmaRawRead; 
         deviceExtension->opt_AtapiDmaReadWrite    = TRUE;
     }
 
@@ -1504,8 +1784,9 @@ AtapiReadChipConfig(
         tmp32 = AtapiRegCheckDevValue(deviceExtension, c, DEVNUM_NOT_SPECIFIED, L"ReorderEnable", TRUE);
         chan->UseReorder = tmp32 ? TRUE : FALSE;
 
-        UniAtaReadLunConfig(deviceExtension, channel, 0);
-        UniAtaReadLunConfig(deviceExtension, channel, 1);
+        for(i=0; i<deviceExtension->NumberLuns; i++) {
+            UniAtaReadLunConfig(deviceExtension, channel, i);
+        }
     }
 
     return TRUE;
@@ -1516,16 +1797,14 @@ NTAPI
 AtapiChipInit(
     IN PVOID HwDeviceExtension,
     IN ULONG DeviceNumber,
-    IN ULONG channel // physical channel
+    IN ULONG channel // logical channel
     )
 {
     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
     ULONG slotNumber = deviceExtension->slotNumber;
     ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
     ULONG VendorID =  deviceExtension->DevID        & 0xffff;
-#ifdef _DEBUG
     ULONG DeviceID = (deviceExtension->DevID >> 16) & 0xffff;
-#endif
     ULONG RevID    =  deviceExtension->RevID;
 //    ULONG i;
 //    BUSMASTER_CONTROLLER_INFORMATION* DevTypeInfo;
@@ -1534,9 +1813,10 @@ AtapiChipInit(
     PHW_CHANNEL chan;
     UCHAR  tmp8;
     USHORT tmp16;
-    ULONG  tmp32;
+    //ULONG  tmp32;
     ULONG  c; // logical channel (for Compatible Mode controllers)
     BOOLEAN CheckCable = FALSE;
+    BOOLEAN GlobalInit = FALSE;
     //ULONG BaseIoAddress;
 
     switch(channel) {
@@ -1545,22 +1825,66 @@ AtapiChipInit(
         /* FALLTHROUGH */
     case CHAN_NOT_SPECIFIED:
         c = CHAN_NOT_SPECIFIED;
+        GlobalInit = TRUE;
         break;
     default:
-        c = channel - deviceExtension->Channel; // logical channel (for Compatible Mode controllers)
+        //c = channel - deviceExtension->Channel; // logical channel (for Compatible Mode controllers)
+        c = channel;
+        channel += deviceExtension->Channel;
     }
 
-    KdPrint2((PRINT_PREFIX "AtapiChipInit: dev %#x, ph chan %d\n", DeviceNumber, channel ));
+    KdPrint2((PRINT_PREFIX "AtapiChipInit: dev %#x, ph chan %d, c %d\n", DeviceNumber, channel, c));
 
     KdPrint2((PRINT_PREFIX "HwFlags: %#x\n", deviceExtension->HwFlags));
     KdPrint2((PRINT_PREFIX "VendorID/DeviceID/Rev %#x/%#x/%#x\n", VendorID, DeviceID, RevID));
 
     if(deviceExtension->UnknownDev) {
-        KdPrint2((PRINT_PREFIX "  Unknown chip, exiting\n" ));
+        KdPrint2((PRINT_PREFIX "  Unknown chip\n" ));
         //return TRUE;
         VendorID = 0xffffffff;
     }
 
+
+    if(ChipFlags & UNIATA_AHCI) {
+        /* if BAR(5) is IO it should point to SATA interface registers */
+        if(!deviceExtension->BaseIoAHCI_0.Addr) {
+            KdPrint2((PRINT_PREFIX "  !BaseIoAHCI_0, exiting\n" ));
+            return FALSE;
+        }
+        if(c == CHAN_NOT_SPECIFIED) {
+            return UniataAhciInit(HwDeviceExtension);
+        } else
+        if(c<deviceExtension->NumberChannels) {
+            KdPrint2((PRINT_PREFIX "  AHCI single channel init\n" ));
+            UniataAhciReset(HwDeviceExtension, c);
+            return TRUE;
+        } else {
+            KdPrint2((PRINT_PREFIX "  AHCI non-existent channel\n" ));
+            return FALSE;
+        }
+    }
+
+    if((WinVer_Id() > WinVer_NT) &&
+       GlobalInit &&
+       deviceExtension->MasterDev) {
+        PCI_COMMON_CONFIG pciData;
+        ULONG busDataRead;
+
+        KdPrint2((PRINT_PREFIX "  re-enable IO resources of MasterDev\n" ));
+
+        busDataRead = HalGetBusData
+                      //ScsiPortGetBusData
+                                   (
+                                    //HwDeviceExtension,
+                                    PCIConfiguration, SystemIoBusNumber, slotNumber,
+                                    &pciData, PCI_COMMON_HDR_LENGTH);
+        if(busDataRead == PCI_COMMON_HDR_LENGTH) {
+            UniataEnableIoPCI(SystemIoBusNumber, slotNumber, &pciData);
+        } else {
+            KdPrint2((PRINT_PREFIX "  re-enable IO resources of MasterDev FAILED\n" ));
+        }
+    }
+
     switch(VendorID) {
 //  case ATA_ACARD_ID:
 //      break;
@@ -1656,31 +1980,123 @@ AtapiChipInit(
         }
         break;
     case ATA_INTEL_ID: {
+        BOOLEAN IsPata;
         USHORT reg54;
+        UCHAR tmp8;
         if(ChipFlags & UNIATA_SATA) {
 
-            if(ChipFlags & UNIATA_AHCI)
+            KdPrint2((PRINT_PREFIX "Intel SATA\n"));
+            if(ChipFlags & UNIATA_AHCI) {
+                KdPrint2((PRINT_PREFIX "Do nothing for AHCI\n"));
                 break;
+            }
             if(c == CHAN_NOT_SPECIFIED) {
+                KdPrint2((PRINT_PREFIX "Base init\n"));
                 /* force all ports active "the legacy way" */
                 ChangePciConfig2(0x92, (a | 0x0f));
+
+                if(deviceExtension->BaseIoAddressSATA_0.Addr && (ChipFlags & ICH7)) {
+                    /* Set SCRAE bit to enable registers access. */
+                    ChangePciConfig4(0x94, (a | (1 << 9)));
+                    /* Set Ports Implemented register bits. */
+                    AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x0c,
+                         AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x0c) | 0x0f);
+                }
                 /* enable PCI interrupt */
-                ChangePciConfig2(/*PCIR_COMMAND*/0x04, (a & ~0x0400));
+                ChangePciConfig2(offsetof(PCI_COMMON_CONFIG, Command), (a & ~0x0400));
+
             } else {
+
+                KdPrint2((PRINT_PREFIX "channel init\n"));
+
+                GetPciConfig1(0x90, tmp8);
+                KdPrint2((PRINT_PREFIX "reg 90: %x, init lun map\n", tmp8));
+
+                KdPrint2((PRINT_PREFIX "chan %d\n", c));
+                chan = &deviceExtension->chan[c];
+                IsPata = FALSE;
+                if(ChipFlags & ICH5) {
+                    KdPrint2((PRINT_PREFIX "ICH5\n"));
+                    if ((tmp8 & 0x04) == 0) {
+                        chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
+                        chan->lun[0]->SATA_lun_map = (tmp8 & 0x01) ^ c;
+                        chan->lun[1]->SATA_lun_map = 0;
+                    } else if ((tmp8 & 0x02) == 0) {
+                        if(c == 0) {
+                            chan->lun[0]->SATA_lun_map = (tmp8 & 0x01) ? 1 : 0;
+                            chan->lun[1]->SATA_lun_map = (tmp8 & 0x01) ? 0 : 1;
+                        } else {
+                            IsPata = TRUE;
+                            //chan->ChannelCtrlFlags |= CTRFLAGS_PATA;
+                        }
+                    } else if ((tmp8 & 0x02) != 0) {
+                        if(c == 1) {
+                            chan->lun[0]->SATA_lun_map = (tmp8 & 0x01) ? 1 : 0;
+                            chan->lun[1]->SATA_lun_map = (tmp8 & 0x01) ? 0 : 1;
+                        } else {
+                            IsPata = TRUE;
+                            //chan->ChannelCtrlFlags |= CTRFLAGS_PATA;
+                        }
+                    }
+                } else
+                if(ChipFlags & I6CH2) {
+                    KdPrint2((PRINT_PREFIX "I6CH2\n"));
+                    chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
+                    chan->lun[0]->SATA_lun_map = c ? 0 : 1;
+                    chan->lun[1]->SATA_lun_map = 0;
+                } else {
+                    KdPrint2((PRINT_PREFIX "other Intel\n"));
+                    switch(tmp8 & 0x03) {
+                    case 0:
+                        KdPrint2((PRINT_PREFIX "0 -> %d/%d\n", 0+c, 2+c));
+                        chan->lun[0]->SATA_lun_map = 0+c;
+                        chan->lun[1]->SATA_lun_map = 2+c;
+                        break;
+                    case 2:
+                        if(c==0) {
+                            KdPrint2((PRINT_PREFIX "2 -> %d/%d\n", 0, 2));
+                            chan->lun[0]->SATA_lun_map = 0;
+                            chan->lun[1]->SATA_lun_map = 2;
+                        } else {
+                            // PATA
+                            KdPrint2((PRINT_PREFIX "PATA\n"));
+                            IsPata = TRUE;
+                        }
+                        break;
+                    case 1:
+                        if(c==1) {
+                            KdPrint2((PRINT_PREFIX "2 -> %d/%d\n", 1, 3));
+                            chan->lun[0]->SATA_lun_map = 1;
+                            chan->lun[1]->SATA_lun_map = 3;
+                        } else {
+                            // PATA
+                            KdPrint2((PRINT_PREFIX "PATA\n"));
+                            IsPata = TRUE;
+                        }
+                        break;
+                    }
+                }
+
+                if(IsPata) {
+                    KdPrint2((PRINT_PREFIX "PATA part\n"));
+                    chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA5);
+                }
+
                 if(ChipType == INTEL_IDX) {
-                    for(c=0; c<deviceExtension->NumberChannels; c++) {
+                    KdPrint2((PRINT_PREFIX "io indexed\n"));
+                    //for(c=0; c<deviceExtension->NumberChannels; c++) {
                         chan = &deviceExtension->chan[c];
                         UniataSataWritePort4(chan, IDX_SATA_SError, 0xffffffff, 0);
                         if(!(chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE)) {
                             UniataSataWritePort4(chan, IDX_SATA_SError, 0xffffffff, 1);
                         }
-                    }
+                    //}
                 }
             }
 
             break;
         }
-        if(deviceExtension->MaxTransferMode < ATA_UDMA2)
+        if(deviceExtension->MaxTransferMode <= ATA_UDMA2)
             break;
         // check 80-pin cable
         if(c == CHAN_NOT_SPECIFIED) {
@@ -1688,7 +2104,12 @@ AtapiChipInit(
         } else {
             chan = &deviceExtension->chan[c];
             GetPciConfig2(0x54, reg54);
-            if( ((reg54 >> (channel*2)) & 30) != 30) {
+            KdPrint2((PRINT_PREFIX " intel 80-pin check (reg54=%x)\n", reg54));
+            if(reg54 == 0x0000 || reg54 == 0xffff) {
+                KdPrint2((PRINT_PREFIX " check failed (not supported)\n"));
+            } else
+            if( ((reg54 >> (channel*2)) & 30) == 0) {
+                KdPrint2((PRINT_PREFIX " intel 40-pin\n"));
                 chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2);
             }
         }
@@ -1704,17 +2125,17 @@ AtapiChipInit(
                 KdPrint2((PRINT_PREFIX "BaseIoAddressSATA_0=%x\n", deviceExtension->BaseIoAddressSATA_0.Addr));
                 if(ChipFlags & NVQ) {
                     /* clear interrupt status */
-                    AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs, 0x00ff00ff);
+                    AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs, 0x00ff00ff);
                     /* enable device and PHY state change interrupts */
-                    AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4, 0x000d000d);
+                    AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4, 0x000d000d);
                     /* disable NCQ support */
-                    AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x0400, 
-                        AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x0400) & 0xfffffff9);
+                    AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x0400, 
+                        AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x0400) & 0xfffffff9);
                 } else {
                     /* clear interrupt status */
-                    AtapiWritePortEx1(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs, 0xff);
+                    AtapiWritePortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs, 0xff);
                     /* enable device and PHY state change interrupts */
-                    AtapiWritePortEx1(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1, 0xdd);
+                    AtapiWritePortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1, 0xdd);
                 }
                 /* enable PCI interrupt */
                 ChangePciConfig2(offsetof(PCI_COMMON_CONFIG, Command), (a & ~0x0400));
@@ -1745,16 +2166,16 @@ AtapiChipInit(
             /* setup clocks */
             if(c == CHAN_NOT_SPECIFIED) {
 //            ATA_OUTB(ctlr->r_res1, 0x11, ATA_INB(ctlr->r_res1, 0x11) | 0x0a);
-                AtapiWritePortEx1(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0),0x11, 
-                    AtapiReadPortEx1(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0),0x11) | 0x0a );
+                AtapiWritePortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x11, 
+                    AtapiReadPortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x11) | 0x0a );
             }
             /* FALLTHROUGH */
         case PROLD:
             /* enable burst mode */
 //            ATA_OUTB(ctlr->r_res1, 0x1f, ATA_INB(ctlr->r_res1, 0x1f) | 0x01);
             if(c == CHAN_NOT_SPECIFIED) {
-                AtapiWritePortEx1(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0),0x1f, 
-                    AtapiReadPortEx1(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0),0x1f) | 0x01 );
+                AtapiWritePortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x1f, 
+                    AtapiReadPortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x1f) | 0x01 );
             } else {
                 // check 80-pin cable
                 chan = &deviceExtension->chan[c];
@@ -1778,8 +2199,13 @@ AtapiChipInit(
             break;
         case PRMIO:
             if(c == CHAN_NOT_SPECIFIED) {
-                if(ChipFlags & PRSATA) {
-                    AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressBM_0),0x6c, 0x000000ff);
+                /* clear SATA status and unmask interrupts */
+                AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),
+                    (ChipFlags & PRG2) ? 0x60 : 0x6c, 0x000000ff);
+                if(ChipFlags & UNIATA_SATA) {
+                    /* enable "long burst length" on gen2 chips */
+                    AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0), 0x44, 
+                        AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0), 0x44) | 0x2000);
                 }
             } else {
                 chan = &deviceExtension->chan[c];
@@ -1813,6 +2239,7 @@ AtapiChipInit(
             KdPrint2((PRINT_PREFIX "ATI\n"));
             break;
         }
+        /* FALLTHROUGH */
     case ATA_SILICON_IMAGE_ID:
   /*      if(ChipFlags & SIIENINTR) {
             SetPciConfig1(0x71, 0x01);
@@ -1858,16 +2285,16 @@ AtapiChipInit(
                         unit10 = (c & 2);
                         if(ChipFlags & SIINOSATAIRQ) {
                             KdPrint2((PRINT_PREFIX "Disable broken SATA intr on c=%x\n", c));
-                            AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x148 + (unit01 << 7) + (unit10 << 8),0);
+                            AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x148 + (unit01 << 7) + (unit10 << 8),0);
                         }
                     }
                 } else {
                     if(ChipFlags & SIINOSATAIRQ) {
                         KdPrint2((PRINT_PREFIX "Disable broken SATA intr on c=%x\n", c));
-                        AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x148 + (unit01 << 7) + (unit10 << 8),0);
+                        AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x148 + (unit01 << 7) + (unit10 << 8),0);
                     } else {
                         KdPrint2((PRINT_PREFIX "Enable SATA intr on c=%x\n", c));
-                        AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x148 + (unit01 << 7) + (unit10 << 8),(1 << 16));
+                        AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x148 + (unit01 << 7) + (unit10 << 8),(1 << 16));
                     }
                 }
             }
@@ -1877,21 +2304,21 @@ AtapiChipInit(
                 // Enable 3rd and 4th channels
                 if (ChipFlags & SII4CH) {
                     KdPrint2((PRINT_PREFIX "SII4CH\n"));
-                    AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x0200, 0x00000002);
+                    AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x0200, 0x00000002);
                 }
             } else {
                 chan = &deviceExtension->chan[c];
                 /* dont block interrupts */
                 //ChangePciConfig4(0x48, (a & ~0x03c00000));
-                tmp32 = AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x48);
-                AtapiWritePortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x48, (1 << 22) << c);
+                /*tmp32 =*/ AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x48);
+                AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x48, (1 << 22) << c);
                 // flush
-                tmp32 = AtapiReadPortEx4(NULL, (ULONG_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x48);
+                /*tmp32 =*/ AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x48);
 
                 /* Initialize FIFO PCI bus arbitration */
                 GetPciConfig1(offsetof(PCI_COMMON_CONFIG, CacheLineSize), tmp8);
                 if(tmp8) {
-                    KdPrint2((PRINT_PREFIX "SII: CacheLine=%d\n", tmp32));
+                    KdPrint2((PRINT_PREFIX "SII: CacheLine=%d\n", tmp8));
                     tmp8 = (tmp8/8)+1;
                     AtapiWritePort2(chan, IDX_BM_DeviceSpecific1, ((USHORT)tmp8) << 8 | tmp8);
                } else {
@@ -1931,7 +2358,15 @@ AtapiChipInit(
             }
 
             break; }
-        }
+        case ATI700:
+            KdPrint2((PRINT_PREFIX "ATI700\n"));
+            if(c == 0 && !(ChipFlags & UNIATA_AHCI)) {
+                KdPrint2((PRINT_PREFIX "IXP700 PATA\n"));
+                chan = &deviceExtension->chan[c];
+                chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA5);
+            }
+            break;
+        } /* switch(ChipType) */
         break;
     case ATA_SIS_ID:
         if(c == CHAN_NOT_SPECIFIED) {
@@ -1952,6 +2387,7 @@ AtapiChipInit(
                 break;
             case SISSATA:
                 ChangePciConfig2(0x04, (a & ~0x0400));
+                break;
             }
         }
         if(ChipType == SIS133NEW) {
@@ -1992,7 +2428,34 @@ AtapiChipInit(
             // no init for SATA
             if(ChipFlags & (UNIATA_SATA | VIASATA)) {
                 /* enable PCI interrupt */
-                ChangePciConfig2(/*PCIR_COMMAND*/0x04, (a & ~0x0400));
+                ChangePciConfig2(offsetof(PCI_COMMON_CONFIG, Command), (a & ~0x0400));
+
+               /*
+                * vt6420/1 has problems talking to some drives.  The following
+                * is based on the fix from Joseph Chan <JosephChan@via.com.tw>.
+                *
+                * When host issues HOLD, device may send up to 20DW of data
+                * before acknowledging it with HOLDA and the host should be
+                * able to buffer them in FIFO.  Unfortunately, some WD drives
+                * send upto 40DW before acknowledging HOLD and, in the
+                * default configuration, this ends up overflowing vt6421's
+                * FIFO, making the controller abort the transaction with
+                * R_ERR.
+                *
+                * Rx52[2] is the internal 128DW FIFO Flow control watermark
+                * adjusting mechanism enable bit and the default value 0
+                * means host will issue HOLD to device when the left FIFO
+                * size goes below 32DW.  Setting it to 1 makes the watermark
+                * 64DW.
+                *
+                * http://www.reactos.org/bugzilla/show_bug.cgi?id=6500
+                */
+
+                if(DeviceID == 0x3149 || DeviceID == 0x3249) {    //vt6420 or vt6421
+                    KdPrint2((PRINT_PREFIX "VIA 642x FIFO\n"));
+                    ChangePciConfig1(0x52, a | (1 << 2));
+                }
+
                 break;
             }
 
@@ -2024,16 +2487,19 @@ AtapiChipInit(
             // no init for SATA
             if(ChipFlags & (UNIATA_SATA | VIASATA)) {
                 if((ChipFlags & VIABAR) && (c >= 2)) {
+                    // this is PATA channel
+                    chan->MaxTransferMode = ATA_UDMA5;
                     break;
                 }
                 UniataSataWritePort4(chan, IDX_SATA_SError, 0xffffffff, 0);
                 break;
             }
-
+/*
             // check 80-pin cable
             if(!via_cable80(deviceExtension, channel)) {
                 chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2);
             }
+*/
         }
 
         break;
@@ -2102,13 +2568,14 @@ UniataInitMapBM(
     for(c=0; c<deviceExtension->NumberChannels; c++) {
         chan = &deviceExtension->chan[c];
         for (i=0; i<IDX_BM_IO_SZ; i++) {
-            chan->RegTranslation[IDX_BM_IO+i].Addr  = BaseIoAddressBM_0 ? ((ULONG_PTR)BaseIoAddressBM_0 + i) : 0;
+            chan->RegTranslation[IDX_BM_IO+i].Addr  = BaseIoAddressBM_0 ? ((ULONGIO_PTR)BaseIoAddressBM_0 + i) : 0;
             chan->RegTranslation[IDX_BM_IO+i].MemIo = MemIo;
         }
         if(BaseIoAddressBM_0) {
             BaseIoAddressBM_0++;
         }
     }
+    return;
 } // end UniataInitMapBM()
 
 VOID
@@ -2122,14 +2589,15 @@ UniataInitMapBase(
     ULONG i;
 
     for (i=0; i<IDX_IO1_SZ; i++) {
-        chan->RegTranslation[IDX_IO1+i].Addr = BaseIoAddress1 ? ((ULONG_PTR)BaseIoAddress1 + i) : 0;
+        chan->RegTranslation[IDX_IO1+i].Addr = BaseIoAddress1 ? ((ULONGIO_PTR)BaseIoAddress1 + i) : 0;
         chan->RegTranslation[IDX_IO1+i].MemIo = FALSE;
     }
     for (i=0; i<IDX_IO2_SZ; i++) {
-        chan->RegTranslation[IDX_IO2+i].Addr = BaseIoAddress2 ? ((ULONG_PTR)BaseIoAddress2 + i) : 0;
+        chan->RegTranslation[IDX_IO2+i].Addr = BaseIoAddress2 ? ((ULONGIO_PTR)BaseIoAddress2 + i) : 0;
         chan->RegTranslation[IDX_IO2+i].MemIo = FALSE;
     }
     UniataInitSyncBaseIO(chan);
+    return;
 } // end UniataInitMapBase()
 
 VOID
@@ -2140,4 +2608,141 @@ UniataInitSyncBaseIO(
 {
     RtlCopyMemory(&chan->RegTranslation[IDX_IO1_o], &chan->RegTranslation[IDX_IO1], IDX_IO1_SZ*sizeof(chan->RegTranslation[0]));
     RtlCopyMemory(&chan->RegTranslation[IDX_IO2_o], &chan->RegTranslation[IDX_IO2], IDX_IO2_SZ*sizeof(chan->RegTranslation[0]));
+    return;
 } // end UniataInitSyncBaseIO()
+
+VOID
+NTAPI
+AtapiSetupLunPtrs(
+    IN PHW_CHANNEL chan,
+    IN PHW_DEVICE_EXTENSION deviceExtension,
+    IN ULONG c
+    )
+{
+    ULONG i;
+
+    KdPrint2((PRINT_PREFIX "AtapiSetupLunPtrs for channel %d of %d, %d luns \n", c, deviceExtension->NumberChannels, deviceExtension->NumberLuns));
+
+    if(!deviceExtension->NumberLuns) {
+        KdPrint2((PRINT_PREFIX "Achtung !deviceExtension->NumberLuns \n"));
+        deviceExtension->NumberLuns = IDE_MAX_LUN_PER_CHAN;
+    }
+    KdPrint2((PRINT_PREFIX "  Chan %#x\n", chan));
+    chan->DeviceExtension = deviceExtension;
+    chan->lChannel        = c;
+    chan->NumberLuns      = deviceExtension->NumberLuns;
+    for(i=0; i<deviceExtension->NumberLuns; i++) {
+        chan->lun[i] = &(deviceExtension->lun[c*deviceExtension->NumberLuns+i]);
+        KdPrint2((PRINT_PREFIX "  Lun %#x\n", i));
+        KdPrint2((PRINT_PREFIX "  Lun ptr %#x\n", chan->lun[i]));
+    }
+    chan->AltRegMap       = deviceExtension->AltRegMap;
+    chan->NextDpcChan     = -1;
+    for(i=0; i<deviceExtension->NumberLuns; i++) {
+        chan->lun[i]->DeviceExtension = deviceExtension;
+        chan->lun[i]->chan            = chan;
+        chan->lun[i]->Lun             = i;
+    }
+    if((deviceExtension->HwFlags & UNIATA_AHCI) &&
+       deviceExtension->AhciInternalAtaReq0 &&
+       deviceExtension->AhciInternalSrb0) {
+        chan->AhciInternalAtaReq = &(deviceExtension->AhciInternalAtaReq0[c]);
+        chan->AhciInternalSrb = &(deviceExtension->AhciInternalSrb0[c]);
+        UniataAhciSetupCmdPtr(chan->AhciInternalAtaReq);
+        chan->AhciInternalSrb->SrbExtension = chan->AhciInternalAtaReq;
+        chan->AhciInternalAtaReq->Srb = chan->AhciInternalSrb;
+    }
+    return;
+} // end AtapiSetupLunPtrs()
+
+BOOLEAN
+NTAPI
+UniataAllocateLunExt(
+    PHW_DEVICE_EXTENSION  deviceExtension,
+    ULONG NewNumberChannels
+    )
+{
+    PHW_LU_EXTENSION old_luns = NULL;
+    PHW_CHANNEL old_chans = NULL;
+
+    KdPrint2((PRINT_PREFIX "allocate %d Luns for %d channels\n", deviceExtension->NumberLuns, deviceExtension->NumberChannels));
+
+    old_luns = deviceExtension->lun;
+    old_chans = deviceExtension->chan;
+
+    if(old_luns || old_chans) {
+        if(NewNumberChannels == UNIATA_ALLOCATE_NEW_LUNS) {
+            KdPrint2((PRINT_PREFIX "already allocated!\n"));
+            return FALSE;
+        }
+    }
+
+    if(!deviceExtension->NumberLuns) {
+        KdPrint2((PRINT_PREFIX "default NumberLuns=2\n"));
+        deviceExtension->NumberLuns = 2;
+    }
+
+    if(deviceExtension->HwFlags & UNIATA_AHCI) {
+        if(!deviceExtension->AhciInternalAtaReq0) {
+            deviceExtension->AhciInternalAtaReq0 = (PATA_REQ)ExAllocatePool(NonPagedPool, sizeof(ATA_REQ)*deviceExtension->NumberChannels);
+            if (!deviceExtension->AhciInternalAtaReq0) {
+                KdPrint2((PRINT_PREFIX "!deviceExtension->AhciInternalAtaReq0 => SP_RETURN_ERROR\n"));
+                return FALSE;
+            }
+            RtlZeroMemory(deviceExtension->AhciInternalAtaReq0, sizeof(ATA_REQ)*deviceExtension->NumberChannels);
+        }
+        if(!deviceExtension->AhciInternalSrb0) {
+            deviceExtension->AhciInternalSrb0 = (PSCSI_REQUEST_BLOCK)ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK)*deviceExtension->NumberChannels);
+            if (!deviceExtension->AhciInternalSrb0) {
+                KdPrint2((PRINT_PREFIX "!deviceExtension->AhciInternalSrb0 => SP_RETURN_ERROR\n"));
+                UniataFreeLunExt(deviceExtension);
+                return FALSE;
+            }
+            RtlZeroMemory(deviceExtension->AhciInternalSrb0, sizeof(SCSI_REQUEST_BLOCK)*deviceExtension->NumberChannels);
+        }
+    }
+
+    deviceExtension->lun = (PHW_LU_EXTENSION)ExAllocatePool(NonPagedPool, sizeof(HW_LU_EXTENSION) * (deviceExtension->NumberChannels+1) * deviceExtension->NumberLuns);
+    if (!deviceExtension->lun) {
+        KdPrint2((PRINT_PREFIX "!deviceExtension->lun => SP_RETURN_ERROR\n"));
+        UniataFreeLunExt(deviceExtension);
+        return FALSE;
+    }
+    RtlZeroMemory(deviceExtension->lun, sizeof(HW_LU_EXTENSION) * (deviceExtension->NumberChannels+1) * deviceExtension->NumberLuns);
+    
+    deviceExtension->chan = (PHW_CHANNEL)ExAllocatePool(NonPagedPool, sizeof(HW_CHANNEL) * (deviceExtension->NumberChannels+1));
+    if (!deviceExtension->chan) {
+        UniataFreeLunExt(deviceExtension);
+        KdPrint2((PRINT_PREFIX "!deviceExtension->chan => SP_RETURN_ERROR\n"));
+        return FALSE;
+    }
+    RtlZeroMemory(deviceExtension->chan, sizeof(HW_CHANNEL) * (deviceExtension->NumberChannels+1));
+    return TRUE;
+} // end UniataAllocateLunExt()
+
+VOID
+NTAPI
+UniataFreeLunExt(
+    PHW_DEVICE_EXTENSION  deviceExtension
+    )
+{
+    if (deviceExtension->lun) {
+        ExFreePool(deviceExtension->lun);
+        deviceExtension->lun = NULL;
+    }
+    if (deviceExtension->chan) {
+        ExFreePool(deviceExtension->chan);
+        deviceExtension->chan = NULL;
+    }
+    if(deviceExtension->AhciInternalAtaReq0) {
+        ExFreePool(deviceExtension->AhciInternalAtaReq0);
+        deviceExtension->AhciInternalAtaReq0 = NULL;
+    }
+    if(deviceExtension->AhciInternalSrb0) {
+        ExFreePool(deviceExtension->AhciInternalSrb0);
+        deviceExtension->AhciInternalSrb0 = NULL;
+    }
+    
+    return;
+} // end UniataFreeLunExt()
+