/*++

Copyright (c) 2002-2005 Alexandr A. Telyatnikov (Alter)

Module Name:
    id_probe.cpp

Abstract:
    This module scans PCI and ISA buses for IDE controllers
    and determines their Busmaster DMA capabilities

Author:
    Alexander A. Telyatnikov (Alter)

Environment:
    kernel mode only

Notes:

    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Revision History:

    Some parts of hardware-specific code were taken from FreeBSD 4.3 ATA driver by
         Søren Schmidt, Copyright (c) 1998,1999,2000,2001

    Some parts of device detection code were taken from from standard ATAPI.SYS from NT4 DDK by
         Mike Glass (MGlass)
         Chuck Park (ChuckP)

    Device search/init algorithm is completly rewritten by
         Alter, Copyright (c) 2002-2004

    Fixes for Native/Compatible modes of onboard IDE controller by
         Vitaliy Vorobyov, deathsoft@yandex.ru (c) 2004

--*/

extern "C" {

#include <ntddk.h>
//#include "miniport.h"

};
#include "stddef.h"

#include "atapi.h"               // includes scsi.h
#include "ntdddisk.h"
#include "ntddscsi.h"
#include "bsmaster.h"

UCHAR         pciBuffer[256];
PBUSMASTER_CONTROLLER_INFORMATION BMList = NULL;
ULONG         BMListLen = 0;
ULONG         maxPciBus = 16;
PDRIVER_OBJECT SavedDriverObject = NULL;

BOOLEAN FirstMasterOk = FALSE;

// local routines 

ULONG
AtapiEnumBusMasterController__(
/*    IN PVOID HwDeviceExtension,
    IN PVOID Context,
    IN PVOID BusInformation,
    IN PCHAR ArgumentString,
    IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
    OUT PBOOLEAN Again*/
    );

VOID
AtapiDoNothing(VOID)
{
    ULONG i = 0;
    return;
} // end AtapiDoNothing()

/*
    Get PCI address by ConfigInfo and RID
*/
ULONG
AtapiGetIoRange(
    IN PVOID HwDeviceExtension,
    IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
    IN PPCI_COMMON_CONFIG pciData,
    IN ULONG SystemIoBusNumber,
    IN ULONG rid,   //range id
    IN ULONG offset,
    IN ULONG length
    )
{
    ULONG io_start = 0;
    KdPrint2((PRINT_PREFIX "  AtapiGetIoRange:\n"));

    if(ConfigInfo->NumberOfAccessRanges <= rid)
        return 0;

    KdPrint2((PRINT_PREFIX "  AtapiGetIoRange: rid %#x, start %#x, offs %#x, len %#x, mem %#x\n",
        rid,
        ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[rid].RangeStart),
        offset,
        length,
        (*ConfigInfo->AccessRanges)[rid].RangeInMemory
        ));

    io_start =
        // Get the system physical address for this IO range.
        ((ULONG)ScsiPortGetDeviceBase(HwDeviceExtension,
                    PCIBus /*ConfigInfo->AdapterInterfaceType*/,
                    SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/,
                    ScsiPortConvertUlongToPhysicalAddress(
                        (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[rid].RangeStart) &
                        ~0x07/*PCI_ADDRESS_IOMASK*/) + offset
                                                         ),
                    length,
                    (BOOLEAN)!(*ConfigInfo->AccessRanges)[rid].RangeInMemory) 
                           );

    KdPrint2((PRINT_PREFIX "  AtapiGetIoRange: %#x\n", io_start));
    if(io_start > offset) {
        return io_start;
    }

    io_start = (pciData->u.type0.BaseAddresses[rid] & ~0x07/*PCI_ADDRESS_IOMASK*/) + offset;
    if(io_start > offset) {
        if((WinVer_Id() <= WinVer_NT) && offset && rid == 4) {
            // MS atapi.sys does so for BusMaster controllers
            (*ConfigInfo->AccessRanges)[rid+1].RangeStart =
                ScsiPortConvertUlongToPhysicalAddress(io_start);
            (*ConfigInfo->AccessRanges)[rid+1].RangeLength = length;
        } else {
            (*ConfigInfo->AccessRanges)[rid].RangeStart =
                ScsiPortConvertUlongToPhysicalAddress(io_start);
            (*ConfigInfo->AccessRanges)[rid].RangeLength = length;
        }
    } else {
        io_start = 0;
    }
    KdPrint2((PRINT_PREFIX "  AtapiGetIoRange: (2) %#x\n", io_start));
    return io_start;

} // end AtapiGetIoRange()

/*
    Do nothing, but build list of supported IDE controllers
    It is a hack, ScsiPort architecture assumes, that DriverEntry
    can support only KNOWN Vendor/Device combinations.
    Thus, we build list here. Later will pretend that always knew
    about found devices.

    We shall initiate ISA device init, but callback will use
    Hal routines directly in order to scan PCI bus.
*/
VOID
AtapiEnumBusMasterController(
    IN PVOID DriverObject,
    PVOID Argument2
    )
{
/*    HW_INITIALIZATION_DATA hwInitializationData;

    // Zero out structure.
    RtlZeroMemory(((PCHAR)&hwInitializationData), sizeof(HW_INITIALIZATION_DATA));

    // Set size of hwInitializationData.
    hwInitializationData.HwInitializationDataSize =
      sizeof(HW_INITIALIZATION_DATA);

    // Set entry points.
    hwInitializationData.HwInitialize = AtapiHwInitialize;
    hwInitializationData.HwResetBus = AtapiResetController;
    hwInitializationData.HwStartIo = AtapiStartIo;
    hwInitializationData.HwInterrupt = AtapiInterrupt;

    // Specify size of extensions.
    hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
    hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION);

    // Indicate PIO device.
    hwInitializationData.MapBuffers = TRUE;

    hwInitializationData.HwFindAdapter = AtapiEnumBusMasterController__;
    hwInitializationData.NumberOfAccessRanges = 4;
    hwInitializationData.AdapterInterfaceType = Isa;

    KdPrint2((PRINT_PREFIX "\n\nATAPI IDE Look for PCI Controllers\n"));
    ScsiPortInitialize(DriverObject,
                       Argument2,
                       &hwInitializationData,
                       NULL);*/

    AtapiEnumBusMasterController__();

} // end AtapiEnumBusMasterController()


