[UNIATA] Fix for uninitialized Lun pointer
[reactos.git] / drivers / storage / ide / uniata / id_init.cpp
index e34f3de..b9beb1b 100644 (file)
@@ -1,6 +1,6 @@
 /*++
 
-Copyright (c) 2004-2011 Alexandr A. Telyatnikov (Alter)
+Copyright (c) 2004-2018 Alexandr A. Telyatnikov (Alter)
 
 Module Name:
     id_init.cpp
@@ -38,11 +38,21 @@ Revision History:
         VIA, nVidia
     added support for non-standard layout of registers
     added SATA support
+    added AHCI support
+
+Licence:
+    GPLv2
 
 --*/
 
 #include "stdafx.h"
 
+static BUSMASTER_CONTROLLER_INFORMATION_BASE 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,23 +64,26 @@ 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;
     ULONG ChipType = deviceExtension->HwFlags & CHIPTYPE_MASK;
     ULONG ChipFlags= deviceExtension->HwFlags & CHIPFLAG_MASK;
+    ULONG i,n;
 
     KdPrint2((PRINT_PREFIX "UniataChipDetectChannels:\n" ));
 
+    deviceExtension->AHCI_PI_mask = 0;
+
     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\n"));
-            deviceExtension->NumberLuns = 2;
+            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));
@@ -82,6 +95,21 @@ UniataChipDetectChannels(
         KdPrint2((PRINT_PREFIX "MasterDev -> 1 chan\n"));
         deviceExtension->NumberChannels = 1;
     }
+    for(n=0; n<deviceExtension->NumberChannels; n++) {
+        if(AtapiRegCheckDevValue(deviceExtension, n, DEVNUM_NOT_SPECIFIED, L"Exclude", 0)) {
+            KdPrint2((PRINT_PREFIX "Channel %d excluded\n", n));
+            deviceExtension->AHCI_PI_mask &= ~((ULONG)1 << n);
+        } else {
+            deviceExtension->AHCI_PI_mask |= ((ULONG)1 << n);
+        }
+    }
+    KdPrint2((PRINT_PREFIX "PortMask %#x\n", deviceExtension->AHCI_PI_mask));
+    deviceExtension->AHCI_PI_mask = 
+        AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"PortMask", (ULONG)0xffffffff >> (32-deviceExtension->NumberChannels) );
+    KdPrint2((PRINT_PREFIX "Force PortMask %#x\n", deviceExtension->AHCI_PI_mask));
+
+    for(i=deviceExtension->AHCI_PI_mask, n=0; i; n++, i=i>>1);
+    KdPrint2((PRINT_PREFIX "mask -> %d chans\n", n));
 
     switch(VendorID) {
     case ATA_ACER_LABS_ID:
@@ -97,16 +125,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;
@@ -118,8 +156,8 @@ UniataChipDetectChannels(
         KdPrint2((PRINT_PREFIX "ATI\n"));
         switch(deviceExtension->DevID) {
         case ATA_ATI_IXP600:    
-        case ATA_ATI_IXP700:
-            /* IXP600 & IXP700 only have 1 PATA channel */
+            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;
@@ -127,11 +165,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 j, 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.
+             */
+            j = AtapiFindListedDev((BUSMASTER_CONTROLLER_INFORMATION_BASE*)&AtiSouthAdapters[0], -1, HwDeviceExtension, SystemIoBusNumber, PCISLOTNUM_NOT_SPECIFIED, &slotData);
+            if(j != 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; }
         }
         /* 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;
@@ -175,9 +262,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) { 
@@ -189,20 +278,58 @@ UniataChipDetectChannels(
             KdPrint2((PRINT_PREFIX "New Intel PATA 1 chan\n"));
         }
         break;
+#endif // this code is removed from newer FreeBSD
+#if 0
     case ATA_JMICRON_ID:
         /* New JMicron PATA controllers */
         if(deviceExtension->DevID == ATA_JMB361 ||
            deviceExtension->DevID == ATA_JMB363 ||
+           deviceExtension->DevID == ATA_JMB365 ||
+           deviceExtension->DevID == ATA_JMB366 ||
            deviceExtension->DevID == ATA_JMB368) { 
-            if(BMList[deviceExtension->DevIndex].channel) {
-                KdPrint2((PRINT_PREFIX "New JMicron has no 2nd chan\n"));
+
+            ULONG tmp32, port_mask;
+
+            port_mask = BMList[deviceExtension->DevIndex].channel;
+
+            GetPciConfig4(0x40, tmp32);
+
+            deviceExtension->NumberChannels = 2;
+            //KdPrint2((PRINT_PREFIX "New JMicron PATA 1 chan\n"));
+        }
+        break;
+#endif // this code is unnecessary since port mapping is implemented
+    case ATA_CYRIX_ID:
+        if(ChipType == CYRIX_OLD) {
+            UCHAR tmp8;
+            ULONG slotNumber;
+            slotNumber = deviceExtension->slotNumber;
+            KdPrint2((PRINT_PREFIX "Cyrix slot %#x\n", slotNumber));
+            GetPciConfig1(0x60, tmp8);
+            if(tmp8 & (1 << BMList[deviceExtension->DevIndex].channel)) {
+                KdPrint2((PRINT_PREFIX "Old Cyrix chan %d ok\n", BMList[deviceExtension->DevIndex].channel));
+            } else {
+                KdPrint2((PRINT_PREFIX "Old Cyrix no chan %d\n", BMList[deviceExtension->DevIndex].channel));
                 return FALSE;
             }
-            deviceExtension->NumberChannels = 1;
-            KdPrint2((PRINT_PREFIX "New JMicron PATA 1 chan\n"));
         }
         break;
     } // end switch(VendorID)
+
+    i = AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"NumberChannels", n);
+    if(!i) {
+        i = n;
+    }
+    KdPrint2((PRINT_PREFIX "reg -> %d chans\n", n));
+
+    deviceExtension->NumberChannels = min(i, deviceExtension->NumberChannels);
+    if(!deviceExtension->NumberChannels) {
+        KdPrint2((PRINT_PREFIX "all channels blocked\n", n));
+        return FALSE;
+    }
+    deviceExtension->AHCI_PI_mask &= (ULONG)0xffffffff >> (32-deviceExtension->NumberChannels);
+    KdPrint2((PRINT_PREFIX "Final PortMask %#x\n", deviceExtension->AHCI_PI_mask));
+
     return TRUE;
 
 } // end UniataChipDetectChannels()
