--- ata-lowlevel.c.orig Thu Oct 9 23:33:06 2003 +++ ata-lowlevel.c Thu Oct 16 22:28:06 2003 @@ -488,162 +488,222 @@ } /* must be called with ATA channel locked */ -static void -ata_reset(struct ata_channel *ch) +#define ATA_TIMEOUT 10000 +#define ATA_IDENTIFY_DEVICE 0xec +#define ATA_IDENTIFY_PACKET_DEVICE 0xa1 + +#define ATA_MASTER_MASK (ATA_ATA_MASTER | ATA_ATAPI_MASTER) +#define ATA_SLAVE_MASK (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE) + +static int +ata_wait_ready(struct ata_channel *ch) { - u_int8_t err, lsb, msb, ostat0, ostat1; - u_int8_t stat0 = 0, stat1 = 0; - int mask = 0, timeout; + int i, stat; - /* do we have any signs of ATA/ATAPI HW being present ? */ - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); - DELAY(10); - ostat0 = ATA_IDX_INB(ch, ATA_STATUS); - if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) { - stat0 = ATA_S_BUSY; - mask |= 0x01; - } - - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); - DELAY(10); - ostat1 = ATA_IDX_INB(ch, ATA_STATUS); - - /* in some setups we dont want to test for a slave */ - if (!(ch->flags & ATA_NO_SLAVE)) { - if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) { - stat1 = ATA_S_BUSY; - mask |= 0x02; - } + for (i = 0; i< ATA_TIMEOUT; i++) { + DELAY(10); + stat = ATA_IDX_INB(ch, ATA_STATUS); + if (!(stat & ATA_S_BUSY) && !(stat & ATA_S_DRQ)) + break; } + DELAY(10); - /* if nothing showed up no need to get any further */ - /* SOS is that too strong?, we just might loose devices here XXX */ - ch->devices = 0; - if (!mask) - return; + if (i == ATA_TIMEOUT) + return -1; - if (bootverbose) - ata_printf(ch, -1, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n", - mask, ostat0, ostat1); + return 0; +} + +static int +ata_soft_reset(struct ata_channel *ch) +{ + int i, stat; /* reset channel */ - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); - DELAY(10); ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET); DELAY(10000); ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS); - DELAY(10000); + DELAY(20000); + + for (i = 0; i< ATA_TIMEOUT; i++) { + DELAY(100); + /* stat = ATA_IDX_INB(ch, ATA_STATUS); */ + stat = ATA_IDX_INB(ch, ATA_ALTSTAT); + if (!(stat & ATA_S_BUSY)) + break; + } + if (i == ATA_TIMEOUT) + return -1; + + DELAY(10); + + return 0; +} + +static int +ata_device_select(struct ata_channel *ch, u_int8_t unit) +{ + if (ata_wait_ready(ch)) + return -1; + + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | unit); + DELAY(10); + + if (ata_wait_ready(ch)) + return -1; + + return 0; +} + +static int +ata_check_device_existence(struct ata_channel *ch) +{ + u_int8_t lsb, msb; + + ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0x55); + ATA_IDX_OUTB(ch, ATA_CYL_MSB, 0xaa); + + lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); + msb = ATA_IDX_INB(ch, ATA_CYL_MSB); + + if (lsb != 0x55 || msb != 0xaa) { + /* not found */ + ata_printf(ch, -1, "check dev existence:lsb=%02x msb=%02x\n", lsb, msb); + return 0; + } + + /* found */ + return 1; +} + +static int +identify_device(struct ata_channel *ch, int device, u_int8_t type) +{ + int i, j; + u_int8_t stat; + + ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS); + + ATA_IDX_OUTB(ch, ATA_FEATURE, 0); + ATA_IDX_OUTB(ch, ATA_COUNT, 0); + ATA_IDX_OUTB(ch, ATA_SECTOR, 0); + ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0); + ATA_IDX_OUTB(ch, ATA_CYL_MSB, 0); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | device); + ATA_IDX_OUTB(ch, ATA_CMD, type); + DELAY(10); - /* wait for BUSY to go inactive */ - for (timeout = 0; timeout < 310; timeout++) { - if (stat0 & ATA_S_BUSY) { - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); - DELAY(10); - err = ATA_IDX_INB(ch, ATA_ERROR); - lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); - msb = ATA_IDX_INB(ch, ATA_CYL_MSB); - stat0 = ATA_IDX_INB(ch, ATA_STATUS); - if (bootverbose) - ata_printf(ch, ATA_MASTER, - "stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", - stat0, err, lsb, msb); - if (!(stat0 & ATA_S_BUSY)) { - if ((err & 0x7f) == ATA_E_ILI) { - if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) { - ch->devices |= ATA_ATAPI_MASTER; - } - else if (stat0 & ATA_S_READY) { - ch->devices |= ATA_ATA_MASTER; - } - } - else if ((stat0 & 0x4f) && err == lsb && err == msb) { - stat0 |= ATA_S_BUSY; - } - } - } - if (stat1 & ATA_S_BUSY) { - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); - DELAY(10); - err = ATA_IDX_INB(ch, ATA_ERROR); - lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); - msb = ATA_IDX_INB(ch, ATA_CYL_MSB); - stat1 = ATA_IDX_INB(ch, ATA_STATUS); - if (bootverbose) - ata_printf(ch, ATA_SLAVE, - " stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", - stat1, err, lsb, msb); - if (!(stat1 & ATA_S_BUSY)) { - if ((err & 0x7f) == ATA_E_ILI) { - if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) { - ch->devices |= ATA_ATAPI_SLAVE; - } - else if (stat1 & ATA_S_READY) { - ch->devices |= ATA_ATA_SLAVE; - } - } - else if ((stat1 & 0x4f) && err == lsb && err == msb) { - stat1 |= ATA_S_BUSY; - } - } - } - if (mask == 0x01) /* wait for master only */ - if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 20)) - break; - if (mask == 0x02) /* wait for slave only */ - if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 20)) - break; - if (mask == 0x03) /* wait for both master & slave */ - if ((!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 20)) && - (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 20))) - break; - DELAY(100000); - } - - if (stat0 & ATA_S_BUSY) - mask &= ~0x01; - if (stat1 & ATA_S_BUSY) - mask &= ~0x02; + ATA_IDX_INB(ch, ATA_ALTSTAT); + + for (j = 0; j < ATA_TIMEOUT; j++) { + stat = ATA_IDX_INB(ch, ATA_ALTSTAT); + if (!(stat & ATA_S_BUSY)) + break; + } + if (j == ATA_TIMEOUT) { + if (bootverbose) + ata_printf(ch, -1, "identify timeout %02x\n", stat); + return -1; + } + + if (stat & ATA_S_ERROR) { + ATA_IDX_INB(ch, ATA_STATUS); + if (bootverbose) + ata_printf(ch, -1, "identify error %02x\n", stat); + return -1; + } + + if (!(stat & ATA_S_DRQ)) { + ATA_IDX_INB(ch, ATA_STATUS); + if (bootverbose) + ata_printf(ch, -1, "identify drq %02x\n", stat); + return -1; + } + + for (i = 0; i < 256; i++) { + ATA_IDX_INW(ch, ATA_DATA); + } + + ATA_IDX_INB(ch, ATA_STATUS); + return 0; +} + +static void +ata_reset(struct ata_channel *ch) +{ + int mask = 0; + int devices = 0; + int ret; + + ch->devices = 0; + + /* reset */ + if (ata_soft_reset(ch)) { + if (bootverbose) + ata_printf(ch, -1, "error or timeout while reset\n"); + return; + } + + /* check MASTER */ + if (ata_device_select(ch, ATA_MASTER)) + return; + ret = ata_check_device_existence(ch); + if (ret > 0) { + mask |= 0x01; + } + + /* check SLAVE */ + if (ata_device_select(ch, ATA_SLAVE)) + return; + ret = ata_check_device_existence(ch); + if (ret > 0) { + mask |= 0x02; + } + + /* ATA MASTER */ + if (mask & 0x01) { + if (!ata_device_select(ch, ATA_MASTER)) + if (!identify_device(ch, ATA_MASTER, ATA_IDENTIFY_DEVICE)) + devices |= ATA_ATA_MASTER; + } + + /* ATA SLAVE */ + if (mask & 0x02) { + if (!ata_device_select(ch, ATA_SLAVE)) + if (!identify_device(ch, ATA_SLAVE, ATA_IDENTIFY_DEVICE)) + devices |= ATA_ATA_SLAVE; + } if (bootverbose) - ata_printf(ch, -1, - "reset tp2 mask=%02x stat0=%02x stat1=%02x devices=0x%b\n", - mask, stat0, stat1, ch->devices, - "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); -#if 0 - if (!mask) - return; - - if (mask & 0x01 && ostat0 != 0x00 && - !(ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER))) { - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); - DELAY(10); - ATA_IDX_OUTB(ch, ATA_ERROR, 0x58); - ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5); - err = ATA_IDX_INB(ch, ATA_ERROR); - lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); - if (bootverbose) - ata_printf(ch, ATA_MASTER, "ATA err=0x%02x lsb=0x%02x\n", err, lsb); - if (err != 0x58 && lsb == 0xa5) - ch->devices |= ATA_ATA_MASTER; - } - if (mask & 0x02 && ostat1 != 0x00 && - !(ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE))) { - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); - DELAY(10); - ATA_IDX_OUTB(ch, ATA_ERROR, 0x58); - ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5); - err = ATA_IDX_INB(ch, ATA_ERROR); - lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); - if (bootverbose) - ata_printf(ch, ATA_SLAVE, "ATA err=0x%02x lsb=0x%02x\n", err, lsb); - if (err != 0x58 && lsb == 0xa5) - ch->devices |= ATA_ATA_SLAVE; + ata_printf(ch, -1, "reset check ATA: devices=%02x\n", devices); + + /* ATAPI MASTER */ + if (mask & 0x01) { + if (!ata_device_select(ch, ATA_MASTER)) + if (!identify_device(ch, ATA_MASTER, ATA_IDENTIFY_PACKET_DEVICE)) + devices |= ATA_ATAPI_MASTER; + } + + /* ATAPI SLAVE */ + if (mask & 0x02) { + if (!ata_device_select(ch, ATA_SLAVE)) + if (!identify_device(ch, ATA_SLAVE, ATA_IDENTIFY_PACKET_DEVICE)) + devices |= ATA_ATAPI_SLAVE; } if (bootverbose) - ata_printf(ch, -1, "reset tp3 devices=0x%b\n", ch->devices, - "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); -#endif + ata_printf(ch, -1, "reset check ATAPI: devices=%02x\n", devices); + + if (!((devices & ATA_ATA_MASTER) && (devices & ATA_ATAPI_MASTER))) + ch->devices |= (devices & ATA_MASTER_MASK); + + if (!((devices & ATA_ATA_SLAVE) && (devices & ATA_ATAPI_SLAVE))) + ch->devices |= (devices & ATA_SLAVE_MASK); + + if (bootverbose) + ata_printf(ch, -1, "reset check final: devices=%02x\n", ch->devices); + + return; } static int