int ata_wait(struct ata_device *atadev, u_int8_t mask) { int timeout = 0; DELAY(1); while (timeout < 5000000) { /* timeout 5 secs */ atadev->channel->status = ATA_INB(atadev->channel->r_io, ATA_STATUS); /* if drive fails status, reselect the drive just to be sure */ if (atadev->channel->status == 0xff) { ata_prtdev(atadev, "no status, reselecting device\n"); ATA_OUTB(atadev->channel->r_io, ATA_DRIVE, ATA_D_IBM|atadev->unit); DELAY(10); atadev->channel->status = ATA_INB(atadev->channel->r_io,ATA_STATUS); if (atadev->channel->status == 0xff) return -1; } /* are we done ? */ if (!(atadev->channel->status & ATA_S_BUSY)) break; if (timeout > 1000) { timeout += 1000; DELAY(1000); } else { timeout += 10; DELAY(10); } } if (atadev->channel->status & ATA_S_ERROR) atadev->channel->error = ATA_INB(atadev->channel->r_io, ATA_ERROR); if (timeout >= 5000000) return -1; if (!mask) return (atadev->channel->status & ATA_S_ERROR); /* Wait 50 msec for bits wanted. */ timeout = 5000; while (timeout--) { atadev->channel->status = ATA_INB(atadev->channel->r_io, ATA_STATUS); if ((atadev->channel->status & mask) == mask) { if (atadev->channel->status & ATA_S_ERROR) atadev->channel->error=ATA_INB(atadev->channel->r_io,ATA_ERROR); return (atadev->channel->status & ATA_S_ERROR); } DELAY (10); } return -1; }
static int ata_nvidia_status(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ctlr->chip->cfg1 & NV4 ? 0x0440 : 0x0010; int shift = ch->unit << (ctlr->chip->cfg1 & NVQ ? 4 : 2); u_int32_t istatus; /* get interrupt status */ if (ctlr->chip->cfg1 & NVQ) istatus = ATA_INL(ctlr->r_res2, offset); else istatus = ATA_INB(ctlr->r_res2, offset); /* do we have any PHY events ? */ if (istatus & (0x0c << shift)) ata_sata_phy_check_events(dev, -1); /* clear interrupt(s) */ if (ctlr->chip->cfg1 & NVQ) ATA_OUTL(ctlr->r_res2, offset, (0x0f << shift) | 0x00f000f0); else ATA_OUTB(ctlr->r_res2, offset, (0x0f << shift)); /* do we have any device action ? */ return (istatus & (0x01 << shift)); }
static int ata_service(struct ata_channel *ch) { /* do we have a SERVICE request from the drive ? */ if ((ch->status & (ATA_S_SERVICE|ATA_S_ERROR|ATA_S_DRQ)) == ATA_S_SERVICE) { ATA_OUTB(ch->r_bmio, ATA_BMSTAT_PORT, ata_dmastatus(ch) | ATA_BMSTAT_INTERRUPT); #if NATADISK > 0 if ((ATA_INB(ch->r_io, ATA_DRIVE) & ATA_SLAVE) == ATA_MASTER) { if ((ch->devices & ATA_ATA_MASTER) && ch->device[MASTER].driver) return ad_service((struct ad_softc *) ch->device[MASTER].driver, 0); } else { if ((ch->devices & ATA_ATA_SLAVE) && ch->device[SLAVE].driver) return ad_service((struct ad_softc *) ch->device[SLAVE].driver, 0); } #endif } return ATA_OP_FINISHED; }
void ata_reset(struct ata_channel *ch) { u_int8_t lsb, msb, ostat0, ostat1; u_int8_t stat0 = 0, stat1 = 0; int mask = 0, timeout; /* do we have any signs of ATA/ATAPI HW being present ? */ ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); DELAY(10); ostat0 = ATA_INB(ch->r_io, ATA_STATUS); if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) { stat0 = ATA_S_BUSY; mask |= 0x01; } ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); DELAY(10); ostat1 = ATA_INB(ch->r_io, ATA_STATUS); if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) { stat1 = ATA_S_BUSY; mask |= 0x02; } ch->devices = 0; if (!mask) return; /* in some setups we dont want to test for a slave */ if (ch->flags & ATA_NO_SLAVE) { stat1 = 0x0; mask &= ~0x02; } if (bootverbose) ata_printf(ch, -1, "mask=%02x ostat0=%02x ostat2=%02x\n", mask, ostat0, ostat1); /* reset channel */ ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); DELAY(10); ATA_OUTB(ch->r_altio, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET); DELAY(10000); ATA_OUTB(ch->r_altio, ATA_ALTSTAT, ATA_A_IDS); DELAY(100000); ATA_INB(ch->r_io, ATA_ERROR); /* wait for BUSY to go inactive */ for (timeout = 0; timeout < 310000; timeout++) { if (stat0 & ATA_S_BUSY) { ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); DELAY(10); /* check for ATAPI signature while its still there */ lsb = ATA_INB(ch->r_io, ATA_CYL_LSB); msb = ATA_INB(ch->r_io, ATA_CYL_MSB); stat0 = ATA_INB(ch->r_io, ATA_STATUS); if (!(stat0 & ATA_S_BUSY)) { if (bootverbose) ata_printf(ch, ATA_MASTER, "ATAPI %02x %02x\n", lsb, msb); if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) ch->devices |= ATA_ATAPI_MASTER; } } if (stat1 & ATA_S_BUSY) { ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); DELAY(10); /* check for ATAPI signature while its still there */ lsb = ATA_INB(ch->r_io, ATA_CYL_LSB); msb = ATA_INB(ch->r_io, ATA_CYL_MSB); stat1 = ATA_INB(ch->r_io, ATA_STATUS); if (!(stat1 & ATA_S_BUSY)) { if (bootverbose) ata_printf(ch, ATA_SLAVE, "ATAPI %02x %02x\n", lsb, msb); if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) ch->devices |= ATA_ATAPI_SLAVE; } } if (mask == 0x01) /* wait for master only */ if (!(stat0 & ATA_S_BUSY)) break; if (mask == 0x02) /* wait for slave only */ if (!(stat1 & ATA_S_BUSY)) break; if (mask == 0x03) /* wait for both master & slave */ if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY)) break; DELAY(100); } DELAY(10); ATA_OUTB(ch->r_altio, ATA_ALTSTAT, ATA_A_4BIT); if (stat0 & ATA_S_BUSY) mask &= ~0x01; if (stat1 & ATA_S_BUSY) mask &= ~0x02; if (bootverbose) ata_printf(ch, -1, "mask=%02x stat0=%02x stat1=%02x\n", mask, stat0, stat1); if (!mask) return; if (mask & 0x01 && ostat0 != 0x00 && !(ch->devices & ATA_ATAPI_MASTER)) { ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); DELAY(10); ATA_OUTB(ch->r_io, ATA_ERROR, 0x58); ATA_OUTB(ch->r_io, ATA_CYL_LSB, 0xa5); lsb = ATA_INB(ch->r_io, ATA_ERROR); msb = ATA_INB(ch->r_io, ATA_CYL_LSB); if (bootverbose) ata_printf(ch, ATA_MASTER, "ATA %02x %02x\n", lsb, msb); if (lsb != 0x58 && msb == 0xa5) ch->devices |= ATA_ATA_MASTER; } if (mask & 0x02 && ostat1 != 0x00 && !(ch->devices & ATA_ATAPI_SLAVE)) { ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); DELAY(10); ATA_OUTB(ch->r_io, ATA_ERROR, 0x58); ATA_OUTB(ch->r_io, ATA_CYL_LSB, 0xa5); lsb = ATA_INB(ch->r_io, ATA_ERROR); msb = ATA_INB(ch->r_io, ATA_CYL_LSB); if (bootverbose) ata_printf(ch, ATA_SLAVE, "ATA %02x %02x\n", lsb, msb); if (lsb != 0x58 && msb == 0xa5) ch->devices |= ATA_ATA_SLAVE; } if (bootverbose) ata_printf(ch, -1, "devices=%02x\n", ch->devices); }
static void ata_intr(void *data) { struct ata_channel *ch = (struct ata_channel *)data; /* * on PCI systems we might share an interrupt line with another * device or our twin ATA channel, so call ch->intr_func to figure * out if it is really an interrupt we should process here */ if (ch->intr_func && ch->intr_func(ch)) return; /* if drive is busy it didn't interrupt */ if (ATA_INB(ch->r_altio, ATA_ALTSTAT) & ATA_S_BUSY) { DELAY(100); if (!(ATA_INB(ch->r_altio, ATA_ALTSTAT) & ATA_S_DRQ)) return; } /* clear interrupt and get status */ ch->status = ATA_INB(ch->r_io, ATA_STATUS); if (ch->status & ATA_S_ERROR) ch->error = ATA_INB(ch->r_io, ATA_ERROR); /* find & call the responsible driver to process this interrupt */ switch (ch->active) { #if NATADISK > 0 case ATA_ACTIVE_ATA: if (!ch->running || ad_interrupt(ch->running) == ATA_OP_CONTINUES) return; break; #endif #if DEV_ATAPIALL case ATA_ACTIVE_ATAPI: if (!ch->running || atapi_interrupt(ch->running) == ATA_OP_CONTINUES) return; break; #endif case ATA_WAIT_INTR: case ATA_WAIT_INTR | ATA_CONTROL: wakeup((caddr_t)ch); break; case ATA_WAIT_READY: case ATA_WAIT_READY | ATA_CONTROL: break; case ATA_IDLE: if (ch->flags & ATA_QUEUED) { ch->active = ATA_ACTIVE; if (ata_service(ch) == ATA_OP_CONTINUES) return; } /* FALLTHROUGH */ default: #ifdef ATA_DEBUG { static int intr_count = 0; if (intr_count++ < 10) ata_printf(ch, -1, "unwanted interrupt #%d active=%02x s=%02x\n", intr_count, ch->active, ch->status); } #endif break; } ch->active &= ATA_CONTROL; if (ch->active & ATA_CONTROL) return; ch->running = NULL; ata_start(ch); return; }