@@ -224,22 +351,23 @@ UniataChipDetect(
     ULONG DeviceID = (deviceExtension->DevID >> 16) & 0xffff;
     ULONG RevID    =  deviceExtension->RevID;
     ULONG i, c;
-    BUSMASTER_CONTROLLER_INFORMATION* DevTypeInfo;
+    BUSMASTER_CONTROLLER_INFORMATION_BASE* DevTypeInfo;
     PHW_CHANNEL chan;
     ULONG ChipType;
     ULONG ChipFlags;
     ULONG tmp32;
     UCHAR tmp8;
-    ULONG BaseMemAddress;
-    ULONG BaseIoAddress1;
-    ULONG BaseIoAddress2;
-    ULONG BaseIoAddressBM;
+    ULONG_PTR BaseMemAddress;
+    ULONG_PTR BaseIoAddress1;
+    ULONG_PTR BaseIoAddress2;
+    ULONG_PTR BaseIoAddressBM;
     BOOLEAN MemIo = FALSE;
+    BOOLEAN IsPata = FALSE;
 
     KdPrint2((PRINT_PREFIX "UniataChipDetect:\n" ));
     KdPrint2((PRINT_PREFIX "HwFlags: %#x\n", deviceExtension->HwFlags));
 
-    i = Ata_is_dev_listed((PBUSMASTER_CONTROLLER_INFORMATION)&BusMasterAdapters[0], VendorID, 0xffff, 0, NUM_BUSMASTER_ADAPTERS);
+    i = Ata_is_dev_listed((PBUSMASTER_CONTROLLER_INFORMATION_BASE)&BusMasterAdapters[0], VendorID, 0xffff, 0, NUM_BUSMASTER_ADAPTERS);
 
     c = AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"ForceSimplex", 0);
     if(c) {
@@ -251,11 +379,15 @@ 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];
+        DevTypeInfo = (PBUSMASTER_CONTROLLER_INFORMATION_BASE)&BusMasterAdapters[i];
     } else {
+unknown_dev:
         if(Ata_is_ahci_dev(pciData)) {
             KdPrint2((PRINT_PREFIX "  AHCI candidate"));
 
@@ -264,10 +396,9 @@ UniataChipDetect(
                 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 AHCI dev, addr %#x ", deviceExtension->BaseIoAHCI_0.Addr));
         }
-unknown_dev:
-        KdPrint2((PRINT_PREFIX "  unknown dev, BM addr %#I64x", BaseIoAddressBM));
+        KdPrint2((PRINT_PREFIX "  unknown dev, BM addr %#x ", BaseIoAddressBM));
         DevTypeInfo = NULL;
         KdPrint2((PRINT_PREFIX "  MaxTransferMode %#x\n", deviceExtension->MaxTransferMode));
 
@@ -277,11 +408,13 @@ unknown_dev:
         if(!UniataAllocateLunExt(deviceExtension, UNIATA_ALLOCATE_NEW_LUNS)) {
             return STATUS_UNSUCCESSFUL;
         }
-
-        return STATUS_NOT_FOUND;
+        return STATUS_SUCCESS;
     }
 
-    static BUSMASTER_CONTROLLER_INFORMATION const SiSAdapters[] = {
+    static BUSMASTER_CONTROLLER_INFORMATION_BASE const SiSAdapters[] = {
+        PCI_DEV_HW_SPEC_BM( 1183, 1039, 0x00, ATA_SA150, "SiS 1183 IDE" , 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 RAID"  , 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),
@@ -300,7 +433,7 @@ unknown_dev:
 /*        PCI_DEV_HW_SPEC_BM( 0640, 1039, 0x00, ATA_UDMA4, "SiS 640"  , SIS_SOUTH        ),*/
         PCI_DEV_HW_SPEC_BM( 0635, 1039, 0x00, ATA_UDMA5, "SiS 635"  , SIS100NEW        ),
         PCI_DEV_HW_SPEC_BM( 0633, 1039, 0x00, ATA_UDMA5, "SiS 633"  , SIS100NEW        ),
-        PCI_DEV_HW_SPEC_BM( 0630, 1039, 0x00, ATA_UDMA5, "SiS 630S" , SIS100OLD        ),
+        PCI_DEV_HW_SPEC_BM( 0630, 1039, 0x30, ATA_UDMA5, "SiS 630S" , SIS100OLD        ),
         PCI_DEV_HW_SPEC_BM( 0630, 1039, 0x00, ATA_UDMA4, "SiS 630"  , SIS66            ),
         PCI_DEV_HW_SPEC_BM( 0620, 1039, 0x00, ATA_UDMA4, "SiS 620"  , SIS66            ),
 
@@ -319,7 +452,7 @@ unknown_dev:
         PCI_DEV_HW_SPEC_BM( ffff, ffff, 0xff, BMLIST_TERMINATOR       , NULL       , BMLIST_TERMINATOR )
         };
 
-    static BUSMASTER_CONTROLLER_INFORMATION const ViaAdapters[] = {
+    static BUSMASTER_CONTROLLER_INFORMATION_BASE const ViaAdapters[] = {
         PCI_DEV_HW_SPEC_BM( 0586, 1106, 0x41, ATA_UDMA2, "VIA 82C586B", VIA33  | 0x00   ),
         PCI_DEV_HW_SPEC_BM( 0586, 1106, 0x40, ATA_UDMA2, "VIA 82C586B", VIA33  | VIAPRQ ),
         PCI_DEV_HW_SPEC_BM( 0586, 1106, 0x02, ATA_UDMA2, "VIA 82C586B", VIA33  | 0x00   ),
@@ -341,18 +474,18 @@ unknown_dev:
         PCI_DEV_HW_SPEC_BM( 5372, 1106, 0x00, ATA_UDMA6, "VIA 8237"   , VIA133 | 0x00 ),
         PCI_DEV_HW_SPEC_BM( 7372, 1106, 0x00, ATA_UDMA6, "VIA 8237"   , VIA133 | 0x00 ),
         PCI_DEV_HW_SPEC_BM( 3349, 1106, 0x00, ATA_UDMA6, "VIA 8251"   , VIA133 | 0x00 ),
-        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( 8324, 1106, 0x00, ATA_SA150, "VIA CX700"  , VIANEW | VIASATA),
+        PCI_DEV_HW_SPEC_BM( 8353, 1106, 0x00, ATA_SA150, "VIA VX800"  , VIANEW | 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( 8410, 1106, 0x00, ATA_SA300, "VIA VX900"  , VIANEW | 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 ),
+    static BUSMASTER_CONTROLLER_INFORMATION_BASE const ViaSouthAdapters[] = {
+        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 )
         };
 
@@ -361,8 +494,12 @@ 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];
+        DevTypeInfo = (BUSMASTER_CONTROLLER_INFORMATION_BASE*)&SiSAdapters[0];
         i = AtapiFindListedDev(DevTypeInfo, -1, HwDeviceExtension, SystemIoBusNumber, PCISLOTNUM_NOT_SPECIFIED, NULL);
         if(i != BMLIST_TERMINATOR) {
             deviceExtension->FullDevName = SiSAdapters[i].FullDevName;
@@ -383,7 +520,7 @@ unknown_dev:
         KdPrint2((PRINT_PREFIX "Via-old-style %x\n", deviceExtension->DevID));
         // Traditionally, chips have same DeviceId, we can distinguish between them
         // only by ISA Bridge DeviceId
-        DevTypeInfo = (BUSMASTER_CONTROLLER_INFORMATION*)&ViaSouthAdapters[0];
+        DevTypeInfo = (BUSMASTER_CONTROLLER_INFORMATION_BASE*)&ViaSouthAdapters[0];
         i = AtapiFindListedDev(DevTypeInfo, -1, HwDeviceExtension, SystemIoBusNumber,
                                PCISLOTNUM_NOT_SPECIFIED/*slotNumber*/, NULL);
 /*        if(i == BMLIST_TERMINATOR) {
@@ -393,7 +530,7 @@ unknown_dev:
             KdPrint2((PRINT_PREFIX "VIASOUTH\n"));
             deviceExtension->HwFlags |= VIASOUTH;
         }
-        DevTypeInfo = (BUSMASTER_CONTROLLER_INFORMATION*)&ViaAdapters[0];
+        DevTypeInfo = (BUSMASTER_CONTROLLER_INFORMATION_BASE*)&ViaAdapters[0];
         i = AtapiFindListedDev(DevTypeInfo, -1, HwDeviceExtension, SystemIoBusNumber,
                                PCISLOTNUM_NOT_SPECIFIED/*slotNumber*/, NULL);
         if(i != BMLIST_TERMINATOR) {
@@ -442,8 +579,8 @@ unknown_dev:
                 ScsiPortFreeDeviceBase(HwDeviceExtension,
                                        deviceExtension->BaseIoAddressBM_0);
 
-            deviceExtension->BaseIoAddressBM_0 = 0;
-            deviceExtension->BusMaster = FALSE;
+            UniataInitIoResEx(&deviceExtension->BaseIoAddressBM_0, 0, FALSE, FALSE);
+            deviceExtension->BusMaster = DMA_MODE_NONE;
             deviceExtension->MaxTransferMode = ATA_PIO4;
             break;
 
@@ -493,8 +630,10 @@ for_ugly_chips:
     }
 
     if(deviceExtension->MaxTransferMode >= ATA_SA150) {
+        KdPrint2((PRINT_PREFIX "setting UNIATA_SATA flag\n"));
         deviceExtension->HwFlags |= UNIATA_SATA;
     }
+
 /*
     ConfigInfo->MaximumTransferLength = DEV_BSIZE*256;
     deviceExtension->MaximumDmaTransferLength = ConfigInfo->MaximumTransferLength;
@@ -502,12 +641,40 @@ 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;
+        default:
+            if(!ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[5].RangeStart)) {
+                KdPrint2((PRINT_PREFIX "No BAR5, try BM\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;
@@ -517,9 +684,6 @@ for_ugly_chips:
         return STATUS_UNSUCCESSFUL;
     }
 
-    if(ChipFlags & UNIATA_AHCI) {
-    }
-
     switch(VendorID) {
     case ATA_ACER_LABS_ID:
         if(ChipFlags & UNIATA_SATA) {
@@ -536,13 +700,13 @@ for_ugly_chips:
                 chan = &deviceExtension->chan[c];
 
                 for (i=0; i<=IDX_IO1_SZ; i++) {
-                    chan->RegTranslation[IDX_IO1+i].Addr           = BaseIoAddress1  + i + (unit10 ? 8 : 0);
+                    UniataInitIoRes(chan, IDX_IO1+i, BaseIoAddress1 + i + (unit10 ? 8 : 0), FALSE, FALSE);
                 }
-                chan->RegTranslation[IDX_IO2_AltStatus].Addr       = BaseIoAddress2  + 2 + (unit10 ? 4 : 0);
+                UniataInitIoRes(chan, IDX_IO2_AltStatus, BaseIoAddress2  + 2 + (unit10 ? 4 : 0), FALSE, FALSE);
                 UniataInitSyncBaseIO(chan);
 
                 for (i=0; i<=IDX_BM_IO_SZ; i++) {
-                    chan->RegTranslation[IDX_BM_IO+i].Addr         = BaseIoAddressBM + i + (c * sizeof(IDE_BUSMASTER_REGISTERS));
+                    UniataInitIoRes(chan, IDX_BM_IO+i, BaseIoAddressBM + i + (c * sizeof(IDE_BUSMASTER_REGISTERS)), FALSE, FALSE);
                 }
 
                 // SATA not supported yet
@@ -561,21 +725,20 @@ 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;
             }
-            deviceExtension->BaseIoAddressSATA_0.Addr  = BaseMemAddress;
-            deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo;
+            UniataInitIoResEx(&deviceExtension->BaseIoAddressSATA_0, BaseMemAddress, MemIo, FALSE);
             for(c=0; c<deviceExtension->NumberChannels; c++) {
                 chan = &deviceExtension->chan[c];
 
-                chan->RegTranslation[IDX_SATA_SStatus].Addr   = BaseMemAddress +     (c << 6);
-                chan->RegTranslation[IDX_SATA_SStatus].MemIo  = MemIo;
-                chan->RegTranslation[IDX_SATA_SError].Addr    = BaseMemAddress + 4 + (c << 6);
-                chan->RegTranslation[IDX_SATA_SError].MemIo   = MemIo;
-                chan->RegTranslation[IDX_SATA_SControl].Addr  = BaseMemAddress + 8 + (c << 6);
-                chan->RegTranslation[IDX_SATA_SControl].MemIo = MemIo;
+                UniataInitIoRes(chan, IDX_SATA_SStatus,  BaseMemAddress +     (c << 6), MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_SATA_SError,   BaseMemAddress + 4 + (c << 6), MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_SATA_SControl, BaseMemAddress + 8 + (c << 6), MemIo, FALSE);
 
                 chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
             }
@@ -590,44 +753,91 @@ 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->BaseIoAddressBM_0.Addr  = BaseMemAddress;
-        deviceExtension->BaseIoAddressBM_0.MemIo = MemIo;
+        UniataInitIoResEx(&deviceExtension->BaseIoAddressSATA_0, BaseMemAddress, MemIo, FALSE);
+
+        /* 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;
+        }
+        UniataInitIoResEx(&deviceExtension->BaseIoAddressBM_0, BaseMemAddress, MemIo, FALSE);
+
+        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].MemIo          = MemIo;
+                UniataInitIoRes(chan, IDX_IO1+i,          BaseMemAddress + 0x200 + (i << 2) + offs8, MemIo, FALSE);
             }
-            chan->RegTranslation[IDX_IO2_AltStatus].Addr       = BaseMemAddress + 0x238 + offs7;
-            chan->RegTranslation[IDX_IO2_AltStatus].MemIo      = MemIo;
+            UniataInitIoRes(chan, IDX_IO2_AltStatus,      BaseMemAddress + 0x238 + offs7, MemIo, FALSE);
 
             UniataInitSyncBaseIO(chan);
 
-            chan->RegTranslation[IDX_BM_Command].Addr          = BaseMemAddress + 0x260 + offs7;
-            chan->RegTranslation[IDX_BM_Command].MemIo         = MemIo;
-            chan->RegTranslation[IDX_BM_PRD_Table].Addr        = BaseMemAddress + 0x244 + offs7;
-            chan->RegTranslation[IDX_BM_PRD_Table].MemIo       = MemIo;
-            chan->RegTranslation[IDX_BM_DeviceSpecific0].Addr  = BaseMemAddress + (c << 2);
-            chan->RegTranslation[IDX_BM_DeviceSpecific0].MemIo = MemIo;
+            UniataInitIoRes(chan, IDX_BM_Command,         BaseMemAddress + 0x260 + offs7, MemIo, FALSE);
+            UniataInitIoRes(chan, IDX_BM_PRD_Table,       BaseMemAddress + 0x244 + offs7, MemIo, FALSE);
+            UniataInitIoRes(chan, IDX_BM_DeviceSpecific0, BaseMemAddress + (c << 2),      MemIo, FALSE);
+
+            if((ChipFlags & PRSATA) ||
+               ((ChipFlags & PRCMBO) && c<2)) {
+                KdPrint2((PRINT_PREFIX "Promise SATA\n"));
+
+                UniataInitIoRes(chan, IDX_SATA_SStatus,  BaseMemAddress + 0x400 + offs7, MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_SATA_SError,   BaseMemAddress + 0x404 + offs7, MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_SATA_SControl, BaseMemAddress + 0x408 + offs7, MemIo, FALSE);
+
+                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: {
 
@@ -651,12 +861,14 @@ 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;
         }
-        deviceExtension->BaseIoAddressSATA_0.Addr  = BaseMemAddress;
-        deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo;
+        UniataInitIoResEx(&deviceExtension->BaseIoAddressSATA_0, BaseMemAddress, MemIo, FALSE);
 
         for(c=0; c<deviceExtension->NumberChannels; c++) {
             ULONG unit01 = (c & 1);
@@ -666,34 +878,26 @@ for_ugly_chips:
 
             if(deviceExtension->AltRegMap) {
                 for (i=0; i<=IDX_IO1_SZ; i++) {
-                    chan->RegTranslation[IDX_IO1+i].Addr           = BaseMemAddress + 0x80 + i + (unit01 << 6) + (unit10 << 8);
-                    chan->RegTranslation[IDX_IO1+i].MemIo          = MemIo;
+                    UniataInitIoRes(chan, IDX_IO1+i, BaseMemAddress + 0x80 + i + (unit01 << 6) + (unit10 << 8), MemIo, FALSE);
                 }
-                chan->RegTranslation[IDX_IO2_AltStatus].Addr       = BaseMemAddress + 0x8a + (unit01 << 6) + (unit10 << 8);
-                chan->RegTranslation[IDX_IO2_AltStatus].MemIo      = MemIo;
+                UniataInitIoRes(chan, IDX_IO2_AltStatus, BaseMemAddress + 0x8a + (unit01 << 6) + (unit10 << 8), MemIo, FALSE);
                 UniataInitSyncBaseIO(chan);
 
-                chan->RegTranslation[IDX_BM_Command].Addr          = BaseMemAddress + 0x00 + (unit01 << 3) + (unit10 << 8);
-                chan->RegTranslation[IDX_BM_Command].MemIo         = MemIo;
-                chan->RegTranslation[IDX_BM_Status].Addr           = BaseMemAddress + 0x02 + (unit01 << 3) + (unit10 << 8);
-                chan->RegTranslation[IDX_BM_Status].MemIo          = MemIo;
-                chan->RegTranslation[IDX_BM_PRD_Table].Addr        = BaseMemAddress + 0x04 + (unit01 << 3) + (unit10 << 8);
-                chan->RegTranslation[IDX_BM_PRD_Table].MemIo       = MemIo;
-                //chan->RegTranslation[IDX_BM_DeviceSpecific0].Addr  = BaseMemAddress + 0xa1 + (unit01 << 6) + (unit10 << 8);
-                //chan->RegTranslation[IDX_BM_DeviceSpecific0].MemIo = MemIo;
-                chan->RegTranslation[IDX_BM_DeviceSpecific0].Addr  = BaseMemAddress + 0x10 + (unit01 << 3) + (unit10 << 8);
-                chan->RegTranslation[IDX_BM_DeviceSpecific0].MemIo = MemIo;
-                chan->RegTranslation[IDX_BM_DeviceSpecific1].Addr  = BaseMemAddress + 0x40 + (unit01 << 2) + (unit10 << 8);
-                chan->RegTranslation[IDX_BM_DeviceSpecific1].MemIo = MemIo;
+                UniataInitIoRes(chan, IDX_BM_Command,   BaseMemAddress + 0x00 + (unit01 << 3) + (unit10 << 8), MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_BM_Status,    BaseMemAddress + 0x02 + (unit01 << 3) + (unit10 << 8), MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_BM_PRD_Table, BaseMemAddress + 0x04 + (unit01 << 3) + (unit10 << 8), MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_BM_DeviceSpecific0, BaseMemAddress + 0x10 + (unit01 << 3) + (unit10 << 8), MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_BM_DeviceSpecific1, BaseMemAddress + 0x40 + (unit01 << 2) + (unit10 << 8), MemIo, FALSE);
             }
 
+            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;
-                chan->RegTranslation[IDX_SATA_SError].Addr         = BaseMemAddress + 0x108 + (unit01 << 7) + (unit10 << 8);
-                chan->RegTranslation[IDX_SATA_SError].MemIo        = MemIo;
-                chan->RegTranslation[IDX_SATA_SControl].Addr       = BaseMemAddress + 0x100 + (unit01 << 7) + (unit10 << 8);
-                chan->RegTranslation[IDX_SATA_SControl].MemIo      = MemIo;
+                UniataInitIoRes(chan, IDX_SATA_SStatus,  BaseMemAddress + 0x104 + (unit01 << 7) + (unit10 << 8), MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_SATA_SError,   BaseMemAddress + 0x108 + (unit01 << 2) + (unit10 << 8), MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_SATA_SControl, BaseMemAddress + 0x100 + (unit01 << 2) + (unit10 << 8), MemIo, FALSE);
 
                 chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
             }
@@ -715,38 +919,32 @@ 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;
         }
-        deviceExtension->BaseIoAddressSATA_0.Addr  = BaseMemAddress;
-        deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo;
+        UniataInitIoResEx(&deviceExtension->BaseIoAddressSATA_0, BaseMemAddress, MemIo, FALSE);
 
         for(c=0; c<deviceExtension->NumberChannels; c++) {
             ULONG offs = c*0x100;
 
             chan = &deviceExtension->chan[c];
             for (i=0; i<=IDX_IO1_SZ; i++) {
-                chan->RegTranslation[IDX_IO1+i].Addr           = BaseMemAddress + offs + i*4;
-                chan->RegTranslation[IDX_IO1+i].MemIo          = MemIo;
+                UniataInitIoRes(chan, IDX_IO1+i, BaseMemAddress + offs + i*4, MemIo, FALSE);
             }
-            chan->RegTranslation[IDX_IO2_AltStatus].Addr       = BaseMemAddress + offs + 0x20;
-            chan->RegTranslation[IDX_IO2_AltStatus].MemIo      = MemIo;
+            UniataInitIoRes(chan, IDX_IO2_AltStatus, BaseMemAddress + offs + 0x20, MemIo, FALSE);
             UniataInitSyncBaseIO(chan);
 
-            chan->RegTranslation[IDX_BM_Command].Addr          = BaseMemAddress + offs + 0x30;
-            chan->RegTranslation[IDX_BM_Command].MemIo         = MemIo;
-            chan->RegTranslation[IDX_BM_Status].Addr           = BaseMemAddress + offs + 0x32;
-            chan->RegTranslation[IDX_BM_Status].MemIo          = MemIo;
-            chan->RegTranslation[IDX_BM_PRD_Table].Addr        = BaseMemAddress + offs + 0x34;
-            chan->RegTranslation[IDX_BM_PRD_Table].MemIo       = MemIo;
+            UniataInitIoRes(chan, IDX_BM_Command,   BaseMemAddress + offs + 0x30, MemIo, FALSE);
+            UniataInitIoRes(chan, IDX_BM_Status,    BaseMemAddress + offs + 0x32, MemIo, FALSE);
+            UniataInitIoRes(chan, IDX_BM_PRD_Table, BaseMemAddress + offs + 0x34, MemIo, FALSE);
 
-            chan->RegTranslation[IDX_SATA_SStatus].Addr        = BaseMemAddress + offs + 0x40;
-            chan->RegTranslation[IDX_SATA_SStatus].MemIo       = MemIo;               
-            chan->RegTranslation[IDX_SATA_SError].Addr         = BaseMemAddress + offs + 0x44;
-            chan->RegTranslation[IDX_SATA_SError].MemIo        = MemIo;               
-            chan->RegTranslation[IDX_SATA_SControl].Addr       = BaseMemAddress + offs + 0x48;
-            chan->RegTranslation[IDX_SATA_SControl].MemIo      = MemIo;
+            UniataInitIoRes(chan, IDX_SATA_SStatus,  BaseMemAddress + offs + 0x40, MemIo, FALSE);
+            UniataInitIoRes(chan, IDX_SATA_SError,   BaseMemAddress + offs + 0x44, MemIo, FALSE);
+            UniataInitIoRes(chan, IDX_SATA_SControl, BaseMemAddress + offs + 0x48, MemIo, FALSE);
 
             chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
         }
@@ -774,25 +972,29 @@ for_ugly_chips:
             // Restore device ID
             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 )
+            static BUSMASTER_CONTROLLER_INFORMATION_BASE const SiSSouthAdapters[] = {
+                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);
             ChangePciConfig1(0x4a, (a | 0x10));
             if(tmp32 == ATA_SIS5513 ||
                tmp32 == ATA_SIS5517) {
-                i = AtapiFindListedDev((BUSMASTER_CONTROLLER_INFORMATION*)&SiSSouthAdapters[0],
+                i = AtapiFindListedDev((BUSMASTER_CONTROLLER_INFORMATION_BASE*)&SiSSouthAdapters[0],
                      -1, HwDeviceExtension, SystemIoBusNumber, PCISLOTNUM_NOT_SPECIFIED, NULL); 
                 if(i != BMLIST_TERMINATOR) {
+                    KdPrint2((PRINT_PREFIX "SIS South\n"));
                     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) {
+                        KdPrint2((PRINT_PREFIX "SIS South SATA\n"));
                         deviceExtension->HwFlags |= UNIATA_SATA;
-                        if(SiSSouthAdapters[i].nDeviceId == 0x1182) {
+                        if(SiSSouthAdapters[i].nDeviceId == 0x1182 ||
+                           SiSSouthAdapters[i].nDeviceId == 0x1183) {
+                            KdPrint2((PRINT_PREFIX "SIS_182\n"));
                             SIS_182 = TRUE;
                         }
                     }
@@ -817,25 +1019,23 @@ 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;
+                    }
+                    UniataInitIoResEx(&deviceExtension->BaseIoAddressSATA_0, BaseMemAddress, MemIo, FALSE);
 
-                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];
+                        UniataInitIoRes(chan, IDX_SATA_SStatus,  BaseMemAddress + 0 + offs, MemIo, FALSE);
+                        UniataInitIoRes(chan, IDX_SATA_SError,   BaseMemAddress + 4 + offs, MemIo, FALSE);
+                        UniataInitIoRes(chan, IDX_SATA_SControl, BaseMemAddress + 8 + offs, MemIo, FALSE);
 
-                    chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
+                        chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
+                    }
                 }
             }
         }
@@ -853,33 +1053,7 @@ for_ugly_chips:
         if(ChipFlags & UNIATA_SATA) {
 
             ULONG IoSize = 0;
-            ULONG BaseMemAddress = 0;
-
-            /*
-             * 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));
-            }
+            BaseMemAddress = 0;
 
             switch(DeviceID) {
             case 0x3149: // VIA 6420
@@ -899,8 +1073,7 @@ for_ugly_chips:
                     KdPrint2((PRINT_PREFIX "MemIo\n"));
                     MemIo = TRUE;
                 }
-                deviceExtension->BaseIoAddressSATA_0.Addr  = BaseMemAddress;
-                deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo;
+                UniataInitIoResEx(&deviceExtension->BaseIoAddressSATA_0, BaseMemAddress, MemIo, FALSE);
             }
             if(/*deviceExtension->*/BaseMemAddress) {
                 KdPrint2((PRINT_PREFIX "UniataChipDetect: BAR5 %x\n", /*deviceExtension->*/BaseMemAddress));
@@ -921,13 +1094,13 @@ for_ugly_chips:
                         BaseIo = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, c, 0, /*0x80*/ sizeof(IDE_REGISTERS_1) + sizeof(IDE_REGISTERS_2)*2);
 
                         for (i=0; i<=IDX_IO1_SZ; i++) {
-                            chan->RegTranslation[IDX_IO1+i].Addr           = BaseIo + i;
+                            UniataInitIoRes(chan, IDX_IO1+i, BaseIo + i, FALSE, FALSE);
                         }
-                        chan->RegTranslation[IDX_IO2_AltStatus].Addr       = BaseIo + sizeof(IDE_REGISTERS_1) + 2;
+                        UniataInitIoRes(chan, IDX_IO2_AltStatus, BaseIo + sizeof(IDE_REGISTERS_1) + 2, FALSE, FALSE);
                         UniataInitSyncBaseIO(chan);
 
                         for (i=0; i<=IDX_BM_IO_SZ; i++) {
-                            chan->RegTranslation[IDX_BM_IO+i].Addr         = BaseIoAddressBM_0 + sizeof(IDE_BUSMASTER_REGISTERS)*c + i;
+                            UniataInitIoRes(chan, IDX_BM_IO+i, BaseIoAddressBM_0 + sizeof(IDE_BUSMASTER_REGISTERS)*c + i, FALSE, FALSE);
                         }
 
                     }
@@ -937,17 +1110,13 @@ for_ugly_chips:
                     if((ChipFlags & VIABAR) && (c==2)) {
                         // Do not setup SATA registers for PATA part
                         for (i=0; i<=IDX_SATA_IO_SZ; i++) {
-                            chan->RegTranslation[IDX_SATA_IO+i].Addr = 0;
-                            chan->RegTranslation[IDX_SATA_IO+i].MemIo = 0;
+                            UniataInitIoRes(chan, IDX_SATA_IO+i, 0, FALSE, FALSE);
                         }
                         break;
                     }
-                    chan->RegTranslation[IDX_SATA_SStatus].Addr        = BaseMemAddress + (c * IoSize);
-                    chan->RegTranslation[IDX_SATA_SStatus].MemIo       = MemIo;
-                    chan->RegTranslation[IDX_SATA_SError].Addr         = BaseMemAddress + 4 + (c * IoSize);
-                    chan->RegTranslation[IDX_SATA_SError].MemIo        = MemIo;
-                    chan->RegTranslation[IDX_SATA_SControl].Addr       = BaseMemAddress + 8 + (c * IoSize);
-                    chan->RegTranslation[IDX_SATA_SControl].MemIo      = MemIo;
+                    UniataInitIoRes(chan, IDX_SATA_SStatus,  BaseMemAddress + (c * IoSize), MemIo, FALSE);
+                    UniataInitIoRes(chan, IDX_SATA_SError,   BaseMemAddress + 4 + (c * IoSize), MemIo, FALSE);
+                    UniataInitIoRes(chan, IDX_SATA_SControl, BaseMemAddress + 8 + (c * IoSize), MemIo, FALSE);
 
                     chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
                 }
@@ -957,7 +1126,6 @@ for_ugly_chips:
         break; }
     case ATA_INTEL_ID: {
 
-        BOOLEAN IsPata;
         if(!(ChipFlags & UNIATA_SATA)) {
             break;
         }
@@ -969,54 +1137,39 @@ 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;
             }
             deviceExtension->AltRegMap = TRUE; // inform generic resource allocator