/*
    Device initializaton callback
    Builds PCI device list using Hal routines (not ScsiPort wrappers)
*/
ULONG
AtapiEnumBusMasterController__(
/*    IN PVOID HwDeviceExtension,
    IN PVOID Context,
    IN PVOID BusInformation,
    IN PCHAR ArgumentString,
    IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
    OUT PBOOLEAN Again*/
    )
{
//    PHW_DEVICE_EXTENSION  deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
    PVOID HwDeviceExtension;
    PHW_DEVICE_EXTENSION  deviceExtension = NULL;
    PCI_SLOT_NUMBER       slotData;
    PCI_COMMON_CONFIG     pciData;
    ULONG                 busNumber;
    ULONG                 slotNumber;
    ULONG                 funcNumber;
    BOOLEAN               no_buses = FALSE;
    BOOLEAN               no_ranges = FALSE;
    ULONG                 busDataRead;
//    BOOLEAN               SimplexOnly;

    UCHAR                 vendorString[5];
    UCHAR                 deviceString[5];
    PUCHAR                vendorStrPtr;
    PUCHAR                deviceStrPtr;

    UCHAR   BaseClass;                  // (ro)
    UCHAR   SubClass;                   // (ro)
    ULONG   VendorID;
    ULONG   DeviceID;
    ULONG   dev_id;

    ULONG   i;
    ULONG   pass=0;

    ULONG   RaidFlags;

    BOOLEAN found;
    BOOLEAN known;

    UCHAR IrqForCompat = 10;

    vendorStrPtr = vendorString;
    deviceStrPtr = deviceString;
    slotData.u.AsULONG = 0;

    HwDeviceExtension =
    deviceExtension = (PHW_DEVICE_EXTENSION)ExAllocatePool(NonPagedPool, sizeof(HW_DEVICE_EXTENSION));
    if(!deviceExtension) {
        return(SP_RETURN_NOT_FOUND);
    }
    RtlZeroMemory(deviceExtension, sizeof(HW_DEVICE_EXTENSION));

    for(pass=0; pass<3; pass++) {
        for(busNumber=0 ;busNumber<maxPciBus && !no_buses; busNumber++) {
            for(slotNumber=0; slotNumber<PCI_MAX_DEVICES  && !no_buses; slotNumber++) {
            for(funcNumber=0; funcNumber<PCI_MAX_FUNCTION && !no_buses; funcNumber++) {
                
//                KdPrint2((PRINT_PREFIX "-- BusID: %#x:%#x:%#x\n",busNumber,slotNumber,funcNumber));
                slotData.u.bits.DeviceNumber   = slotNumber;
                slotData.u.bits.FunctionNumber = funcNumber;

                busDataRead = HalGetBusData
                              //ScsiPortGetBusData
                                           (
                                            //HwDeviceExtension,
                                            PCIConfiguration, busNumber, slotData.u.AsULONG, 
                                            &pciData, PCI_COMMON_HDR_LENGTH);
                // no more buses
                if(!busDataRead) {
                    no_buses = TRUE;
                    maxPciBus = busNumber;
                    break;
                }
                // no device in this slot
                if(busDataRead == 2)
                    continue;

                if(busDataRead < PCI_COMMON_HDR_LENGTH)
                    continue;

                VendorID  = pciData.VendorID;
                DeviceID  = pciData.DeviceID;
                BaseClass = pciData.BaseClass;
                SubClass  = pciData.SubClass;
                dev_id = VendorID | (DeviceID << 16);
                //KdPrint2((PRINT_PREFIX "DevId = %8.8X Class = %4.4X/%4.4X\n", dev_id, BaseClass, SubClass ));

                if(BaseClass != PCI_DEV_CLASS_STORAGE)
                    continue;

                KdPrint2((PRINT_PREFIX "Storage Class\n"));
                KdPrint2((PRINT_PREFIX "DevId = %8.8X Class = %4.4X/%4.4X\n", dev_id, BaseClass, SubClass ));
                // look for known chipsets
                found = FALSE;
                known = FALSE;

                if(deviceExtension) {
                    deviceExtension->slotNumber = slotData.u.AsULONG;
                    deviceExtension->SystemIoBusNumber = busNumber;
                    deviceExtension->DevID = dev_id;
                    deviceExtension->RevID = pciData.RevisionID;
                }

                found = (BOOLEAN)AtapiRegCheckDevValue(deviceExtension, -1, -1, L"Include", 0);
                if(!found) {
                    KdPrint2((PRINT_PREFIX "No force include, check exclude\n"));
                    found = !AtapiRegCheckDevValue(deviceExtension, -1, -1, L"Exclude", 0);
                    if(!found) {
                        KdPrint2((PRINT_PREFIX "Device excluded\n"));
                        continue;
                    }
                }

                //known = AtapiChipDetect(HwDeviceExtension, NULL, -1, ConfigInfo, &SimplexOnly);
                i = Ata_is_dev_listed((PBUSMASTER_CONTROLLER_INFORMATION)&BusMasterAdapters[0], VendorID, DeviceID, 0, NUM_BUSMASTER_ADAPTERS);

                known = (i != -1);
                if(known) {
                    RaidFlags = BusMasterAdapters[i].RaidFlags;
                    if((RaidFlags & UNIATA_RAID_CONTROLLER) &&
                        SkipRaids) {
                        KdPrint2((PRINT_PREFIX "Skip RAID\n"));
                        continue;
                    }
                    found = TRUE;
                } else {
                    RaidFlags = 0;
                }

                switch(dev_id) {
                /* additional checks for some supported chipsets */
                case 0xc6931080:
                    if (SubClass != PCI_DEV_SUBCLASS_IDE)
                        found = FALSE;
                    break;

                /* unknown chipsets, try generic DMA if it seems possible */
                default:
                    KdPrint2((PRINT_PREFIX "Default device\n"));
                    if(Ata_is_supported_dev(&pciData))
                        found = TRUE;
                    break;
                }

                if(found) {

                    KdPrint2((PRINT_PREFIX "found, pass %d\n", pass));

                    KdPrint2((PRINT_PREFIX "InterruptPin = %#x\n", pciData.u.type0.InterruptPin));
                    KdPrint2((PRINT_PREFIX "InterruptLine = %#x\n", pciData.u.type0.InterruptLine));

                    if(!pass) {
                        // Enable Busmastering, IO-space and Mem-space
                        KdPrint2((PRINT_PREFIX "Enabling Mem/Io spaces and busmastering...\n"));
                        KdPrint2((PRINT_PREFIX "Initial pciData.Command = %#x\n", pciData.Command));
                        for(i=0; i<3; i++) {
                            switch(i) {
                            case 0:
                                KdPrint2((PRINT_PREFIX "PCI_ENABLE_IO_SPACE\n"));
                                pciData.Command |= PCI_ENABLE_IO_SPACE;
                                break;
                            case 1:
                                KdPrint2((PRINT_PREFIX "PCI_ENABLE_MEMORY_SPACE\n"));
                                pciData.Command |= PCI_ENABLE_MEMORY_SPACE;
                                break;
                            case 2:
                                KdPrint2((PRINT_PREFIX "PCI_ENABLE_BUS_MASTER\n"));
                                pciData.Command |= PCI_ENABLE_BUS_MASTER;
                                break;
                            }
                            HalSetBusDataByOffset(  PCIConfiguration, busNumber, slotData.u.AsULONG, 
                                                    &(pciData.Command),
                                                    offsetof(PCI_COMMON_CONFIG, Command),
                                                    sizeof(pciData.Command));
                            KdPrint2((PRINT_PREFIX "InterruptLine = %#x\n", pciData.u.type0.InterruptLine));

                            // reread config space
                            busDataRead = HalGetBusData(PCIConfiguration, busNumber, slotData.u.AsULONG, 
                                                        &pciData, PCI_COMMON_HDR_LENGTH);
                            KdPrint2((PRINT_PREFIX "New pciData.Command = %#x\n", pciData.Command));
                        }
                        KdPrint2((PRINT_PREFIX "Final pciData.Command = %#x\n", pciData.Command));
                    }
                    // validate Mem/Io ranges
                    no_ranges = TRUE;
                    for(i=0; i<PCI_TYPE0_ADDRESSES; i++) {
                        if(pciData.u.type0.BaseAddresses[i] & ~0x7) {
                            no_ranges = FALSE;
                            //break;
                            KdPrint2((PRINT_PREFIX "Range %d = %#x\n", i, pciData.u.type0.BaseAddresses[i]));
                        }
                    }
                    if(no_ranges) {
                        KdPrint2((PRINT_PREFIX "No PCI Mem/Io ranges found on device, skip it\n"));
                        continue;
                    }
                    
                    if(pass) {
                        // fill list of detected devices
                        // it'll be used for further init
                        KdPrint2((PRINT_PREFIX "found suitable device\n"));
                        PBUSMASTER_CONTROLLER_INFORMATION newBMListPtr = BMList+BMListLen;

                        if(pass == 1) {
                            if(!IsMasterDev(&pciData))
                                continue;
                            if(AtapiRegCheckDevValue(deviceExtension, -1, -1, L"NativePCIMode", 0)) {
                                KdPrint2((PRINT_PREFIX "try switch to native mode\n"));

                                IrqForCompat = (UCHAR)AtapiRegCheckDevValue(deviceExtension, -1, -1, L"NativePCIModeIRQ", 0xff);
                                KdPrint2((PRINT_PREFIX "IrqForCompat = %#x\n", IrqForCompat));
                                if((IrqForCompat & 0xffffff00) /*||
                                   (IrqForCompat & 0xff) > 31*/ ||
                                   (IrqForCompat == 0xff)) {
                                    IrqForCompat = 0x0b;
                                    KdPrint2((PRINT_PREFIX "default to IRQ 11\n"));
                                }

                                //ChangePciConfig1(0x09, a | PCI_IDE_PROGIF_NATIVE_ALL); // ProgIf
                                pciData.ProgIf |= PCI_IDE_PROGIF_NATIVE_ALL;
                                HalSetBusDataByOffset(  PCIConfiguration, busNumber, slotData.u.AsULONG, 
                                                        &(pciData.ProgIf),
                                                        offsetof(PCI_COMMON_CONFIG, ProgIf),
                                                        sizeof(pciData.ProgIf));

                                // reread config space
                                busDataRead = HalGetBusData(PCIConfiguration, busNumber, slotData.u.AsULONG, 
                                                            &pciData, PCI_COMMON_HDR_LENGTH);
                                // check if the device have switched to Native Mode
                                if(IsMasterDev(&pciData)) {
                                    KdPrint2((PRINT_PREFIX "Can't switch to native mode\n"));
                                } else {
                                    KdPrint2((PRINT_PREFIX "switched to native mode\n"));
                                    KdPrint2((PRINT_PREFIX "InterruptPin = %#x\n", pciData.u.type0.InterruptPin));
                                    KdPrint2((PRINT_PREFIX "InterruptLine = %#x\n", pciData.u.type0.InterruptLine));
                                    // check if IRQ is assigned to device
                                    if(!(pciData.u.type0.InterruptLine) ||
                                        (pciData.u.type0.InterruptLine == 0xff)) {
                                        KdPrint2((PRINT_PREFIX "assign interrupt for device\n"));
                                        pciData.u.type0.InterruptLine = IrqForCompat;
                                        HalSetBusDataByOffset(  PCIConfiguration, busNumber, slotData.u.AsULONG, 
                                                                &(pciData.u.type0.InterruptLine),
                                                                offsetof(PCI_COMMON_CONFIG, u.type0.InterruptLine),
                                                                sizeof(pciData.u.type0.InterruptLine));
                                    } else {
                                        KdPrint2((PRINT_PREFIX "Auto-assigned interrupt line %#x\n",
                                            pciData.u.type0.InterruptLine));
                                        IrqForCompat = pciData.u.type0.InterruptLine;
                                    }
                                    KdPrint2((PRINT_PREFIX "reread config space\n"));
                                    // reread config space
                                    busDataRead = HalGetBusData(PCIConfiguration, busNumber, slotData.u.AsULONG, 
                                                                &pciData, PCI_COMMON_HDR_LENGTH);
                                    KdPrint2((PRINT_PREFIX "busDataRead = %#x\n", busDataRead));
                                    KdPrint2((PRINT_PREFIX "reread InterruptLine = %#x\n", pciData.u.type0.InterruptLine));
                                    // check if we have successfully assigned IRQ to device
                                    if((pciData.u.type0.InterruptLine != IrqForCompat) ||
                                       (pciData.u.type0.InterruptLine == 0xff) ||
                                       !pciData.u.type0.InterruptLine) {
                                        KdPrint2((PRINT_PREFIX "can't assign interrupt for device, revert to compat mode\n"));
                                        pciData.u.type0.InterruptLine = 0xff;
                                        KdPrint2((PRINT_PREFIX "set IntrLine to 0xff\n"));
                                        HalSetBusDataByOffset(  PCIConfiguration, busNumber, slotData.u.AsULONG, 
                                                                &(pciData.u.type0.InterruptLine),
                                                                offsetof(PCI_COMMON_CONFIG, u.type0.InterruptLine),
                                                                sizeof(pciData.u.type0.InterruptLine));
                                        KdPrint2((PRINT_PREFIX "clear PCI_IDE_PROGIF_NATIVE_ALL\n"));
                                        pciData.ProgIf &= ~PCI_IDE_PROGIF_NATIVE_ALL;
                                        HalSetBusDataByOffset(  PCIConfiguration, busNumber, slotData.u.AsULONG, 
                                                                &(pciData.ProgIf),
                                                                offsetof(PCI_COMMON_CONFIG, ProgIf),
                                                                sizeof(pciData.ProgIf));
                                        // reread config space
                                        KdPrint2((PRINT_PREFIX "reread config space on revert\n"));
                                        busDataRead = HalGetBusData(PCIConfiguration, busNumber, slotData.u.AsULONG, 
                                                                    &pciData, PCI_COMMON_HDR_LENGTH);
                                    } else {
                                        KdPrint2((PRINT_PREFIX "Assigned interrupt %#x for device\n", IrqForCompat));
                                        KdPrint2((PRINT_PREFIX "continue detection on next round\n"));
                                        continue;
                                    }
                                }
                            }
                        } else
                        if(pass == 2) {
                            if(IsMasterDev(&pciData))
                                continue;
                        }

/*                        if(known) {
                            RtlCopyMemory(newBMListPtr, (PVOID)&(BusMasterAdapters[i]), sizeof(BUSMASTER_CONTROLLER_INFORMATION));
                        } else {*/
                        sprintf((PCHAR)vendorStrPtr, "%4.4x", VendorID);
                        sprintf((PCHAR)deviceStrPtr, "%4.4x", DeviceID);

                        RtlCopyMemory(&(newBMListPtr->VendorIdStr), (PCHAR)vendorStrPtr, 4);
                        RtlCopyMemory(&(newBMListPtr->DeviceIdStr), (PCHAR)deviceStrPtr, 4);
                        
                        newBMListPtr->nVendorId = VendorID;
                        newBMListPtr->VendorId = (PCHAR)&(newBMListPtr->VendorIdStr);
                        newBMListPtr->VendorIdLength = 4;
                        newBMListPtr->nDeviceId = DeviceID;
                        newBMListPtr->DeviceId = (PCHAR)&(newBMListPtr->DeviceIdStr);
                        newBMListPtr->DeviceIdLength = 4;

                        newBMListPtr->RaidFlags = RaidFlags;
//                        }
                        newBMListPtr->slotNumber = slotData.u.AsULONG;
                        newBMListPtr->MasterDev = IsMasterDev(&pciData) ? 1 : 0;
                        newBMListPtr->busNumber = busNumber;

                        KdPrint2((PRINT_PREFIX "Add to BMList\n"));
                    } else {
                        KdPrint2((PRINT_PREFIX "count: BMListLen++\n"));
                    }

                    BMListLen++;
                }
            }
            }
        }
        if(!pass) {
             if(!BMListLen)
                 break;
             BMList = (PBUSMASTER_CONTROLLER_INFORMATION)ExAllocatePool(NonPagedPool, 
                                         (BMListLen+1)*sizeof(BUSMASTER_CONTROLLER_INFORMATION));
             if(!BMList) {
                 BMListLen=0;
                 break;
             }
             RtlZeroMemory(BMList, (BMListLen+1)*sizeof(BUSMASTER_CONTROLLER_INFORMATION));
             no_buses = FALSE;
             BMListLen=0;
        }
    }
    if(deviceExtension) {
        ExFreePool(deviceExtension);
    }
    return(SP_RETURN_NOT_FOUND);
} // end AtapiEnumBusMasterController__()


