Index: src/sys/dev/ata/ata-all.h =================================================================== RCS file: /ncvs/src/sys/dev/ata/ata-all.h,v retrieving revision 1.133 diff -u -b -p -r1.133 ata-all.h --- src/sys/dev/ata/ata-all.h 17 Apr 2008 12:29:35 -0000 1.133 +++ src/sys/dev/ata/ata-all.h 11 Aug 2008 07:50:24 -0000 @@ -583,6 +583,7 @@ void ata_generic_hw(device_t dev); int ata_begin_transaction(struct ata_request *); int ata_end_transaction(struct ata_request *); void ata_generic_reset(device_t dev); +void ata_generic_reset2(device_t dev); int ata_generic_command(struct ata_request *request); /* macros for alloc/free of struct ata_request */ Index: src/sys/dev/ata/ata-chipset.c =================================================================== RCS file: /ncvs/src/sys/dev/ata/ata-chipset.c,v retrieving revision 1.224 diff -u -b -p -r1.224 ata-chipset.c --- src/sys/dev/ata/ata-chipset.c 10 Jul 2008 21:36:53 -0000 1.224 +++ src/sys/dev/ata/ata-chipset.c 11 Aug 2008 07:50:24 -0000 @@ -2535,14 +2535,20 @@ static int ata_ite_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); + u_int8_t t; if (ata_setup_interrupt(dev)) return ENXIO; ctlr->setmode = ata_ite_setmode; + ctlr->reset = ata_generic_reset2; /* set PCI mode and 66Mhz reference clock */ - pci_write_config(dev, 0x50, pci_read_config(dev, 0x50, 1) & ~0x83, 1); + t = pci_read_config(dev, 0x50, 1); + pci_write_config(dev, 0x50, t & ~0x83, 1); + if (bootverbose) + device_printf(dev, "t = 0x%02x, controller in %s mode\n", + t, t & 1 ? "smart": "pass through"); /* set default active & recover timings */ pci_write_config(dev, 0x54, 0x31, 1); Index: src/sys/dev/ata/ata-lowlevel.c =================================================================== RCS file: /ncvs/src/sys/dev/ata/ata-lowlevel.c,v retrieving revision 1.84 diff -u -b -p -r1.84 ata-lowlevel.c --- src/sys/dev/ata/ata-lowlevel.c 8 May 2008 17:55:44 -0000 1.84 +++ src/sys/dev/ata/ata-lowlevel.c 11 Aug 2008 07:50:24 -0000 @@ -454,6 +454,145 @@ end_continue: return ATA_OP_CONTINUES; } +static int +ata_check_device(device_t dev, int slave) +{ + struct ata_channel *ch = device_get_softc(dev); + + /* select device */ + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(slave)); + DELAY(10); + + ATA_IDX_OUTB(ch, ATA_SECTOR, 0x55); + ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xaa); + + ATA_IDX_OUTB(ch, ATA_SECTOR, 0xaa); + ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0x55); + + ATA_IDX_OUTB(ch, ATA_SECTOR, 0x55); + ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xaa); + + if (ATA_IDX_INB(ch, ATA_SECTOR) == 0x55 && + ATA_IDX_INB(ch, ATA_CYL_LSB) == 0xaa) + return 1; + + return 0; +} + +void +ata_generic_reset2(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + int mask = 0, timeout, i; + uint8_t stat0, stat1, lsb, msb, err = 0; + + if (ata_check_device(dev, ATA_MASTER)) + mask |= 0x01; + + if (!(ch->flags & ATA_NO_SLAVE) && + ata_check_device(dev, ATA_SLAVE)) + mask |= 0x02; + + if (bootverbose) + device_printf(dev, "reset mask = 0x%02x\n", mask); + + /* select device */ + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | + ATA_DEV(ATA_MASTER)); + DELAY(10); + + /* issue bus reset */ + ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS); + DELAY(10000); + ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS | ATA_A_RESET); + DELAY(10000); + ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS); + DELAY(150000); + + timeout = 0; + do { + DELAY(1000); + if (timeout++ > 31000) { + if (bootverbose) + device_printf(dev, "timeout after reset: stat0 = 0x%02x\n", + stat0); + break; + } + } while(((stat0 = ATA_IDX_INB(ch, ATA_STATUS)) & ATA_S_BUSY) && stat0 != 0xff); + + if (bootverbose) + device_printf(dev, "busy wait time: %d ms, stat0 = 0x%02x\n", timeout, stat0); + + if ((mask & 0x02) && stat0) { + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | + ATA_DEV(ATA_SLAVE)); + DELAY(10); + + for (i = 0; i < 2; i++) { + if (ATA_IDX_INB(ch, ATA_SECTOR) == 0x01 && + ATA_IDX_INB(ch, ATA_CYL_LSB) == 0x01) + break; + DELAY(50000); + } + timeout = 0; + do { + DELAY(1000); + if (timeout++ > 31000) { + if (bootverbose) + device_printf(dev, "timeout after reset: stat1 = 0x%02x\n", + stat1); + break; + } + } while(((stat1 = ATA_IDX_INB(ch, ATA_STATUS)) & ATA_S_BUSY) && stat1 != 0xff); + + if (bootverbose) + device_printf(dev, "busy wait time: %d ms, stat1 = 0x%02x\n", timeout, stat1); + } + if (mask & 0x01) { + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | + ATA_DEV(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 (lsb == 0 && msb == 0) + ch->devices |= ATA_ATA_MASTER; + else if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) + ch->devices |= ATA_ATAPI_MASTER; + else if (err == 0) /* diagnostic failed */ + ch->devices |= ATA_ATA_MASTER; + + if (bootverbose) + device_printf(dev, "stat0 = 0x%02x, err = 0x%02x, lsb = 0x%02x, msb = 0x%02x\n", + stat0, err, lsb, msb); + } + + if ((mask & 0x02) && err != 0x81) { + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | + ATA_DEV(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 (lsb == 0 && msb == 0) + ch->devices |= ATA_ATA_SLAVE; + else if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) + ch->devices |= ATA_ATAPI_SLAVE; + else if (err == 0) + ch->devices |= ATA_ATA_SLAVE; + + if (bootverbose) + device_printf(dev, "stat1 = 0x%02x, err = 0x%02x, lsb = 0x%02x, msb = 0x%02x\n", + stat1, err, lsb, msb); + } + if (bootverbose) + device_printf(dev, "reset done: ch->devices = 0x%x\n", ch->devices); +} + /* must be called with ATA channel locked and state_mtx held */ void ata_generic_reset(device_t dev)