-            deviceExtension->BaseIoAddressSATA_0.Addr  = BaseMemAddress;
-            deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo;
+            UniataInitIoResEx(&deviceExtension->BaseIoAddressSATA_0, BaseMemAddress, MemIo, FALSE);
 
             for(c=0; c<deviceExtension->NumberChannels; c++) {
                 ULONG offs = 0x200 + c*0x200;
 
                 chan = &deviceExtension->chan[c];
                 for (i=0; i<=IDX_IO1_SZ; i++) {
-                    chan->RegTranslation[IDX_IO1+i].MemIo          = MemIo;
-                    chan->RegTranslation[IDX_IO1_o+i].MemIo        = MemIo;
+                    UniataInitIoRes(chan, IDX_BM_IO+i, BaseMemAddress + i*4 + offs, MemIo, FALSE);
                 }
 
-                chan->RegTranslation[IDX_IO1_i_Data        ].Addr       = BaseMemAddress + 0x00 + offs;
-                chan->RegTranslation[IDX_IO1_i_Error       ].Addr       = BaseMemAddress + 0x04 + offs;
-                chan->RegTranslation[IDX_IO1_i_BlockCount  ].Addr       = BaseMemAddress + 0x08 + offs;
-                chan->RegTranslation[IDX_IO1_i_BlockNumber ].Addr       = BaseMemAddress + 0x0c + offs;
-                chan->RegTranslation[IDX_IO1_i_CylinderLow ].Addr       = BaseMemAddress + 0x10 + offs;
-                chan->RegTranslation[IDX_IO1_i_CylinderHigh].Addr       = BaseMemAddress + 0x14 + offs;
-                chan->RegTranslation[IDX_IO1_i_DriveSelect ].Addr       = BaseMemAddress + 0x18 + offs;
-                chan->RegTranslation[IDX_IO1_i_Status      ].Addr       = BaseMemAddress + 0x1c + offs;
-
                 UniataInitSyncBaseIO(chan);
 
-                chan->RegTranslation[IDX_IO1_o_Command     ].Addr       = BaseMemAddress + 0x1d + offs;
-                chan->RegTranslation[IDX_IO1_o_Feature     ].Addr       = BaseMemAddress + 0x06 + offs;
-                chan->RegTranslation[IDX_IO2_o_Control     ].Addr       = BaseMemAddress + 0x29 + offs;
+                UniataInitIoRes(chan, IDX_IO1_o_Command, BaseMemAddress + 0x1d + offs, MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_IO1_o_Feature, BaseMemAddress + 0x06 + offs, MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_IO2_o_Control, BaseMemAddress + 0x29 + offs, MemIo, FALSE);
 
-                chan->RegTranslation[IDX_IO2_AltStatus].Addr       = BaseMemAddress + 0x28 + offs;
-                chan->RegTranslation[IDX_IO2_AltStatus].MemIo      = MemIo;
+                UniataInitIoRes(chan, IDX_IO2_AltStatus, BaseMemAddress + 0x28 + offs, MemIo, FALSE);
 
-                chan->RegTranslation[IDX_BM_Command].Addr          = BaseMemAddress + offs + 0x70;
-                chan->RegTranslation[IDX_BM_Command].MemIo         = MemIo;
-                chan->RegTranslation[IDX_BM_Status].Addr           = BaseMemAddress + offs + 0x72;
-                chan->RegTranslation[IDX_BM_Status].MemIo          = MemIo;
-                chan->RegTranslation[IDX_BM_PRD_Table].Addr        = BaseMemAddress + offs + 0x74;
-                chan->RegTranslation[IDX_BM_PRD_Table].MemIo       = MemIo;
+                UniataInitIoRes(chan, IDX_BM_Command,   BaseMemAddress + 0x70 + offs, MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_BM_Status,    BaseMemAddress + 0x72 + offs, MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_BM_PRD_Table, BaseMemAddress + 0x74 + offs, MemIo, FALSE);
 
-                chan->RegTranslation[IDX_SATA_SStatus].Addr        = BaseMemAddress + 0x100 + offs;
-                chan->RegTranslation[IDX_SATA_SStatus].MemIo       = MemIo;
-                chan->RegTranslation[IDX_SATA_SError].Addr         = BaseMemAddress + 0x104 + offs;
-                chan->RegTranslation[IDX_SATA_SError].MemIo        = MemIo;
-                chan->RegTranslation[IDX_SATA_SControl].Addr       = BaseMemAddress + 0x108 + offs;
-                chan->RegTranslation[IDX_SATA_SControl].MemIo      = MemIo;
+                UniataInitIoRes(chan, IDX_SATA_SStatus,  BaseMemAddress + 0x100 + offs, MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_SATA_SError,   BaseMemAddress + 0x104 + offs, MemIo, FALSE);
+                UniataInitIoRes(chan, IDX_SATA_SControl, BaseMemAddress + 0x108 + offs, MemIo, FALSE);
 
                 chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
             }