/*
    Wrapper for read PCI config space
*/
ULONG 
ScsiPortGetBusDataByOffset(
    IN PVOID  HwDeviceExtension,
    IN BUS_DATA_TYPE  BusDataType,
    IN ULONG  BusNumber,
    IN ULONG  SlotNumber,
    IN PVOID  Buffer,
    IN ULONG  Offset,
    IN ULONG  Length
    )
{
    UCHAR tmp[256];
    ULONG busDataRead;

    if(Offset+Length > 256)
        return 0;

    busDataRead = ScsiPortGetBusData(HwDeviceExtension,
                                     BusDataType,
                                     BusNumber,
                                     SlotNumber,
                                     &tmp,
                                     Offset+Length);
    if(busDataRead < Offset+Length) {
        if(busDataRead < Offset)
            return 0;
        return (Offset+Length-busDataRead);
    }
    RtlCopyMemory(Buffer, tmp+Offset, Length);
    return Length;
} // end ScsiPortGetBusDataByOffset()

/*
    Looks for devices from list on specified bus(es)/slot(s)
    returnts its index in list.
    If no matching record found, -1 is returned
*/
ULONG
AtapiFindListedDev(
    PBUSMASTER_CONTROLLER_INFORMATION BusMasterAdapters,
    ULONG     lim,
    IN PVOID  HwDeviceExtension,
    IN ULONG  BusNumber,
    IN ULONG  SlotNumber,
    OUT PCI_SLOT_NUMBER* _slotData // optional
    )
{
    PCI_SLOT_NUMBER       slotData;
    PCI_COMMON_CONFIG     pciData;
    ULONG                 busDataRead;

    ULONG busNumber;
    ULONG slotNumber;
    ULONG funcNumber;

    ULONG busNumber2;
    ULONG slotNumber2;

    ULONG i;

    // set start/end bus
    if(BusNumber == -1) {
        busNumber  = 0;
        busNumber2 = maxPciBus;
    } else {
        busNumber  = BusNumber;
        busNumber2 = BusNumber+1;
    }
    // set start/end slot
    if(SlotNumber == -1) {
        slotNumber  = 0;
        slotNumber2 = PCI_MAX_DEVICES;
    } else {
        slotNumber  = SlotNumber;
        slotNumber2 = SlotNumber+1;
    }
    slotData.u.AsULONG = 0;

    for(            ; busNumber  < busNumber2       ; busNumber++ ) {
    for(            ; slotNumber < slotNumber2      ; slotNumber++) {
    for(funcNumber=0; funcNumber < PCI_MAX_FUNCTION ; funcNumber++) {

        slotData.u.bits.DeviceNumber   = slotNumber;
        slotData.u.bits.FunctionNumber = funcNumber;

        busDataRead = ScsiPortGetBusData(HwDeviceExtension,
                                    PCIConfiguration, busNumber, slotData.u.AsULONG, 
                                    &pciData, PCI_COMMON_HDR_LENGTH);
        // no more buses (this should not happen)
        if(!busDataRead) {
            continue;
        }
        // no device in this slot
        if(busDataRead == 2)
            continue;

        if(busDataRead < PCI_COMMON_HDR_LENGTH)
            continue;

        i = Ata_is_dev_listed(BusMasterAdapters, pciData.VendorID, pciData.DeviceID, pciData.RevisionID, lim);
        if(i != -1) {
            if(_slotData)
                *_slotData = slotData;
            return i;
        }

    }}}
    return -1;
} // end AtapiFindListedDev()

/*
    Looks for device with specified Device/Vendor and Revision
    on specified Bus/Slot
*/
ULONG
AtapiFindDev(
    IN PVOID  HwDeviceExtension,
    IN BUS_DATA_TYPE  BusDataType,
    IN ULONG  BusNumber,
    IN ULONG  SlotNumber,
    IN ULONG  dev_id,
    IN ULONG  RevID
    )
{
    PCI_COMMON_CONFIG     pciData;
    ULONG                 funcNumber;
    ULONG                 busDataRead;

    ULONG   VendorID;
    ULONG   DeviceID;
    PCI_SLOT_NUMBER       slotData;

    slotData.u.AsULONG = SlotNumber;
    // walk through all Function Numbers
    for(funcNumber = 0; funcNumber < PCI_MAX_FUNCTION; funcNumber++) {
        
        slotData.u.bits.FunctionNumber = funcNumber;
        if(slotData.u.AsULONG == SlotNumber)
            continue;

        busDataRead = ScsiPortGetBusData(HwDeviceExtension,
                                         PCIConfiguration,
                                         BusNumber,
                                         slotData.u.AsULONG,
                                         &pciData,
                                         PCI_COMMON_HDR_LENGTH);

        if (busDataRead < PCI_COMMON_HDR_LENGTH) {
            continue;
        }

        VendorID  = pciData.VendorID;
        DeviceID  = pciData.DeviceID;

        if(dev_id != (VendorID | (DeviceID << 16)) )
            continue;
        if(RevID >= pciData.RevisionID)
            return 1;
    }
    return 0;
} // end AtapiFindDev()

