diff --git a/storage/pc-ata/ata.c b/storage/pc-ata/ata.c index 3e763fb0d..1f647f6ad 100644 --- a/storage/pc-ata/ata.c +++ b/storage/pc-ata/ata.c @@ -22,6 +22,9 @@ #include #include +#include +#include + #include "ata.h" #define ATA_SECTORSZ_MAX 4096 /* Max supported sector size */ @@ -33,6 +36,12 @@ ata_common_t ata_common; static ata_bus_t *buses; +static int pci_dev_classes[2] = { + 0x0101, /* IDE interface */ + 0x0105, /* ATA controller */ +}; + + static uint32_t ata_readreg(void *base, uint8_t reg, uint8_t size) { uintptr_t addr = (uintptr_t)base; @@ -610,11 +619,16 @@ static int ata_initbus(void *base, void *ctrl, ata_bus_t *bus) int ata_init(void) { + int err; ata_bus_t *bus1, *bus2; + int bus1_found, bus2_found; + addr_t ata1_base, ata1_ctrl, ata2_base, ata2_ctrl; ata_common.ndevs = 0; ata_common.devs = NULL; buses = NULL; + bus1_found = 0; + bus2_found = 0; if ((bus1 = (ata_bus_t *)malloc(sizeof(ata_bus_t))) == NULL) return -ENOMEM; @@ -624,11 +638,72 @@ int ata_init(void) return -ENOMEM; } - if (ata_initbus((void *)(ATA1_BASE | 0x1), (void *)(ATA1_CTRL | 0x1), bus1) < 0) - free(bus1); + /* try most common adresses first */ + ata1_base = ATA1_BASE; + ata1_ctrl = ATA1_CTRL; + ata2_base = ATA2_BASE; + ata2_ctrl = ATA2_CTRL; + + if (ata_initbus((void *)(ata1_base | 0x1), (void *)(ata1_ctrl | 0x1), bus1) == EOK) { + bus1_found = 1; + } - if (ata_initbus((void *)(ATA2_BASE | 0x1), (void *)(ATA2_CTRL | 0x1), bus2) < 0) - free(bus2); + if (ata_initbus((void *)(ata2_base | 0x1), (void *)(ata2_ctrl | 0x1), bus2) == EOK) { + bus2_found = 1; + } + + if (buses == NULL) { + /* no buses found on common addresses. look through pci config BARs */ + platformctl_t pctl = { .action = pctl_get, .type = pctl_pci }; + + for (uint8_t i = 0; i < sizeof(pci_dev_classes); i++) { + pctl.pci.id.vendor = PCI_ANY; + pctl.pci.id.device = PCI_ANY; + pctl.pci.id.subvendor = PCI_ANY; + pctl.pci.id.subdevice = PCI_ANY; + pctl.pci.dev.bus = 0; + pctl.pci.dev.dev = 0; + pctl.pci.dev.func = 0; + pctl.pci.caps = NULL; + + pctl.pci.id.cl = pci_dev_classes[i]; + err = platformctl(&pctl); + if (err < 0) { + /* try next device class */ + continue; + } + + ata1_base = pctl.pci.dev.resources[0].base; + ata1_ctrl = pctl.pci.dev.resources[1].base; + ata2_base = pctl.pci.dev.resources[2].base; + ata2_ctrl = pctl.pci.dev.resources[3].base; + + if (ata_initbus((void *)(ata1_base | 0x1), (void *)(ata1_ctrl | 0x1), bus1) == EOK) { + bus1_found = 1; + } + + if (ata_initbus((void *)(ata2_base | 0x1), (void *)(ata2_ctrl | 0x1), bus2) == EOK) { + bus2_found = 1; + } + + if (buses != NULL) { + /* at least one bus found via pci config */ + break; + } + } + + if (bus1_found == 0) { + free(bus1); + } + + if (bus2_found == 0) { + free(bus2); + } + + if (buses == NULL) { + return -ENODEV; + } + } return EOK; }