@@ -1024,33 +1177,81 @@ for_ugly_chips:
             break;
         }
         if(deviceExtension->MaxTransferMode >= ATA_SA150) {
+
+            BOOLEAN OrigAHCI = FALSE;
+
             GetPciConfig1(0x90, tmp8);
             KdPrint2((PRINT_PREFIX "Intel chip config: %x\n", tmp8));
             /* SATA parts can be either compat or AHCI */
+            MemIo = FALSE;
             if(ChipFlags & UNIATA_AHCI) {
-
+                OrigAHCI = TRUE;
                 if(tmp8 & 0xc0) {
                     //KdPrint2((PRINT_PREFIX "AHCI not supported yet\n"));
                     //return FALSE;
                     KdPrint2((PRINT_PREFIX "try run AHCI\n"));
-                    break;
+                    if(ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[5].RangeStart)) {
+                        break;
+                    }
+                    KdPrint2((PRINT_PREFIX "No BAR5, try BM\n"));
+                    deviceExtension->HwFlags &= ~UNIATA_AHCI;
+                }
+                BaseIoAddressBM = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber,
+                                        4, 0, sizeof(IDE_BUSMASTER_REGISTERS));
+                if(BaseIoAddressBM) {
+                    KdPrint2((PRINT_PREFIX "Intel BM check at %x\n", BaseIoAddressBM));
+                    /* check if we really have valid BM registers */
+                    if((*ConfigInfo->AccessRanges)[4].RangeInMemory) {
+                        KdPrint2((PRINT_PREFIX "MemIo[4]\n"));
+                        MemIo = TRUE;
+                    }
+                    UniataInitIoResEx(&deviceExtension->BaseIoAddressBM_0, BaseIoAddressBM, MemIo, FALSE);
+
+                    tmp8 = AtapiReadPortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),IDX_BM_Status);
+                    KdPrint2((PRINT_PREFIX "BM status: %x\n", tmp8));
+                    /* cleanup */
+                    ScsiPortFreeDeviceBase(HwDeviceExtension, (PCHAR)(ULONG_PTR)BaseIoAddressBM);
+                    UniataInitIoResEx(&deviceExtension->BaseIoAddressBM_0, 0, 0, FALSE);
+
+                    if(tmp8 == 0xff) {
+                        KdPrint2((PRINT_PREFIX "invalid BM status, keep AHCI mode\n"));
+                        break;
+                    }
+                }
+                KdPrint2((PRINT_PREFIX "Compatible mode, reallocate LUNs\n"));
+                deviceExtension->NumberLuns = 2; // we may be in Legacy mode
+                if(!UniataAllocateLunExt(deviceExtension, 2)) {
+                    KdPrint2((PRINT_PREFIX "can't re-allocate Luns\n"));
+                    return STATUS_UNSUCCESSFUL;
                 }