/*++

Routine Description:

    This function is called by the OS-specific port driver after
    the necessary storage has been allocated, to gather information
    about the adapter's configuration.

Arguments:

    HwDeviceExtension - HBA miniport driver's adapter data storage
    Context - Address of adapter count
    BusInformation -
    ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility.
    ConfigInfo - Configuration information structure describing HBA
    Again - Indicates search for adapters to continue

Return Value:

    ULONG

--*/
ULONG
AtapiFindBusMasterController(
    IN PVOID HwDeviceExtension,
    IN PVOID Context,
    IN PVOID BusInformation,
    IN PCHAR ArgumentString,
    IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
    OUT PBOOLEAN Again
    )
{
    PHW_DEVICE_EXTENSION  deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
    PHW_CHANNEL           chan = NULL;
    PCI_COMMON_CONFIG     pciData;
    ULONG                 slotNumber;
    ULONG                 busDataRead;
    ULONG                 SystemIoBusNumber;

    UCHAR                 vendorString[5];
    UCHAR                 deviceString[5];
    PUCHAR                vendorStrPtr;
    PUCHAR                deviceStrPtr;

    UCHAR   BaseClass;
    UCHAR   SubClass;
    ULONG   VendorID;
    ULONG   DeviceID;
    ULONG   RevID;
    ULONG   dev_id;
    PCI_SLOT_NUMBER       slotData;

    ULONG   i;
    ULONG   channel;
    ULONG   c = 0;
    PUCHAR  ioSpace;
    UCHAR   statusByte;
    ULONG   bm_offset;

//    UCHAR   tmp8;
//    ULONG   irq;

    BOOLEAN found = FALSE;
    BOOLEAN MasterDev;
    BOOLEAN simplexOnly = FALSE;
    BOOLEAN skip_find_dev = FALSE;
    BOOLEAN AltInit = FALSE;

    SCSI_PHYSICAL_ADDRESS IoBasePort1;
    SCSI_PHYSICAL_ADDRESS IoBasePort2;

    NTSTATUS status;
    PPORT_CONFIGURATION_INFORMATION_COMMON _ConfigInfo =
        (PPORT_CONFIGURATION_INFORMATION_COMMON)ConfigInfo;

    *Again = FALSE;

    if(ForceSimplex) {
        KdPrint2((PRINT_PREFIX "ForceSimplex (1)\n"));
        simplexOnly = TRUE;
    }

    if(InDriverEntry) {
        i = (ULONG)Context;
        if(i & 0x80000000) {
            AltInit = TRUE;
        }
        i &= ~0x80000000;
        channel   = BMList[i].channel;
    } else {
        for(i=0; i<BMListLen; i++) {
            if(BMList[i].slotNumber == ConfigInfo->SlotNumber &&
               BMList[i].busNumber  == ConfigInfo->SystemIoBusNumber) {
                break;
            }
        }
        if(i >= BMListLen) {
            KdPrint2((PRINT_PREFIX "unexpected device arrival => SP_RETURN_NOT_FOUND\n"));
            return(SP_RETURN_NOT_FOUND);
        }
        channel = 0;
    }

    bm_offset = channel ? ATA_BM_OFFSET1 : 0;

//    PORT_CONFIGURATION_INFORMATION SavedConfigInfo = *ConfigInfo;

    KdPrint2((PRINT_PREFIX "AtapiFindBusMasterController\n"));

    if (!deviceExtension) {
        KdPrint2((PRINT_PREFIX "!deviceExtension => SP_RETURN_ERROR\n"));
        return SP_RETURN_ERROR;
    }

    RtlZeroMemory(deviceExtension, sizeof(HW_DEVICE_EXTENSION));

    vendorStrPtr = vendorString;
    deviceStrPtr = deviceString;

    slotNumber = BMList[i].slotNumber;
    SystemIoBusNumber = BMList[i].busNumber;

    KdPrint2((PRINT_PREFIX "IoBusNumber=%#x\n",ConfigInfo->SystemIoBusNumber));
    KdPrint2((PRINT_PREFIX "slotNumber=%#x\n",slotNumber));

    busDataRead = ScsiPortGetBusData(HwDeviceExtension,
                                     PCIConfiguration,
                                     SystemIoBusNumber,
                                     slotNumber,
                                     &pciData,
                                     PCI_COMMON_HDR_LENGTH);

    if (busDataRead < PCI_COMMON_HDR_LENGTH) {
        KdPrint2((PRINT_PREFIX "busDataRead < PCI_COMMON_HDR_LENGTH => SP_RETURN_ERROR\n"));
        return SP_RETURN_ERROR;
    }

    KdPrint2((PRINT_PREFIX "busDataRead\n"));
    if (pciData.VendorID == PCI_INVALID_VENDORID) {
        KdPrint2((PRINT_PREFIX "PCI_INVALID_VENDORID\n"));
        return SP_RETURN_ERROR;
    }

    VendorID  = pciData.VendorID;
    DeviceID  = pciData.DeviceID;
    BaseClass = pciData.BaseClass;
    SubClass  = pciData.SubClass;
    RevID     = pciData.RevisionID;
    dev_id = VendorID | (DeviceID << 16);
    slotData.u.AsULONG = slotNumber;
    KdPrint2((PRINT_PREFIX "DevId = %8.8X Class = %4.4X/%4.4X\n", dev_id, BaseClass, SubClass ));

    deviceExtension->slotNumber = slotNumber;
    deviceExtension->SystemIoBusNumber = SystemIoBusNumber;
    deviceExtension->DevID = dev_id;
    deviceExtension->RevID = RevID;

    _snprintf(deviceExtension->Signature, sizeof(deviceExtension->Signature),
              "UATA%8.8x/%1.1x@%8.8x", dev_id, channel, slotNumber);

    if(BaseClass != PCI_DEV_CLASS_STORAGE) {
        KdPrint2((PRINT_PREFIX "BaseClass != PCI_DEV_CLASS_STORAGE => SP_RETURN_NOT_FOUND\n"));
        return(SP_RETURN_NOT_FOUND);
    }

    KdPrint2((PRINT_PREFIX "Storage Class\n"));

    // look for known chipsets
    if(VendorID != BMList[i].nVendorId ||
       DeviceID != BMList[i].nDeviceId) {
        KdPrint2((PRINT_PREFIX "device not suitable\n"));
        return(SP_RETURN_NOT_FOUND);
    }

    if((BMList[i].RaidFlags & UNIATA_RAID_CONTROLLER) &&
        SkipRaids) {
        KdPrint2((PRINT_PREFIX "RAID support disabled\n"));
        return(SP_RETURN_NOT_FOUND);
    }
    ConfigInfo->AlignmentMask = 0x00000003;

    found = AtapiChipDetect(HwDeviceExtension, &pciData, i, ConfigInfo, &simplexOnly);
    KdPrint2((PRINT_PREFIX "ForceSimplex = %d\n", simplexOnly));
    KdPrint2((PRINT_PREFIX "HwFlags = %x\n (0)", deviceExtension->HwFlags));
    switch(dev_id) {
    /* additional checks for some supported chipsets */
    case 0xc6931080:
        if (SubClass != PCI_DEV_SUBCLASS_IDE) {
            KdPrint2((PRINT_PREFIX "0xc6931080, SubClass != PCI_DEV_SUBCLASS_IDE => found = FALSE\n"));
            found = FALSE;
        } else {
            found = FALSE;
        }
        break;

    /* unknown chipsets, try generic DMA if it seems possible */
    default:
        if (found)
            break;
        KdPrint2((PRINT_PREFIX "Default device\n"));
        if(!Ata_is_supported_dev(&pciData)) {
            KdPrint2((PRINT_PREFIX "!Ata_is_supported_dev => found = FALSE\n"));
            found = FALSE;
        }
        deviceExtension->UnknownDev = TRUE;
        break;
    }

    KdPrint2((PRINT_PREFIX "HwFlags = %x\n (1)", deviceExtension->HwFlags));
    if(!found) {
        KdPrint2((PRINT_PREFIX "!found => SP_RETURN_NOT_FOUND\n"));
        return(SP_RETURN_NOT_FOUND);
    }

    KdPrint2((PRINT_PREFIX "HwFlags = %x\n (2)", deviceExtension->HwFlags));
    KdPrint2((PRINT_PREFIX "found suitable device\n"));

    /***********************************************************/
    /***********************************************************/
    /***********************************************************/

    deviceExtension->UseDpc = TRUE;
    KdPrint2((PRINT_PREFIX "HwFlags = %x\n (3)", deviceExtension->HwFlags));
    if(deviceExtension->HwFlags & UNIATA_NO_DPC) {
        /* CMD 649, ROSB SWK33, ICH4 */
        KdPrint2((PRINT_PREFIX "AtapiFindBusMasterController: UNIATA_NO_DPC (0)\n"));
        deviceExtension->UseDpc = FALSE;
    }

    deviceExtension->NumberChannels = 1;
    MasterDev = IsMasterDev(&pciData);

    if(MasterDev) {
        KdPrint2((PRINT_PREFIX "MasterDev\n"));
        deviceExtension->MasterDev = TRUE;
    }

    if(MasterDev) {
        if((WinVer_Id() <= WinVer_NT) && AltInit && FirstMasterOk) {
            // this is the 2nd attempt to init this controller by OUR driver
            KdPrint2((PRINT_PREFIX "Skip primary/secondary claiming checks\n"));
        } else {
            if((channel==0) && ConfigInfo->AtdiskPrimaryClaimed) {
                KdPrint2((PRINT_PREFIX "Error: Primary channel already claimed by another driver\n"));
                return(SP_RETURN_NOT_FOUND);
            }
            if((channel==1) && ConfigInfo->AtdiskSecondaryClaimed) {
                KdPrint2((PRINT_PREFIX "Error: Secondary channel already claimed by another driver\n"));
                return(SP_RETURN_NOT_FOUND);
            }
        }
/*
        if(BMList[i].AltInitMasterDev == 0x01) {
            // revert to 0x00 ?
            BMList[i].AltInitMasterDev = 0;
        } else {
            BMList[i].AltInitMasterDev++;
        }
*/
    }

    if(!deviceExtension->MemIo) {
        deviceExtension->BusMaster = FALSE;
        if(IsBusMaster(&pciData)) {
            KdPrint2((PRINT_PREFIX "IsBusMaster == TRUE\n"));
            deviceExtension->BaseIoAddressBM_0 = (PIDE_BUSMASTER_REGISTERS)
                (AtapiGetIoRange(HwDeviceExtension, ConfigInfo, &pciData, SystemIoBusNumber,
                                4, bm_offset, MasterDev ? 0x08 : 0x10/*ATA_BMIOSIZE*/) - bm_offset); //range id
            if(deviceExtension->BaseIoAddressBM_0) {
                deviceExtension->BusMaster = TRUE;
            }
            KdPrint2((PRINT_PREFIX "  BusMasterAddress (base): %#x\n", deviceExtension->BaseIoAddressBM_0));
        }

        if(!deviceExtension->BusMaster) {
            KdPrint2((PRINT_PREFIX "  !BusMasterAddress -> PIO4\n"));
            deviceExtension->MaxTransferMode = ATA_PIO4;
        }

        if(deviceExtension->BusMaster && !MasterDev) {
            KdPrint2((PRINT_PREFIX "IsBusMaster == TRUE && !MasterDev\n"));
            statusByte = AtapiReadPort1(NULL, (PUCHAR)&(deviceExtension->BaseIoAddressBM_0->Status));
            if(statusByte & BM_STATUS_SIMPLEX_ONLY) {
                KdPrint2((PRINT_PREFIX "  BM_STATUS => simplexOnly\n"));
                simplexOnly = TRUE;
            }
        }
    } else {
        KdPrint2((PRINT_PREFIX "  Using MEM i/o (1)\n"));
    }

    /*
     * the Cypress chip is a mess, it contains two ATA functions, but 
     * both channels are visible on the first one.
     * simply ignore the second function for now, as the right
     * solution (ignoring the second channel on the first function)
     * doesn't work with the crappy ATA interrupt setup on the alpha.
     */
    if (dev_id == 0xc6931080 && slotData.u.bits.FunctionNumber > 1) {
        KdPrint2((PRINT_PREFIX "dev_id == 0xc6931080 && FunctionNumber > 1 => exit_findbm\n"));
        goto exit_findbm;
    }

    /* do extra chipset specific setups */
    AtapiChipInit(HwDeviceExtension, i, -1);

    simplexOnly |= deviceExtension->simplexOnly;
    deviceExtension->simplexOnly |= simplexOnly;

    KdPrint2((PRINT_PREFIX "simplexOnly = %d (2)", simplexOnly));

    //TODO: fix hang with UseDpn=TRUE in Simplex mode
    //deviceExtension->UseDpc = TRUE;
    if(simplexOnly) {
        KdPrint2((PRINT_PREFIX "simplexOnly => UseDpc = FALSE\n"));
        deviceExtension->UseDpc = FALSE;
    }

    if(simplexOnly || !MasterDev || (WinVer_Id() > WinVer_NT)) {
        if(deviceExtension->NumberChannels < 2) {
            deviceExtension->NumberChannels = 2;
        }
    }
    if((channel > 0) &&
       (deviceExtension->NumberChannels > 1)) {
        KdPrint2((PRINT_PREFIX "Error: channel > 0 && NumberChannels > 1\n"));
        goto exit_findbm;
    }

    // Indicate number of buses.
    ConfigInfo->NumberOfBuses = (UCHAR)(deviceExtension->NumberChannels);
    if(!ConfigInfo->InitiatorBusId[0]) {
        ConfigInfo->InitiatorBusId[0] = (CHAR)(IoGetConfigurationInformation()->ScsiPortCount);
        KdPrint2((PRINT_PREFIX "set ConfigInfo->InitiatorBusId[0] = %#x\n", ConfigInfo->InitiatorBusId[0]));
/*        if(ConfigInfo->NumberOfBuses > 1)
            ConfigInfo->InitiatorBusId[1] = (CHAR)(IoGetConfigurationInformation()->ScsiPortCount)+1;*/
    }
    // Indicate four devices can be attached to the adapter
    ConfigInfo->MaximumNumberOfTargets = (UCHAR)(/*deviceExtension->NumberChannels **/ 2);

    if (MasterDev) {
        KdPrint2((PRINT_PREFIX "MasterDev\n"));
        if(simplexOnly ||
           (WinVer_Id() > WinVer_NT) ||
           (deviceExtension->NumberChannels > 1)) {

            KdPrint2((PRINT_PREFIX "2 channels & 2 irq for 1 controller\n"));

            if (ConfigInfo->AdapterInterfaceType == MicroChannel) {
                ConfigInfo->InterruptMode2 =
                ConfigInfo->InterruptMode = LevelSensitive;
            } else {
                ConfigInfo->InterruptMode2 =
                ConfigInfo->InterruptMode = Latched;
            }
            ConfigInfo->BusInterruptLevel = 14;
            ConfigInfo->BusInterruptLevel2 = 15;
        } else {
            KdPrint2((PRINT_PREFIX "1 channels & 1 irq for 1 controller\n"));
            if (ConfigInfo->AdapterInterfaceType == MicroChannel) {
                ConfigInfo->InterruptMode = LevelSensitive;
            } else {
                ConfigInfo->InterruptMode = Latched;
            }
            ConfigInfo->BusInterruptLevel = (channel == 0 ? 14 : 15);
        }
    } else {
        KdPrint2((PRINT_PREFIX "!MasterDev\n"));
        ConfigInfo->SlotNumber = slotNumber;
        ConfigInfo->SystemIoBusNumber = SystemIoBusNumber;
        
        /* primary and secondary channels share the same interrupt */
        if(!ConfigInfo->BusInterruptVector || 
            (ConfigInfo->BusInterruptVector != pciData.u.type0.InterruptLine)) {
            KdPrint2((PRINT_PREFIX "patch irq line = %#x\n", pciData.u.type0.InterruptLine));
            ConfigInfo->BusInterruptVector = pciData.u.type0.InterruptLine;  // set default value
            if(!ConfigInfo->BusInterruptVector) {
                KdPrint2((PRINT_PREFIX "patch irq line (2) = 10\n"));
                ConfigInfo->BusInterruptVector = 10;
            }
        }
    }
    ConfigInfo->MultipleRequestPerLu = TRUE;
    ConfigInfo->AutoRequestSense     = TRUE;
    ConfigInfo->TaggedQueuing        = TRUE;

    if((WinVer_Id() >= WinVer_NT) ||
       (ConfigInfo->Length >= sizeof(_ConfigInfo->comm) + sizeof(_ConfigInfo->nt4))) {
        _ConfigInfo->nt4.DeviceExtensionSize         = sizeof(HW_DEVICE_EXTENSION);
        _ConfigInfo->nt4.SpecificLuExtensionSize     = sizeof(HW_LU_EXTENSION);    
        _ConfigInfo->nt4.SrbExtensionSize            = sizeof(ATA_REQ);            
    }
    if((WinVer_Id() > WinVer_2k) ||
       (ConfigInfo->Length >= sizeof(_ConfigInfo->comm) + sizeof(_ConfigInfo->nt4) + sizeof(_ConfigInfo->w2k))) {
        _ConfigInfo->w2k.Dma64BitAddresses           = 0;
        _ConfigInfo->w2k.ResetTargetSupported        = TRUE;
        _ConfigInfo->w2k.MaximumNumberOfLogicalUnits = 2;
    }

    // Save the Interrupe Mode for later use
    deviceExtension->InterruptMode      = ConfigInfo->InterruptMode;
    deviceExtension->BusInterruptLevel  = ConfigInfo->BusInterruptLevel;
    deviceExtension->BusInterruptVector = ConfigInfo->BusInterruptVector;
    deviceExtension->Channel            = channel;
    deviceExtension->DevIndex           = i;
    deviceExtension->OrigAdapterInterfaceType
                                        = ConfigInfo->AdapterInterfaceType;
    deviceExtension->AlignmentMask      = ConfigInfo->AlignmentMask;

    found = FALSE;

    if(deviceExtension->BusMaster) {
        
        KdPrint2((PRINT_PREFIX "Reconstruct ConfigInfo\n"));
        ConfigInfo->MapBuffers = TRUE;
#ifdef USE_OWN_DMA
        ConfigInfo->NeedPhysicalAddresses = FALSE;
#else
        ConfigInfo->NeedPhysicalAddresses = TRUE;
#endif //USE_OWN_DMA
        if(!MasterDev) {
            KdPrint2((PRINT_PREFIX "set Dma32BitAddresses\n"));
            ConfigInfo->Dma32BitAddresses = TRUE;
        }

        // thanks to Vitaliy Vorobyov aka deathsoft@yandex.ru for
        // better solution:

        if(/*BMList[i].AltInitMasterDev == 0x00 ||*/
           AltInit /*||
           (WinVer_Id() > WinVer_NT)*/) {
            // I'm sorry, I have to do this
            // when Win doesn't 

            if(ConfigInfo->AdapterInterfaceType == Isa /*&&
//               InDriverEntry*/) {
                KdPrint2((PRINT_PREFIX "AdapterInterfaceType Isa => PCIBus\n"));
                ConfigInfo->AdapterInterfaceType = PCIBus;
            }
            if(ConfigInfo->AdapterInterfaceType == PCIBus /*&&
//               InDriverEntry*/) {
                KdPrint2((PRINT_PREFIX "AdapterInterfaceType PCIBus, update address\n"));
                ConfigInfo->SlotNumber = slotNumber;
                ConfigInfo->SystemIoBusNumber = SystemIoBusNumber;
            }
        }

#ifndef USE_OWN_DMA
        ConfigInfo->Master        = TRUE;
        ConfigInfo->DmaWidth      = Width16Bits;
#endif //USE_OWN_DMA
        ConfigInfo->CachesData    = TRUE;
        ConfigInfo->ScatterGather = TRUE;
    }

    // Note: now we can support only 4 channels !!!
    // in order to add support for multichannel controllers we must rewrite
    // io-range claiming algorithm

    for (; channel < (BMList[i].channel + deviceExtension->NumberChannels); channel++, c++) {

        KdPrint2((PRINT_PREFIX "de %#x, Channel %#x\n",deviceExtension, channel));
        //PrintNtConsole("de %#x, Channel %#x, nchan %#x\n",deviceExtension, channel, deviceExtension->NumberChannels);
        chan = &deviceExtension->chan[c];

        KdPrint2((PRINT_PREFIX "chan = %#x\n", chan));
        //PrintNtConsole("chan = %#x, c=%#x\n", chan, c);
        chan->DeviceExtension = deviceExtension;
        chan->lChannel        = c;
        chan->lun[0] = &(deviceExtension->lun[c*2+0]);
        chan->lun[1] = &(deviceExtension->lun[c*2+1]);
        chan->MemIo  = deviceExtension->MemIo;

        /* do extra channel-specific setups */
        AtapiChipInit(HwDeviceExtension, i, channel);

        if(!deviceExtension->MemIo) {
            // Check if the range specified is not used by another driver
            if(MasterDev) {
                KdPrint2((PRINT_PREFIX "set AccessRanges\n"));
                (*ConfigInfo->AccessRanges)[channel * 2 + 0].RangeStart =
                    ScsiPortConvertUlongToPhysicalAddress(channel ? IO_WD2 : IO_WD1);
                (*ConfigInfo->AccessRanges)[channel * 2 + 0].RangeLength = ATA_IOSIZE;

                (*ConfigInfo->AccessRanges)[channel * 2 + 1].RangeStart =
                    ScsiPortConvertUlongToPhysicalAddress((channel ? IO_WD2 : IO_WD1) + ATA_ALTOFFSET);
                (*ConfigInfo->AccessRanges)[channel * 2 + 1].RangeLength = ATA_ALTIOSIZE;

                // do not claim 2nd BM io-range for Secondary channel of
                // Compatible-mode controllers
                if((WinVer_Id() <= WinVer_NT) && !c && channel == 1) {
                    KdPrint2((PRINT_PREFIX "cheat ScsiPort for 2nd channel, BM io-range\n"));
                    (*ConfigInfo->AccessRanges)[4].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0);
                    (*ConfigInfo->AccessRanges)[4].RangeLength = 0;
                }
            }

            IoBasePort1 = (*ConfigInfo->AccessRanges)[channel * 2 + 0].RangeStart;
            IoBasePort2 = (*ConfigInfo->AccessRanges)[channel * 2 + 1].RangeStart;

            if(!MasterDev) {
                if(!IoBasePort1.QuadPart || !IoBasePort2.QuadPart) {
                    KdPrint2((PRINT_PREFIX "ScsiPortValidateRange failed (1)\n"));
                    continue;
                }
            }

            if(!ScsiPortValidateRange(HwDeviceExtension,
                                      PCIBus /*ConfigInfo->AdapterInterfaceType*/,
                                      SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/,
                                      IoBasePort1,
                                      ATA_IOSIZE,
                                      TRUE) ) {
                KdPrint2((PRINT_PREFIX "ScsiPortValidateRange failed (1)\n"));
                continue;
            }
            
            if(!ScsiPortValidateRange(HwDeviceExtension,
                                      PCIBus /*ConfigInfo->AdapterInterfaceType*/,
                                      SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/,
                                      IoBasePort2,
                                      ATA_ALTIOSIZE,
                                      TRUE) ) {
                KdPrint2((PRINT_PREFIX "ScsiPortValidateRange failed (2)\n"));
                continue;
            }

            KdPrint2((PRINT_PREFIX "Getting IO ranges\n"));

            // Ok, translate adresses to io-space
            if(ScsiPortConvertPhysicalAddressToUlong(IoBasePort2)) {
                if(!(MasterDev /* || USE_16_BIT */)) {
                    KdPrint2((PRINT_PREFIX "!MasterDev mode\n"));
                    IoBasePort2 = ScsiPortConvertUlongToPhysicalAddress(
                                      ScsiPortConvertPhysicalAddressToUlong(IoBasePort2) + 2);
                }
            } else {
                KdPrint2((PRINT_PREFIX "use relartive IoBasePort2\n"));
                IoBasePort2 = ScsiPortConvertUlongToPhysicalAddress(
                                  ScsiPortConvertPhysicalAddressToUlong(IoBasePort1) + ATA_PCCARD_ALTOFFSET);
            }

            // Get the system physical address for this IO range.
            ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension,
                                            PCIBus /*ConfigInfo->AdapterInterfaceType*/,
                                            SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/,
                                            IoBasePort1,
                                            ATA_IOSIZE,
                                            TRUE);
            KdPrint2((PRINT_PREFIX "IO range 1 %#x\n",ioSpace));

            // Check if ioSpace accessible.
            if (!ioSpace) {
                KdPrint2((PRINT_PREFIX "!ioSpace\n"));
                continue;
            }

            if(deviceExtension->BusMaster) {
                KdPrint2((PRINT_PREFIX "set BusMaster io-range in DO\n"));
                // bm_offset already inludes (channel ? ATA_BM_OFFSET1 : 0)
                deviceExtension->BaseIoAddressBM[c] = (PIDE_BUSMASTER_REGISTERS)
                    ((ULONG)(deviceExtension->BaseIoAddressBM_0) + bm_offset + (c ? ATA_BM_OFFSET1 : 0));
            }

            deviceExtension->BaseIoAddress1[c] = (PIDE_REGISTERS_1)(ioSpace);

            // Get the system physical address for the second IO range.
            ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension,
                                            PCIBus /*ConfigInfo->AdapterInterfaceType*/,
                                            SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/,
                                            IoBasePort2,
                                            ATA_ALTIOSIZE,
                                            TRUE);
            KdPrint2((PRINT_PREFIX "IO range 2 %#x\n",ioSpace));

            deviceExtension->BaseIoAddress2[c] = (PIDE_REGISTERS_2)(ioSpace);
            if(!deviceExtension->BaseIoAddress2[c]) {
                // Release all allocated resources
                KdPrint2((PRINT_PREFIX "!deviceExtension->BaseIoAddress2\n"));
                ioSpace = (PUCHAR)(deviceExtension->BaseIoAddress1[c]);
    //            goto free_iospace_1;
                found = FALSE;
                goto exit_findbm;
            }
        } else {
            KdPrint2((PRINT_PREFIX "Using MEM i/o space.\n"));
        }
        ioSpace = (PUCHAR)(deviceExtension->BaseIoAddress1[c]);

        KdPrint2((PRINT_PREFIX "Check drive 0\n"));
        // Check master.
        SelectDrive(chan, (PIDE_REGISTERS_1)ioSpace, 0);
        AtapiStallExecution(10);
        GetBaseStatus(chan, (PIDE_REGISTERS_1)ioSpace, statusByte);
        skip_find_dev = FALSE;
        if ((statusByte & 0xf8) == 0xf8 || 
            (statusByte == 0xa5)) {
            // Check slave.
            KdPrint2((PRINT_PREFIX "Check drive 1\n"));
            SelectDrive(chan, (PIDE_REGISTERS_1)ioSpace, 1);
            AtapiStallExecution(1);
            GetBaseStatus(chan, (PIDE_REGISTERS_1)ioSpace, statusByte);
            if ((statusByte & 0xf8) == 0xf8 || 
                (statusByte == 0xa5)) {
                // No controller at this base address.
                KdPrint2((PRINT_PREFIX "Empty channel\n"));
                skip_find_dev = TRUE;
            }
        }

        // Search for devices on this controller.
        if (!skip_find_dev &&
            FindDevices(HwDeviceExtension,
                    FALSE,
                    c)) {
            KdPrint2((PRINT_PREFIX "Found some devices\n"));
            found = TRUE;
        } else {
            KdPrint2((PRINT_PREFIX "no devices\n"));
/*            KeBugCheckEx(0xc000000e,
                         ScsiPortConvertPhysicalAddressToUlong(IoBasePort1),
                         ScsiPortConvertPhysicalAddressToUlong(IoBasePort2), 
                         (ULONG)(deviceExtension->BaseIoAddressBM[c]), skip_find_dev);*/
        }
        found = TRUE;

        chan->PrimaryAddress = FALSE;
        // Claim primary or secondary ATA IO range.
        if (MasterDev) {
            KdPrint2((PRINT_PREFIX "claim Compatible controller\n"));
            if (channel == 0) {
                KdPrint2((PRINT_PREFIX "claim Primary\n"));
                ConfigInfo->AtdiskPrimaryClaimed = TRUE;
                chan->PrimaryAddress = TRUE;

                FirstMasterOk = TRUE;

            } else
            if (channel == 1) {
                KdPrint2((PRINT_PREFIX "claim Secondary\n"));
                ConfigInfo->AtdiskSecondaryClaimed = TRUE;
    
                FirstMasterOk = TRUE;
            }
        }

        AtapiDmaAlloc(HwDeviceExtension, ConfigInfo, c);
    } // end for(channel)

