diff --git a/kernel/dev/ide.c b/kernel/dev/ide.c index 0a2c602..51a6424 100644 --- a/kernel/dev/ide.c +++ b/kernel/dev/ide.c @@ -130,6 +130,18 @@ void ideinit(void) { initlock(&idelock, "ide"); + + // No controller at all: the bus floats and the status port reads 0xFF. + // That has BSY set, so idewait() below took it for a drive that was still + // busy and waited out its full second -- a second of every boot on q35 and + // on any PC whose disks are SATA, which is all of them. 0xFF is not a + // status any drive reports (BSY and DRDY are never both set), so it can be + // answered at once. + if(inb(0x1f7) == 0xFF){ + kinfo("ide: no controller at the legacy ports\n"); + return; + } + // ISA signalling: edge-triggered, active high. Everything at a fixed // legacy port is wired this way; PCI devices are not. irq_register(IRQ_IDE, ide_irq, 0, "ide", 0); diff --git a/kernel/drivers/storage/ahci/ahci.c b/kernel/drivers/storage/ahci/ahci.c index 0b5b743..24733e9 100644 --- a/kernel/drivers/storage/ahci/ahci.c +++ b/kernel/drivers/storage/ahci/ahci.c @@ -167,9 +167,22 @@ port_stop(volatile uint8 *r) static int port_link(volatile uint8 *r) { + // A drive told to spin up a moment ago takes a few milliseconds to be seen + // at all; give it twenty before calling the port empty. uint32 ssts = rd(r, PX_SSTS); + for (int i = 0; i < 20 && (ssts & 0xF) == 0; i++) { + microdelay(1000); + ssts = rd(r, PX_SSTS); + } if ((ssts & 0xF) == 3) return 1; + // DET = 0 is "no device detected": an empty port, not a slow one. This + // used to COMRESET every empty port and wait a second for an answer that + // could not come -- four seconds of boot on a q35 with one disk, all of it + // with interrupts off. Only a device that is detected without a link + // (DET = 1) is worth the reset. + if ((ssts & 0xF) != 1) + return 0; wr(r, PX_SCTL, (rd(r, PX_SCTL) & ~0xFu) | 1); // DET = 1: COMRESET microdelay(2000); // at least 1 ms