-                KdPrint2((PRINT_PREFIX "Compatible mode\n"));
             }
             deviceExtension->HwFlags &= ~UNIATA_AHCI;
 
+            MemIo = FALSE;
             /* if BAR(5) is IO it should point to SATA interface registers */
-            BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber,
+            if(OrigAHCI) {
+                /* Skip BAR(5) in compatible mode */
+                KdPrint2((PRINT_PREFIX "Ignore BAR5 on compatible\n"));
+                BaseMemAddress = 0;
+            } else
+            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[5]\n"));
+                    MemIo = TRUE;
+                }
             }
-            deviceExtension->BaseIoAddressSATA_0.Addr  = BaseMemAddress;
-            deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo;
+            UniataInitIoResEx(&deviceExtension->BaseIoAddressSATA_0, BaseMemAddress, MemIo, FALSE);
 
             for(c=0; c<deviceExtension->NumberChannels; c++) {
                 chan = &deviceExtension->chan[c];
+                AtapiSetupLunPtrs(chan, deviceExtension, c);
                 IsPata = FALSE;
                 if(ChipFlags & ICH5) {
                     KdPrint2((PRINT_PREFIX "ICH5\n"));
@@ -1094,27 +1295,25 @@ for_ugly_chips:
                     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;
-                        chan->RegTranslation[IDX_INDEXED_DATA].MemIo       = MemIo;
+                        UniataInitIoRes(chan, IDX_INDEXED_ADDR,   BaseMemAddress + 0, MemIo, FALSE);
+                        UniataInitIoRes(chan, IDX_INDEXED_DATA,   BaseMemAddress + 4, MemIo, FALSE);
                     }
                     if((ChipFlags & ICH5) || BaseMemAddress) {
 
-                        KdPrint2((PRINT_PREFIX "io indexed\n"));
+                        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;
-                        chan->RegTranslation[IDX_SATA_SStatus].Proc        = 1;
-                        chan->RegTranslation[IDX_SATA_SError].Addr         = 0x200*c + 2;
-                        chan->RegTranslation[IDX_SATA_SError].Proc         = 1;
-                        chan->RegTranslation[IDX_SATA_SControl].Addr       = 0x200*c + 1;
-                        chan->RegTranslation[IDX_SATA_SControl].Proc       = 1;
+                        if(ChipFlags & ICH7) {
+                            KdPrint2((PRINT_PREFIX "ICH7 way\n"));
+                        }
+                        UniataInitIoRes(chan, IDX_SATA_SStatus,  0x200*c + 0, FALSE, TRUE); // this is fake non-zero value
+                        UniataInitIoRes(chan, IDX_SATA_SError,   0x200*c + 2, FALSE, TRUE);
+                        UniataInitIoRes(chan, IDX_SATA_SControl, 0x200*c + 1, FALSE, TRUE);
                     }
                 }
 