exit_findbm:

    if(!found) {
        KdPrint2((PRINT_PREFIX "exit: !found\n"));
        if(deviceExtension->BaseIoAddress1[0])
            ScsiPortFreeDeviceBase(HwDeviceExtension,
                                   deviceExtension->BaseIoAddress1[0]);
        if(deviceExtension->BaseIoAddress2[0])
            ScsiPortFreeDeviceBase(HwDeviceExtension,
                                   deviceExtension->BaseIoAddress2[0]);

        if(deviceExtension->BaseIoAddress1[1])
            ScsiPortFreeDeviceBase(HwDeviceExtension,
                                   deviceExtension->BaseIoAddress1[1]);
        if(deviceExtension->BaseIoAddress2[1])
            ScsiPortFreeDeviceBase(HwDeviceExtension,
                                   deviceExtension->BaseIoAddress2[1]);

        if(deviceExtension->BaseIoAddressBM_0)
            ScsiPortFreeDeviceBase(HwDeviceExtension,
                                   deviceExtension->BaseIoAddressBM_0);
        
        KdPrint2((PRINT_PREFIX "return SP_RETURN_NOT_FOUND\n"));
        return SP_RETURN_NOT_FOUND;
    } else {

        KdPrint2((PRINT_PREFIX "exit: init spinlock\n"));
        KeInitializeSpinLock(&(deviceExtension->DpcSpinLock));
        deviceExtension->ActiveDpcChan =
        deviceExtension->FirstDpcChan = -1;
        deviceExtension->DpcTime1 =
        deviceExtension->DpcTime2 = 0;

        BMList[i].Isr2Enable = FALSE;

        KdPrint2((PRINT_PREFIX "MasterDev=%#x, NumberChannels=%#x, Isr2DevObj=%#x\n",
            MasterDev, deviceExtension->NumberChannels, BMList[i].Isr2DevObj));

        // ConnectIntr2 should be moved to HwInitialize
        status = AtapiConnectIntr2(HwDeviceExtension);

        if(!NT_SUCCESS(status)) {
            KdPrint2((PRINT_PREFIX "failed\n"));
            found = FALSE;
            goto exit_findbm;
        }
    }

    KdPrint2((PRINT_PREFIX "return SP_RETURN_FOUND\n"));
    //PrintNtConsole("return SP_RETURN_FOUND, de %#x, c0.lun0 %#x\n", deviceExtension, deviceExtension->chan[0].lun[0]);

    if(MasterDev) {
        KdPrint2((PRINT_PREFIX "Attempt %d of MasterDev ok\n", AltInit));
        FirstMasterOk = TRUE;
    }

    return SP_RETURN_FOUND;

} // end AtapiFindBusMasterController()