@@ -1132,7 +1331,7 @@ for_ugly_chips:
         }
         break;
     case ATA_JMICRON_ID:
-        /* New JMicron PATA controllers */
+        /* New JMicron PATA/SATA controllers */
         GetPciConfig1(0xdf, tmp8);
         if(tmp8 & 0x40) {
             KdPrint(("  Check JMicron AHCI\n"));
@@ -1140,13 +1339,16 @@ for_ugly_chips:
                 ChipFlags |= UNIATA_AHCI;
                 deviceExtension->HwFlags |= UNIATA_AHCI;
             } else {
-                KdPrint(("  JMicron PATA\n"));
+                KdPrint(("  JMicron PATA/SATA\n"));
             }
         } else {
+#if 0 // do not touch, see Linux sources
             /* set controller configuration to a combined setup we support */
             SetPciConfig4(0x40, 0x80c0a131);
             SetPciConfig4(0x80, 0x01200000);
-            //KdPrint(("  JMicron Combined (not supported yet)\n"));
+#endif
+            //GetPciConfig1(0x40, tmp32);
+            KdPrint(("  JMicron Combined\n"));
             //return STATUS_NOT_FOUND;
         }
         break;
@@ -1346,8 +1548,19 @@ hpt_cable80(
     UCHAR reg, val, res;
     PCI_SLOT_NUMBER slotData;
 
+    PHW_CHANNEL chan;
+    ULONG  c; // logical channel (for Compatible Mode controllers)
+
+    c = channel - deviceExtension->Channel; // logical channel (for Compatible Mode controllers)
+    chan = &deviceExtension->chan[c];
+
     slotData.u.AsULONG = deviceExtension->slotNumber;
 
+    if(deviceExtension->HwFlags & UNIATA_NO80CHK) {
+        KdPrint2((PRINT_PREFIX "UNIATA_NO80CHK\n"));
+        return TRUE;
+    }
+
     if(ChipType == HPT374 && slotData.u.bits.FunctionNumber == 1)  {
         reg = channel ? 0x57 : 0x53;
         GetPciConfig1(reg, val);
@@ -1361,10 +1574,15 @@ hpt_cable80(
     GetPciConfig1(0x5a, res);
     res = res & (channel ? 0x01 : 0x02);
     SetPciConfig1(reg, val);
+    if(chan->Force80pin) {
+        KdPrint2((PRINT_PREFIX "Force80pin\n"));
+        res = 0;
+    }
+    KdPrint2((PRINT_PREFIX "hpt_cable80(%d) = %d\n", channel, !res));
     return !res;
 } // end hpt_cable80()
 
-
+/*
 ULONG
 NTAPI
 via_cable80(
@@ -1409,9 +1627,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
@@ -1426,6 +1646,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)
@@ -1434,12 +1659,19 @@ generic_cable80(
     c = channel - deviceExtension->Channel; // logical channel (for Compatible Mode controllers)
     chan = &deviceExtension->chan[c];
 
+    if(chan->Force80pin) {
+        KdPrint2((PRINT_PREFIX "Force80pin\n"));
+        return TRUE;
+    }
+
     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()
 
@@ -1474,21 +1706,73 @@ UniAtaReadLunConfig(
     tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"PreferedTransferMode", 0xffffffff);
     LunExt->opt_PreferedTransferMode = tmp32;
 
+    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, DeviceNumber, L"GeomType", 0xffffffff);
-    if(tmp32 > 2) {
+    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, DeviceNumber, L"Hidden", 0);
     if(tmp32) {
         LunExt->DeviceFlags |= DFLAGS_HIDDEN;
     }
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"Exclude", 0);
+    if(tmp32) {
+        LunExt->DeviceFlags |= DFLAGS_HIDDEN;
+    }
 
     return;
 } // end UniAtaReadLunConfig()
@@ -1538,6 +1822,13 @@ AtapiReadChipConfig(
                 KdPrint2((PRINT_PREFIX "MaxTransferMode (overriden): %#x\n", chan->MaxTransferMode));
                 chan->MaxTransferMode = tmp32;
             }
+            tmp32 = AtapiRegCheckDevValue(deviceExtension, c, DEVNUM_NOT_SPECIFIED, L"Force80pin", FALSE);
+            chan->Force80pin = tmp32 ? TRUE : FALSE;
+            if(chan->Force80pin) {
+                KdPrint2((PRINT_PREFIX "Force80pin on chip\n"));
+                deviceExtension->HwFlags |= UNIATA_NO80CHK;
+            }
+
             //UniAtaReadLunConfig(deviceExtension, c, 0);
             //UniAtaReadLunConfig(deviceExtension, c, 1);
         }
@@ -1569,6 +1860,12 @@ AtapiReadChipConfig(
         tmp32 = AtapiRegCheckDevValue(deviceExtension, c, DEVNUM_NOT_SPECIFIED, L"ReorderEnable", TRUE);
         chan->UseReorder = tmp32 ? TRUE : FALSE;
 
+        tmp32 = AtapiRegCheckDevValue(deviceExtension, c, DEVNUM_NOT_SPECIFIED, L"Force80pin", FALSE);
+        chan->Force80pin = tmp32 ? TRUE : FALSE;
+        if(chan->Force80pin) {
+            KdPrint2((PRINT_PREFIX "Force80pin on channel\n"));
+        }
+
         for(i=0; i<deviceExtension->NumberLuns; i++) {
             UniAtaReadLunConfig(deviceExtension, channel, i);
         }
@@ -1582,19 +1879,17 @@ 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;
+//    BUSMASTER_CONTROLLER_INFORMATION_BASE* DevTypeInfo;
     ULONG ChipType  = deviceExtension->HwFlags & CHIPTYPE_MASK;
     ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK;
     PHW_CHANNEL chan;
@@ -1603,6 +1898,7 @@ AtapiChipInit(
     ULONG  tmp32;
     ULONG  c; // logical channel (for Compatible Mode controllers)
     BOOLEAN CheckCable = FALSE;
+    BOOLEAN GlobalInit = FALSE;
     //ULONG BaseIoAddress;
 
     switch(channel) {
@@ -1611,12 +1907,15 @@ 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));
@@ -1647,6 +1946,27 @@ AtapiChipInit(
         }
     }
 
+    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;
@@ -1744,20 +2064,29 @@ AtapiChipInit(
     case ATA_INTEL_ID: {
         BOOLEAN IsPata;
         USHORT reg54;
-        UCHAR tmp8;
         if(ChipFlags & UNIATA_SATA) {
 
             KdPrint2((PRINT_PREFIX "Intel SATA\n"));
             if(ChipFlags & UNIATA_AHCI) {
                 KdPrint2((PRINT_PREFIX "Do nothing for AHCI\n"));
+                /* enable PCI interrupt */
+                ChangePciConfig2(offsetof(PCI_COMMON_CONFIG, Command), (a & ~0x0400));
                 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 {
 
@@ -1796,30 +2125,35 @@ AtapiChipInit(
                 if(ChipFlags & I6CH2) {
                     KdPrint2((PRINT_PREFIX "I6CH2\n"));
                     chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
-                    chan->lun[0]->SATA_lun_map = c ? 4 : 5;
+                    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;
@@ -1845,7 +2179,7 @@ AtapiChipInit(
 
             break;
         }
-        if(deviceExtension->MaxTransferMode < ATA_UDMA2)
+        if(deviceExtension->MaxTransferMode <= ATA_UDMA2)
             break;
         // check 80-pin cable
         if(c == CHAN_NOT_SPECIFIED) {
@@ -1853,7 +2187,18 @@ 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(deviceExtension->HwFlags & UNIATA_NO80CHK) {
+                KdPrint2((PRINT_PREFIX " No check (administrative)\n"));
+                if(chan->Force80pin) {
+                    KdPrint2((PRINT_PREFIX "Force80pin\n"));
+                }
+            } else
+            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);
             }
         }
@@ -1868,13 +2213,29 @@ AtapiChipInit(
                 AtapiStallExecution(10);
                 KdPrint2((PRINT_PREFIX "BaseIoAddressSATA_0=%x\n", deviceExtension->BaseIoAddressSATA_0.Addr));
                 if(ChipFlags & NVQ) {
+                    KdPrint2((PRINT_PREFIX "Disable NCQ\n"));
+                    tmp32 = AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x0400);
+                    KdPrint2((PRINT_PREFIX "MODE=%#x\n", tmp32));
+                    if(tmp32 & ~0xfffffff9) {
+                        AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x0400, 
+                             tmp32 & 0xfffffff9);
+                    }
+                    ChipFlags &= ~NVQ;
+                    deviceExtension->HwFlags = ChipFlags;
+                }
+                if(ChipFlags & NVQ) {
+                    /* disable  ECO 398 */
+                    ChangePciConfig1(0x7f, (a & ~(1 << 7)));
+
+                    KdPrint2((PRINT_PREFIX "Enable NCQ\n"));
+                    /* enable NCQ support */
+                    AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x0400, 
+                         tmp32 | ~0x00000006);
+
                     /* clear interrupt status */
                     AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs, 0x00ff00ff);
                     /* enable device and PHY state change interrupts */
                     AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4, 0x000d000d);