/*++

Routine Description:

    This function is called to initialize 2nd device object for
    multichannel controllers.

Arguments:

    HwDeviceExtension - HBA miniport driver's adapter data storage

Return Value:

    ULONG

--*/
NTSTATUS
AtapiConnectIntr2(
    IN PVOID HwDeviceExtension
    )
{
    PHW_DEVICE_EXTENSION  deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
    ULONG i = deviceExtension->DevIndex;
    NTSTATUS status;
    PISR2_DEVICE_EXTENSION Isr2DevExt;
    WCHAR devname_str[32];
    UNICODE_STRING devname;

    KdPrint2((PRINT_PREFIX "Init ISR:\n"));

//            __asm int 3;
    if(BMList[i].Isr2DevObj) {
        KdPrint2((PRINT_PREFIX "Already initialized %#x\n", BMList[i].Isr2DevObj));
        return STATUS_SUCCESS;
    }

    if(!deviceExtension->MasterDev && (deviceExtension->NumberChannels > 1) &&   // do not touch MasterDev
       !deviceExtension->simplexOnly && /*                        // this is unnecessary on simplex controllers
       !BMList[i].Isr2DevObj*/                                    // handle re-init under w2k+
       /*!ForceSimplex*/
       TRUE) {
        // Ok, continue...
    } else {
        KdPrint2((PRINT_PREFIX "Unnecessary\n"));
        return STATUS_SUCCESS;
    }

    KdPrint2((PRINT_PREFIX "Create DO\n"));

    devname.Length = 
        _snwprintf(devname_str, sizeof(devname_str)/sizeof(WCHAR),
              L"\\Device\\uniata%d_2ch", i);
    devname.Length *= sizeof(WCHAR);
    devname.MaximumLength = devname.Length;
    devname.Buffer = devname_str;

    KdPrint2((PRINT_PREFIX "DO name:  %d, %d, %S\n", devname.Length, devname.MaximumLength, devname.Buffer));

    status = IoCreateDevice(SavedDriverObject, sizeof(ISR2_DEVICE_EXTENSION),
                            /*NULL*/ &devname, FILE_DEVICE_UNKNOWN,
                            0, FALSE, &(BMList[i].Isr2DevObj));

    if(!NT_SUCCESS(status)) {
        KdPrint2((PRINT_PREFIX "failed %#x\n"));
        return status;
    }

    KdPrint2((PRINT_PREFIX "HalGetInterruptVector\n"));
    BMList[i].Isr2Vector = HalGetInterruptVector(
        deviceExtension->OrigAdapterInterfaceType,
        deviceExtension->SystemIoBusNumber,
        deviceExtension->BusInterruptLevel,
        deviceExtension->BusInterruptVector,
        &(BMList[i].Isr2Irql),
        &(BMList[i].Isr2Affinity));

    Isr2DevExt = (PISR2_DEVICE_EXTENSION)(BMList[i].Isr2DevObj->DeviceExtension);
    Isr2DevExt->HwDeviceExtension = deviceExtension;
    Isr2DevExt->DevIndex = i;

    KdPrint2((PRINT_PREFIX "isr2_de %#x\n", Isr2DevExt));

//            deviceExtension->QueueNewIrql = BMList[i].Isr2Irql;
    
    KdPrint2((PRINT_PREFIX "IoConnectInterrupt\n"));
    status = IoConnectInterrupt(
        &(BMList[i].Isr2InterruptObject),
        AtapiInterrupt2,
        Isr2DevExt,
        NULL,
        BMList[i].Isr2Vector,
        BMList[i].Isr2Irql,
        BMList[i].Isr2Irql,
        (KINTERRUPT_MODE)(deviceExtension->InterruptMode),
        TRUE,
        BMList[i].Isr2Affinity,
        FALSE);

    if(!NT_SUCCESS(status)) {
        KdPrint2((PRINT_PREFIX "failed\n"));
        IoDeleteDevice(BMList[i].Isr2DevObj);
        BMList[i].Isr2DevObj          = NULL;
        BMList[i].Isr2InterruptObject = NULL;
        return status;
    }
    return status;
} // end AtapiConnectIntr2()

NTSTATUS
AtapiDisconnectIntr2(
    IN PVOID HwDeviceExtension
    )
{
    PHW_DEVICE_EXTENSION  deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
    ULONG i = deviceExtension->DevIndex;
//    NTSTATUS status;

    KdPrint2((PRINT_PREFIX "Deinit ISR:\n"));

//            __asm int 3;
    if(!BMList[i].Isr2DevObj) {
        KdPrint2((PRINT_PREFIX "Already uninitialized %#x\n"));
        return STATUS_SUCCESS;
    }

    IoDisconnectInterrupt(BMList[i].Isr2InterruptObject);

    BMList[i].Isr2InterruptObject = NULL;

    IoDeleteDevice(BMList[i].Isr2DevObj);

    BMList[i].Isr2DevObj          = NULL;

    return STATUS_SUCCESS;
} // end AtapiDisconnectIntr2()

/*++

Routine Description:

    This function is called by the OS-specific port driver after
    the necessary storage has been allocated, to gather information
    about the adapter's configuration.

Arguments:

    HwDeviceExtension - HBA miniport driver's adapter data storage
    Context - Address of adapter count
    ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility.
    ConfigInfo - Configuration information structure describing HBA
    Again - Indicates search for adapters to continue

Return Value:

    ULONG

--*/
ULONG
AtapiFindController(
    IN PVOID HwDeviceExtension,
    IN PVOID Context,
    IN PVOID BusInformation,
    IN PCHAR ArgumentString,
    IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
    OUT PBOOLEAN Again
    )
{
    PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
    PHW_CHANNEL          chan = &(deviceExtension->chan[0]);
    PULONG               adapterCount    = (PULONG)Context;
    PUCHAR               ioSpace;
    ULONG                i;
    ULONG                irq;
    ULONG                portBase;
    ULONG                retryCount;
    BOOLEAN              atapiOnly;
    UCHAR                statusByte;
    BOOLEAN              preConfig = FALSE;
    //
    // The following table specifies the ports to be checked when searching for
    // an IDE controller.  A zero entry terminates the search.
    CONST ULONG AdapterAddresses[5] = {IO_WD1, IO_WD2, IO_WD1-8, IO_WD2-8, 0};
    CONST UCHAR Channels[5] = {0, 1, 0, 1, 0};

    // The following table specifies interrupt levels corresponding to the
    // port addresses in the previous table.
    CONST ULONG InterruptLevels[5] = {14, 15, 11, 10, 0};

    KdPrint2((PRINT_PREFIX "AtapiFindController:\n"));

    if (!deviceExtension) {
        return SP_RETURN_ERROR;
    }
    RtlZeroMemory(deviceExtension, sizeof(HW_DEVICE_EXTENSION));

    KdPrint2((PRINT_PREFIX "  assume max PIO4\n"));
    deviceExtension->MaxTransferMode = ATA_PIO4;

    /* do extra chipset specific setups */
    AtapiChipInit(HwDeviceExtension, -1, -1);

    // Check to see if this is a special configuration environment.
    portBase = irq = 0;
    if (ArgumentString) {

        irq = AtapiParseArgumentString(ArgumentString, "Interrupt");
        if (irq ) {

            // Both parameters must be present to proceed
            portBase = AtapiParseArgumentString(ArgumentString, "BaseAddress");
            if (!portBase) {

                // Try a default search for the part.
                irq = 0;
            }
        }
    }

    // Scan though the adapter address looking for adapters.
    if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart) != 0) {
        ioSpace =  (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension,
                                         ConfigInfo->AdapterInterfaceType,
                                         ConfigInfo->SystemIoBusNumber,
                                         (*ConfigInfo->AccessRanges)[0].RangeStart,
                                         (*ConfigInfo->AccessRanges)[0].RangeLength,
                                         (BOOLEAN) !((*ConfigInfo->AccessRanges)[0].RangeInMemory));
        *Again = FALSE;
        // Since we have pre-configured information we only need to go through this loop once
        preConfig = TRUE;
        portBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
    }

    while (AdapterAddresses[*adapterCount] != 0) {

        retryCount = 4;

        for (i = 0; i < 4; i++) {
            // Zero device fields to ensure that if earlier devices were found,
            // but not claimed, the fields are cleared.
            deviceExtension->lun[i].DeviceFlags &= ~(DFLAGS_ATAPI_DEVICE | DFLAGS_DEVICE_PRESENT | DFLAGS_TAPE_DEVICE);
        }
        // Get the system physical address for this IO range.

        // Check if configInfo has the default information
        // if not, we go and find ourselves
        if (preConfig == FALSE) {

            if (portBase) {
                ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension,
                                                ConfigInfo->AdapterInterfaceType,
                                                ConfigInfo->SystemIoBusNumber,
                                                ScsiPortConvertUlongToPhysicalAddress(portBase),
                                                8,
                                                TRUE);
            } else {
                ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension,
                                                ConfigInfo->AdapterInterfaceType,
                                                ConfigInfo->SystemIoBusNumber,
                                                ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount]),
                                                8,
                                                TRUE);
            }

        }// ConfigInfo check

        // Update the adapter count.
        (*adapterCount)++;

        // Check if ioSpace accessible.
        if (!ioSpace) {
            KdPrint2((PRINT_PREFIX "AtapiFindController: !ioSpace\n"));
            continue;
        }
        // check if Primary/Secondary Master IDE claimed
        if((ioSpace == (PUCHAR)IO_WD1) &&
           (ConfigInfo->AtdiskPrimaryClaimed)) {
            KdPrint2((PRINT_PREFIX "AtapiFindController: AtdiskPrimaryClaimed\n"));
            continue;
        } else
        if((ioSpace == (PUCHAR)IO_WD2) &&
           (ConfigInfo->AtdiskSecondaryClaimed)) {
            KdPrint2((PRINT_PREFIX "AtapiFindController: AtdiskSecondaryClaimed\n"));
            continue;
        }

retryIdentifier:

        // Select master.
        SelectDrive(chan, (PIDE_REGISTERS_1)ioSpace, 0);

        // Check if card at this address.
        AtapiWritePort1(chan, &((PIDE_REGISTERS_1)ioSpace)->o.CylinderLow, 0xAA);

        // Check if indentifier can be read back.
        if ((statusByte = AtapiReadPort1(chan, &((PIDE_REGISTERS_1)ioSpace)->i.CylinderLow)) != 0xAA) {

            KdPrint2((PRINT_PREFIX "AtapiFindController: Identifier read back from Master (%#x)\n",
                        statusByte));

            statusByte = AtapiReadPort1(chan, &((PATAPI_REGISTERS_2)ioSpace)->AlternateStatus);

            if (statusByte & IDE_STATUS_BUSY) {

                i = 0;

                // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that
                // warm boots don't clear.
                do {
                    AtapiStallExecution(1000);
                    statusByte = AtapiReadPort1(chan, &((PATAPI_REGISTERS_1)ioSpace)->i.Status);
                    KdPrint2((PRINT_PREFIX 
                                "AtapiFindController: First access to status %#x\n",
                                statusByte));
                } while ((statusByte & IDE_STATUS_BUSY) && ++i < 10);

                if (retryCount-- && (!(statusByte & IDE_STATUS_BUSY))) {
                    goto retryIdentifier;
                }
            }

            // Select slave.
            SelectDrive(chan, (PIDE_REGISTERS_1)ioSpace, 1);

            // See if slave is present.
            AtapiWritePort1(chan, &((PIDE_REGISTERS_1)ioSpace)->o.CylinderLow, 0xAA);

            if ((statusByte = AtapiReadPort1(chan, &((PIDE_REGISTERS_1)ioSpace)->i.CylinderLow)) != 0xAA) {

                KdPrint2((PRINT_PREFIX 
                            "AtapiFindController: Identifier read back from Slave (%#x)\n",
                            statusByte));

                // No controller at this base address.
                ScsiPortFreeDeviceBase(HwDeviceExtension,
                                       ioSpace);
                continue;
            }
        }

        // Record base IO address.
        deviceExtension->BaseIoAddress1[0] = (PIDE_REGISTERS_1)(ioSpace);

        // Fill in the access array information only if default params are not in there.
        if (preConfig == FALSE) {

            // An adapter has been found request another call, only if we didn't get preconfigured info.
            *Again = TRUE;

            if (portBase) {
                (*ConfigInfo->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(portBase);
            } else {
                (*ConfigInfo->AccessRanges)[0].RangeStart =
                    ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1]);
            }

            (*ConfigInfo->AccessRanges)[0].RangeLength = 8;
            (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;

            // Indicate the interrupt level corresponding to this IO range.
            if (irq) {
                ConfigInfo->BusInterruptLevel = irq;
            } else {
                ConfigInfo->BusInterruptLevel = InterruptLevels[*adapterCount - 1];
            }

            if (ConfigInfo->AdapterInterfaceType == MicroChannel) {
                ConfigInfo->InterruptMode = LevelSensitive;
            } else {
                ConfigInfo->InterruptMode = Latched;
            }
        }

        // Get the system physical address for the second IO range.
        if (portBase) {
            ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension,
                                            ConfigInfo->AdapterInterfaceType,
                                            ConfigInfo->SystemIoBusNumber,
                                            ScsiPortConvertUlongToPhysicalAddress(portBase + ATA_ALTOFFSET),
                                            ATA_ALTIOSIZE,
                                            TRUE);
        } else {
            ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension,
                                            ConfigInfo->AdapterInterfaceType,
                                            ConfigInfo->SystemIoBusNumber,
                                            ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1] + ATA_ALTOFFSET),
                                            ATA_ALTIOSIZE,
                                            TRUE);
        }

        deviceExtension->BaseIoAddress2[0] = (PIDE_REGISTERS_2)(ioSpace);

        deviceExtension->NumberChannels = 1;

        ConfigInfo->NumberOfBuses = 1;
        ConfigInfo->MaximumNumberOfTargets = 2;

        // Indicate maximum transfer length is 64k.
        ConfigInfo->MaximumTransferLength = 0x10000;
        deviceExtension->MaximumDmaTransferLength = ConfigInfo->MaximumTransferLength;

        KdPrint2((PRINT_PREFIX "de %#x, Channel ???\n", deviceExtension));
        //PrintNtConsole("de %#x, Channel %#x, nchan %#x\n",deviceExtension, channel, deviceExtension->NumberChannels);

        KdPrint2((PRINT_PREFIX "chan = %#x\n", chan));
        //PrintNtConsole("chan = %#x, c=%#x\n", chan, c);
        chan->DeviceExtension = deviceExtension;
        chan->lChannel        = 0;
        chan->lun[0] = &(deviceExtension->lun[0]);
        chan->lun[1] = &(deviceExtension->lun[1]);

        /* do extra channel-specific setups */
        AtapiChipInit(HwDeviceExtension, -1, 0);

        KdPrint2((PRINT_PREFIX 
                   "AtapiFindController: Found IDE at %#x\n",
                   deviceExtension->BaseIoAddress1[0]));

        // For Daytona, the atdisk driver gets the first shot at the
        // primary and secondary controllers.
        if (preConfig == FALSE) {

            if (*adapterCount - 1 < 2) {

                // Determine whether this driver is being initialized by the
                // system or as a crash dump driver.
                if (ArgumentString) {

                    if (AtapiParseArgumentString(ArgumentString, "dump") == 1) {
                        KdPrint2((PRINT_PREFIX 
                                   "AtapiFindController: Crash dump\n"));
                        atapiOnly = FALSE;
                        deviceExtension->DriverMustPoll = TRUE;
                    } else {
                        KdPrint2((PRINT_PREFIX 
                                   "AtapiFindController: Atapi Only\n"));
                        atapiOnly = TRUE;
                        deviceExtension->DriverMustPoll = FALSE;
                    }
                } else {

                    KdPrint2((PRINT_PREFIX 
                               "AtapiFindController: Atapi Only (2)\n"));
                    atapiOnly = TRUE;
                    deviceExtension->DriverMustPoll = FALSE;
                }

            } else {
                atapiOnly = FALSE;
            }

        } else {

            atapiOnly = FALSE;
            deviceExtension->DriverMustPoll = FALSE;

        }// preConfig check

        // Save the Interrupe Mode for later use
        deviceExtension->InterruptMode = ConfigInfo->InterruptMode;

        KdPrint2((PRINT_PREFIX 
                   "AtapiFindController: look for devices\n"));
        // Search for devices on this controller.
        if (FindDevices(HwDeviceExtension,
                        /*atapiOnly*/ FALSE,
                        0)) {

            KdPrint2((PRINT_PREFIX 
                       "AtapiFindController: detected\n"));
            // Claim primary or secondary ATA IO range.
            if (portBase) {
                switch (portBase) {
                case IO_WD2:
                    ConfigInfo->AtdiskSecondaryClaimed = TRUE;
                    chan->PrimaryAddress = FALSE;
                    break;
                case IO_WD1:
                    ConfigInfo->AtdiskPrimaryClaimed = TRUE;
                    chan->PrimaryAddress = TRUE;
                    break;
                default:
                    break;
                }
            } else {
                if (*adapterCount == 1) {
                    ConfigInfo->AtdiskPrimaryClaimed = TRUE;
                    chan->PrimaryAddress = TRUE;
                } else if (*adapterCount == 2) {
                    ConfigInfo->AtdiskSecondaryClaimed = TRUE;
                    chan->PrimaryAddress = FALSE;
                }
            }

            KdPrint2((PRINT_PREFIX 
                       "AtapiFindController: return SP_RETURN_FOUND\n"));
            return(SP_RETURN_FOUND);
        }
    }

    // The entire table has been searched and no adapters have been found.
    // There is no need to call again and the device base can now be freed.
    // Clear the adapter count for the next bus.
    *Again = FALSE;
    *(adapterCount) = 0;

    KdPrint2((PRINT_PREFIX 
               "AtapiFindController: return SP_RETURN_NOT_FOUND\n"));
    return(SP_RETURN_NOT_FOUND);

} // end AtapiFindController()