-                    /* disable NCQ support */
-                    AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x0400, 
-                        AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x0400) & 0xfffffff9);
                 } else {
                     /* clear interrupt status */
                     AtapiWritePortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs, 0xff);
@@ -1943,8 +2304,13 @@ AtapiChipInit(
             break;
         case PRMIO:
             if(c == CHAN_NOT_SPECIFIED) {
-                if(ChipFlags & PRSATA) {
-                    AtapiWritePortEx4(NULL, (ULONGIO_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];
@@ -1978,6 +2344,7 @@ AtapiChipInit(
             KdPrint2((PRINT_PREFIX "ATI\n"));
             break;
         }
+        /* FALLTHROUGH */
     case ATA_SILICON_IMAGE_ID:
   /*      if(ChipFlags & SIIENINTR) {
             SetPciConfig1(0x71, 0x01);
@@ -2048,15 +2415,15 @@ AtapiChipInit(
                 chan = &deviceExtension->chan[c];
                 /* dont block interrupts */
                 //ChangePciConfig4(0x48, (a & ~0x03c00000));
-                tmp32 = AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x48);
+                /*tmp32 =*/ AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x48);
                 AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),0x48, (1 << 22) << c);
                 // flush
-                tmp32 = AtapiReadPortEx4(NULL, (ULONGIO_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 {
@@ -2096,7 +2463,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) {
@@ -2117,10 +2492,13 @@ AtapiChipInit(
                 break;
             case SISSATA:
                 ChangePciConfig2(0x04, (a & ~0x0400));
+                break;
             }
         }
+        if(deviceExtension->HwFlags & UNIATA_SATA) {
+            // do nothing for SATA
+        } else
         if(ChipType == SIS133NEW) {
-            USHORT tmp16;
             // check 80-pin cable
             if(c == CHAN_NOT_SPECIFIED) {
                 // do nothing
@@ -2157,7 +2535,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;
             }
 
@@ -2189,16 +2594,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;
@@ -2225,6 +2633,98 @@ AtapiChipInit(
             }
         } else
         if(ChipType == ITE_133_NEW) {
+        }
+        break;
+    case ATA_CYRIX_ID:
+        KdPrint2((PRINT_PREFIX "Cyrix\n"));
+        if(ChipType == CYRIX_OLD) {
+            if(c == CHAN_NOT_SPECIFIED) {
+                GetPciConfig1(0x60, tmp8);
+                if(!(tmp8 & 0x40)) {
+                    KdPrint2((PRINT_PREFIX "Enable DMA\n"));
+                    tmp8 |= 0x40;
+                    SetPciConfig1(0x60, tmp8);
+                }
+            }
+        }
+        break;
+    case ATA_JMICRON_ID:
+        /* New JMicron PATA controllers */
+        if(deviceExtension->DevID == ATA_JMB361 ||
+           deviceExtension->DevID == ATA_JMB363 ||
+           deviceExtension->DevID == ATA_JMB365 ||
+           deviceExtension->DevID == ATA_JMB366 ||
+           deviceExtension->DevID == ATA_JMB368) { 
+            KdPrint2((PRINT_PREFIX "JMicron\n"));
+
+            ULONG c_swp = 0;
+            ULONG reg40, reg80;
+
+            GetPciConfig4(0x40, reg40);
+            KdPrint2((PRINT_PREFIX "reg 40: %x\n", reg40));
+
+            c_swp = (reg40 & (1<<22)) ? 1 : 0; // 1=swap, 0=keep
+            KdPrint2((PRINT_PREFIX "c_swp: %x\n", c_swp));
+
+            GetPciConfig4(0x80, reg80);
+            KdPrint2((PRINT_PREFIX "reg 80: %x\n", reg80));
+
+            if(c == CHAN_NOT_SPECIFIED) {
+                UCHAR P1mode;
+
+                P1mode = (reg80 & (1<<24)) ? ATA_UDMA6 : ATA_SA300;
+                KdPrint2((PRINT_PREFIX "p1 mode: %x\n", P1mode));
+
+                if(reg40 & (1 << 23)) {
+                    KdPrint2((PRINT_PREFIX "SATA+PATA0\n"));
+                    deviceExtension->chan[0 ^ c_swp].MaxTransferMode = P1mode;
+                    deviceExtension->chan[1 ^ c_swp].MaxTransferMode = ATA_UDMA6;
+                    deviceExtension->chan[1 ^ c_swp].ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
+
+                } else {
+                    KdPrint2((PRINT_PREFIX "SATA+SATA\n"));
+                    deviceExtension->chan[0 ^ c_swp].MaxTransferMode = P1mode;
+                    //deviceExtension->chan[0 ^ c_swp].ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
+                    deviceExtension->chan[1 ^ c_swp].MaxTransferMode = ATA_SA300;
+                    deviceExtension->chan[1 ^ c_swp].ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
+                }
+
+            } else {
+              /*
+                deviceExtension->chan[0 ^ c_swp].lun[0]->SATA_lun_map =
+                deviceExtension->chan[0 ^ c_swp].lun[0]->SATA_lun_map = 0;
+                deviceExtension->chan[1 ^ c_swp].lun[0]->SATA_lun_map =
+                deviceExtension->chan[1 ^ c_swp].lun[0]->SATA_lun_map = 1;
+                */
+                KdPrint2((PRINT_PREFIX "chan %d\n", c));
+                chan = &deviceExtension->chan[c];
+
+                UCHAR ph_channel = (UCHAR)(c ^ c_swp);
+                //c_swp = chan->lun[0]->SATA_lun_map;
+                if(chan->MaxTransferMode >= ATA_SA150) {
+                    KdPrint2((PRINT_PREFIX "SATA, map -> %x\n", ph_channel));
+                } else {
+                    KdPrint2((PRINT_PREFIX "PATA, map -> %x\n", ph_channel));
+                    if(!ph_channel) {
+                        if(!(reg40 & (1<<5))) {
+                            KdPrint2((PRINT_PREFIX "disabled\n", ph_channel));
+                        } else
+                        if(!(reg40 & (1<<3))) {
+                            KdPrint2((PRINT_PREFIX "40-pin\n"));
+                            chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2);
+                        }
+                    } else {
+                        if(!(reg80 & (1<<21))) {
+                            KdPrint2((PRINT_PREFIX "disabled\n", ph_channel));
+                        } else
+                        if(!(reg80 & (1<<19))) {
+                            KdPrint2((PRINT_PREFIX "40-pin\n"));
+                            chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2);
+                        }
+                    }
+                }
+            }
+
         }
         break;
     default:
@@ -2240,7 +2740,8 @@ AtapiChipInit(
 
     // In all places separate channels are inited after common controller init
     // The only exception is probe. But there we may need info about 40/80 pin and MaxTransferRate
-    if(CheckCable && !(ChipFlags & (UNIATA_NO80CHK | UNIATA_SATA))) {
+    // Do not check UNIATA_SATA here since we may have controller with mixed ports
+    if(CheckCable && !(ChipFlags & (UNIATA_NO80CHK/* | UNIATA_SATA*/))) {
         for(c=0; c<deviceExtension->NumberChannels; c++) {
             AtapiChipInit(HwDeviceExtension, DeviceNumber, c);
         }
@@ -2267,13 +2768,13 @@ 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 ? ((ULONGIO_PTR)BaseIoAddressBM_0 + i) : 0;
-            chan->RegTranslation[IDX_BM_IO+i].MemIo = MemIo;
+            UniataInitIoRes(chan, IDX_BM_IO+i, BaseIoAddressBM_0 ? ((ULONGIO_PTR)BaseIoAddressBM_0 + i) : 0, MemIo, FALSE);
         }
         if(BaseIoAddressBM_0) {
             BaseIoAddressBM_0++;
         }
     }
+    return;
 } // end UniataInitMapBM()
 
 VOID
@@ -2287,14 +2788,13 @@ UniataInitMapBase(
     ULONG i;
 
     for (i=0; i<IDX_IO1_SZ; i++) {
-        chan->RegTranslation[IDX_IO1+i].Addr = BaseIoAddress1 ? ((ULONGIO_PTR)BaseIoAddress1 + i) : 0;
-        chan->RegTranslation[IDX_IO1+i].MemIo = FALSE;
+        UniataInitIoRes(chan, IDX_IO1+i, BaseIoAddress1 ? ((ULONGIO_PTR)BaseIoAddress1 + i) : 0, FALSE, FALSE);
     }
     for (i=0; i<IDX_IO2_SZ; i++) {
-        chan->RegTranslation[IDX_IO2+i].Addr = BaseIoAddress2 ? ((ULONGIO_PTR)BaseIoAddress2 + i) : 0;
-        chan->RegTranslation[IDX_IO2+i].MemIo = FALSE;
+        UniataInitIoRes(chan, IDX_IO2+i, BaseIoAddress2 ? ((ULONGIO_PTR)BaseIoAddress2 + i) : 0, FALSE, FALSE);
     }
     UniataInitSyncBaseIO(chan);
+    return;
 } // end UniataInitMapBase()
 
 VOID
@@ -2305,8 +2805,42 @@ 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
+UniataInitIoRes(
+    IN PHW_CHANNEL chan,
+    IN ULONG idx,
+    IN ULONG addr,
+    IN BOOLEAN MemIo,
+    IN BOOLEAN Proc
+    )
+{
+    if(!addr) {
+        MemIo = Proc = FALSE;
+    }
+    chan->RegTranslation[idx].Addr  = addr;
+    chan->RegTranslation[idx].MemIo = MemIo;
+    chan->RegTranslation[idx].Proc  = Proc;
+} // end UniataInitIoRes()
+
+VOID
+UniataInitIoResEx(
+    IN PIORES IoRes,
+    IN ULONG addr,
+    IN BOOLEAN MemIo,
+    IN BOOLEAN Proc
+    )
+{
+    if(!addr) {
+        MemIo = Proc = FALSE;
+    }
+    IoRes->Addr  = addr;
+    IoRes->MemIo = MemIo;
+    IoRes->Proc  = Proc;
+} // end UniataInitIoResEx()
+
 VOID
 NTAPI
 AtapiSetupLunPtrs(
@@ -2317,21 +2851,129 @@ AtapiSetupLunPtrs(
 {
     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;
+    chan->last_devsel     = -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()
+