ULONG
CheckDevice(
    IN PVOID   HwDeviceExtension,
    IN ULONG   Channel,
    IN ULONG   deviceNumber,
    IN BOOLEAN ResetDev
    )
{
    PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
    PHW_CHANNEL          chan = &(deviceExtension->chan[Channel]);
    PIDE_REGISTERS_1     baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel];
    PIDE_REGISTERS_2     baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel];
    ULONG                ldev = GET_LDEV2(Channel, deviceNumber, 0);
    PHW_LU_EXTENSION     LunExt = &(deviceExtension->lun[ldev]);

    UCHAR                signatureLow,
                         signatureHigh;
    UCHAR                statusByte;
    ULONG                RetVal=0;

    KdPrint2((PRINT_PREFIX "CheckDevice: Device %#x\n",
               deviceNumber));
    if(ResetDev) {
        KdPrint2((PRINT_PREFIX "CheckDevice: reset bus\n"));
        // Reset device
        AtapiSoftReset(chan, baseIoAddress1,deviceNumber);
        statusByte = WaitOnBusy(chan, baseIoAddress2);
    }
    // Select the device.
    SelectDrive(chan, baseIoAddress1, deviceNumber);

    AtapiStallExecution(10);
    statusByte = WaitOnBaseBusyLong(chan, baseIoAddress1);

    GetBaseStatus(chan, baseIoAddress1, statusByte);

    KdPrint2((PRINT_PREFIX "CheckDevice: status %#x\n", statusByte));
    if(statusByte & IDE_STATUS_BUSY) {
        KdPrint2((PRINT_PREFIX "CheckDevice: busy => return\n"));
        LunExt->DeviceFlags = 0;
        return 0;
    }

    // set default costs
    LunExt->RwSwitchCost  = REORDER_COST_SWITCH_RW_HDD;
    LunExt->RwSwitchMCost = REORDER_MCOST_SWITCH_RW_HDD;
    LunExt->SeekBackMCost = REORDER_MCOST_SEEK_BACK_HDD;

    signatureLow = AtapiReadPort1(chan, &baseIoAddress1->i.CylinderLow);
    signatureHigh = AtapiReadPort1(chan, &baseIoAddress1->i.CylinderHigh);

    if (signatureLow == ATAPI_MAGIC_LSB && signatureHigh == ATAPI_MAGIC_MSB) {

        KdPrint2((PRINT_PREFIX "CheckDevice: ATAPI signature found\n"));
        // ATAPI signature found.
        // Issue the ATAPI identify command if this
        // is not for the crash dump utility.

        if (!deviceExtension->DriverMustPoll) {

            // Issue ATAPI packet identify command.
            if (IssueIdentify(HwDeviceExtension,
                              deviceNumber,
                              Channel,
                              IDE_COMMAND_ATAPI_IDENTIFY, FALSE)) {

                // Indicate ATAPI device.
                KdPrint2((PRINT_PREFIX "CheckDevice: Device %#x is ATAPI\n",
                           deviceNumber));

                RetVal = DFLAGS_DEVICE_PRESENT | DFLAGS_ATAPI_DEVICE;
                LunExt->DeviceFlags |= (DFLAGS_DEVICE_PRESENT | DFLAGS_ATAPI_DEVICE);

                // some ATAPI devices doesn't work with DPC on CMD-649
                // and probably some other controllers
                if(deviceExtension->HwFlags & UNIATA_NO_DPC_ATAPI) {
                    /* CMD 649, ROSB SWK33, ICH4 */
                    KdPrint2((PRINT_PREFIX "CheckDevice: UNIATA_NO_DPC_ATAPI\n"));
                    deviceExtension->UseDpc = FALSE;
                }

                GetStatus(chan, baseIoAddress2, statusByte);
                if (statusByte & IDE_STATUS_ERROR) {
                    AtapiSoftReset(chan, baseIoAddress1, deviceNumber);
                }

            } else {

                // Indicate no working device.
                KdPrint2((PRINT_PREFIX "CheckDevice: Device %#x not responding\n",
                           deviceNumber));

                LunExt->DeviceFlags = 0;
                RetVal = 0;
            }
            GetBaseStatus(chan, baseIoAddress1, statusByte);

        }

    } else {

        KdPrint2((PRINT_PREFIX "CheckDevice: IDE device check\n"));
        // Issue IDE Identify. If an Atapi device is actually present, the signature
        // will be asserted, and the drive will be recognized as such.
        if (IssueIdentify(HwDeviceExtension,
                          deviceNumber,
                          Channel,
                          IDE_COMMAND_IDENTIFY, FALSE)) {

            // IDE drive found.
            KdPrint2((PRINT_PREFIX "CheckDevice: Device %#x is IDE\n",
                       deviceNumber));

            // Indicate IDE - not ATAPI device.
            RetVal = DFLAGS_DEVICE_PRESENT;
            LunExt->DeviceFlags |= DFLAGS_DEVICE_PRESENT;
            LunExt->DeviceFlags &= ~DFLAGS_ATAPI_DEVICE;
        }
        GetBaseStatus(chan, baseIoAddress1, statusByte);
    }
    KdPrint2((PRINT_PREFIX "CheckDevice: check status: %sfound\n", RetVal ? "" : "not "));
    return RetVal;
} // end CheckDevice()


/*++

Routine Description:

    This routine is called from AtapiFindController to identify
    devices attached to an IDE controller.

Arguments:

    HwDeviceExtension - HBA miniport driver's adapter data storage
    AtapiOnly - Indicates that routine should return TRUE only if
        an ATAPI device is attached to the controller.

Return Value:

    TRUE - True if devices found.

--*/
BOOLEAN
FindDevices(
    IN PVOID HwDeviceExtension,
    IN BOOLEAN AtapiOnly,
    IN ULONG   Channel
    )
{
    PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
    PHW_CHANNEL          chan = &(deviceExtension->chan[Channel]);
    PIDE_REGISTERS_1     baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel];
    PIDE_REGISTERS_2     baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel];
    BOOLEAN              deviceResponded = FALSE,
                         skipSetParameters = FALSE;
    ULONG                waitCount = 10000;
    //ULONG                deviceNumber;
    ULONG                i;
    UCHAR                statusByte;
    ULONG                ldev;

    KdPrint2((PRINT_PREFIX "FindDevices:\n"));

    // Disable interrupts
    AtapiDisableInterrupts(deviceExtension, Channel);
//    AtapiWritePort1(chan, &baseIoAddress2->AlternateStatus,IDE_DC_DISABLE_INTERRUPTS | IDE_DC_A_4BIT );

    // Clear expecting interrupt flag and current SRB field.
    chan->ExpectingInterrupt = FALSE;
//    chan->CurrentSrb = NULL;

    // Search for devices.
    for (i = 0; i < 2; i++) {
        deviceResponded |= 
            (CheckDevice(HwDeviceExtension, Channel, i, TRUE) != 0);
    }

    for (i = 0; i < 2; i++) {
        ldev = GET_LDEV2(Channel, i, 0);

        if ((  deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT) &&
             !(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_LBA_ENABLED) &&
             !(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) && deviceResponded) {

            // This hideous hack is to deal with ESDI devices that return
            // garbage geometry in the IDENTIFY data.
            // This is ONLY for the crashdump environment as
            // these are ESDI devices.
            if (deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack ==
                    0x35 &&
                deviceExtension->lun[ldev].IdentifyData.NumberOfHeads ==
                    0x07) {

                KdPrint2((PRINT_PREFIX 
                           "FindDevices: Found nasty Compaq ESDI!\n"));

                // Change these values to something reasonable.
                deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack =
                    0x34;
                deviceExtension->lun[ldev].IdentifyData.NumberOfHeads =
                    0x0E;
            }

            if (deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack ==
                    0x35 &&
                deviceExtension->lun[ldev].IdentifyData.NumberOfHeads ==
                    0x0F) {

                KdPrint2((PRINT_PREFIX 
                           "FindDevices: Found nasty Compaq ESDI!\n"));

                // Change these values to something reasonable.
                deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack =
                    0x34;
                deviceExtension->lun[ldev].IdentifyData.NumberOfHeads =
                    0x0F;
            }


            if (deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack ==
                    0x36 &&
                deviceExtension->lun[ldev].IdentifyData.NumberOfHeads ==
                    0x07) {

                KdPrint2((PRINT_PREFIX "FindDevices: Found nasty UltraStor ESDI!\n"));

                // Change these values to something reasonable.
                deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack =
                    0x3F;
                deviceExtension->lun[ldev].IdentifyData.NumberOfHeads =
                    0x10;
                skipSetParameters = TRUE;
            }


            if (skipSetParameters)
                continue;

            statusByte = WaitOnBusy(chan, baseIoAddress2);

            // Select the device.
            SelectDrive(chan, baseIoAddress1, i & 0x01);
            GetStatus(chan, baseIoAddress2, statusByte);

            if (statusByte & IDE_STATUS_ERROR) {

                // Reset the device.
                KdPrint2((PRINT_PREFIX 
                            "FindDevices: Resetting controller before SetDriveParameters.\n"));

                AtapiWritePort1(chan, &baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER );
                AtapiStallExecution(500 * 1000);
                AtapiWritePort1(chan, &baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER);
                SelectDrive(chan, baseIoAddress1, i & 0x01);

                do {
                    // Wait for Busy to drop.
                    AtapiStallExecution(100);
                    GetStatus(chan, baseIoAddress2, statusByte);

                } while ((statusByte & IDE_STATUS_BUSY) && waitCount--);
            }

            statusByte = WaitOnBusy(chan, baseIoAddress2);

            KdPrint2((PRINT_PREFIX 
                        "FindDevices: Status before SetDriveParameters: (%#x) (%#x)\n",
                        statusByte,
                        AtapiReadPort1(chan, &baseIoAddress1->i.DriveSelect)));

            GetBaseStatus(chan, baseIoAddress1, statusByte);

            // Use the IDENTIFY data to set drive parameters.
            if (!SetDriveParameters(HwDeviceExtension,i,Channel)) {

                KdPrint2((PRINT_PREFIX 
                           "FindDevices: Set drive parameters for device %d failed\n",
                           i));
                // Don't use this device as writes could cause corruption.
                deviceExtension->lun[ldev].DeviceFlags = 0;
                continue;

            }
            if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_REMOVABLE_DRIVE) {

                // Pick up ALL IDE removable drives that conform to Yosemite V0.2...
                AtapiOnly = FALSE;
            }

            // Indicate that a device was found.
            if (!AtapiOnly) {
                deviceResponded = TRUE;
            }
        }
    }

/*    // Reset the controller. This is a feeble attempt to leave the ESDI
    // controllers in a state that ATDISK driver will recognize them.
    // The problem in ATDISK has to do with timings as it is not reproducible
    // in debug. The reset should restore the controller to its poweron state
    // and give the system enough time to settle.
    if (!deviceResponded) {

        AtapiWritePort1(chan, &baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER );
        AtapiStallExecution(50 * 1000);
        AtapiWritePort1(chan, &baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER);
    }
*/
    if(deviceResponded) {
        for (i = 0; i < 2; i++) {
            ldev = GET_LDEV2(Channel, i, 0);

            if(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT) {
                // Make sure some device (master is preferred) is selected on exit.
                KdPrint2((PRINT_PREFIX 
                           "FindDevices: select %d dev on exit\n", i));
                SelectDrive(chan, baseIoAddress1, i);
                break;
            }
        }
    }

    GetBaseStatus(chan, baseIoAddress1, statusByte);
    // Enable interrupts
    AtapiEnableInterrupts(deviceExtension, Channel);
//    AtapiWritePort1(chan, &baseIoAddress2->AlternateStatus, IDE_DC_A_4BIT );
    GetBaseStatus(chan, baseIoAddress1, statusByte);

    KdPrint2((PRINT_PREFIX 
               "FindDevices: returning %d\n",
               deviceResponded));

    return deviceResponded;

} // end FindDevices()
