diff options
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/ata/ata_wdc.c | 49 | ||||
| -rw-r--r-- | sys/dev/ic/wdc.c | 35 | ||||
| -rw-r--r-- | sys/dev/scsipi/atapi_wdc.c | 22 |
3 files changed, 85 insertions, 21 deletions
diff --git a/sys/dev/ata/ata_wdc.c b/sys/dev/ata/ata_wdc.c index 14e74ad4eca..79a39234d1c 100644 --- a/sys/dev/ata/ata_wdc.c +++ b/sys/dev/ata/ata_wdc.c @@ -1,4 +1,4 @@ -/* $NetBSD: ata_wdc.c,v 1.19 1999/04/01 21:46:28 bouyer Exp $ */ +/* $NetBSD: ata_wdc.c,v 1.20 1999/08/06 12:00:23 bouyer Exp $ */ /* * Copyright (c) 1998 Manuel Bouyer. @@ -117,6 +117,7 @@ int wdcdebug_wd_mask = 0; #define ATA_DELAY 10000 /* 10s for a drive I/O */ void wdc_ata_bio_start __P((struct channel_softc *,struct wdc_xfer *)); +void _wdc_ata_bio_start __P((struct channel_softc *,struct wdc_xfer *)); int wdc_ata_bio_intr __P((struct channel_softc *, struct wdc_xfer *, int)); void wdc_ata_bio_done __P((struct channel_softc *, struct wdc_xfer *)); int wdc_ata_ctrl_intr __P((struct channel_softc *, struct wdc_xfer *, int)); @@ -161,6 +162,22 @@ wdc_ata_bio_start(chp, xfer) struct wdc_xfer *xfer; { struct ata_bio *ata_bio = xfer->cmd; + WDCDEBUG_PRINT(("wdc_ata_bio_start %s:%d:%d\n", + chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), + DEBUG_XFERS); + + /* start timeout machinery */ + if ((ata_bio->flags & ATA_POLL) == 0) + timeout(wdctimeout, chp, ATA_DELAY / 1000 * hz); + _wdc_ata_bio_start(chp, xfer); +} + +void +_wdc_ata_bio_start(chp, xfer) + struct channel_softc *chp; + struct wdc_xfer *xfer; +{ + struct ata_bio *ata_bio = xfer->cmd; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; u_int16_t cyl; u_int8_t head, sect, cmd = 0; @@ -168,10 +185,9 @@ wdc_ata_bio_start(chp, xfer) int ata_delay; int dma_flags = 0; - WDCDEBUG_PRINT(("wdc_ata_bio_start %s:%d:%d\n", + WDCDEBUG_PRINT(("_wdc_ata_bio_start %s:%d:%d\n", chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), - DEBUG_XFERS); - + DEBUG_INTR | DEBUG_XFERS); /* Do control operations specially. */ if (drvp->state < READY) { /* @@ -181,10 +197,10 @@ wdc_ata_bio_start(chp, xfer) */ /* at this point, we should only be in RECAL state */ if (drvp->state != RECAL) { - printf("%s:%d:%d: bad state %d in wdc_ata_bio_start\n", + printf("%s:%d:%d: bad state %d in _wdc_ata_bio_start\n", chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, drvp->state); - panic("wdc_ata_bio_start: bad state"); + panic("_wdc_ata_bio_start: bad state"); } xfer->c_intr = wdc_ata_ctrl_intr; bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, @@ -195,8 +211,6 @@ wdc_ata_bio_start(chp, xfer) drvp->state = RECAL_WAIT; if ((ata_bio->flags & ATA_POLL) == 0) { chp->ch_flags |= WDCF_IRQ_WAIT; - timeout(wdctimeout, chp, - ATA_DELAY / 1000 * hz); } else { /* Wait for at last 400ns for status bit to be valid */ DELAY(1); @@ -368,7 +382,6 @@ again: intr: /* Wait for IRQ (either real or polled) */ if ((ata_bio->flags & ATA_POLL) == 0) { chp->ch_flags |= WDCF_IRQ_WAIT; - timeout(wdctimeout, chp, ata_delay / 1000 * hz); } else { /* Wait for at last 400ns for status bit to be valid */ delay(1); @@ -416,6 +429,16 @@ wdc_ata_bio_intr(chp, xfer, irq) dma_flags |= (ata_bio->flags & ATA_POLL) ? WDC_DMA_POLL : 0; } + /* + * if we missed an interrupt in a PIO transfer, reset and restart. + * Don't try to continue transfer, we may have missed cycles. + */ + if ((xfer->c_flags & (C_TIMEOU | C_DMA)) == C_TIMEOU) { + ata_bio->error = TIMEOUT; + wdc_ata_bio_done(chp, xfer); + return 1; + } + /* Ack interrupt done by wait_for_unbusy */ if (wait_for_unbusy(chp, (irq == 0) ? ATA_DELAY : 0) < 0) { @@ -532,9 +555,9 @@ end: if (xfer->c_bcount > 0) { if ((ata_bio->flags & ATA_POLL) == 0) { /* Start the next operation */ - wdc_ata_bio_start(chp, xfer); + _wdc_ata_bio_start(chp, xfer); } else { - /* Let wdc_ata_bio_start do the loop */ + /* Let _wdc_ata_bio_start do the loop */ return 1; } } else { /* Done with this transfer */ @@ -559,6 +582,7 @@ wdc_ata_bio_done(chp, xfer) (u_int)xfer->c_flags), DEBUG_XFERS); + untimeout(wdctimeout, chp); if (ata_bio->error == NOERROR) drvp->n_dmaerrs = 0; else if (drvp->n_dmaerrs >= NERRS_MAX) { @@ -696,13 +720,12 @@ again: * The drive is usable now */ xfer->c_intr = wdc_ata_bio_intr; - wdc_ata_bio_start(chp, xfer); + _wdc_ata_bio_start(chp, xfer); return 1; } if ((ata_bio->flags & ATA_POLL) == 0) { chp->ch_flags |= WDCF_IRQ_WAIT; - timeout(wdctimeout, chp, ATA_DELAY / 1000 * hz); } else { goto again; } diff --git a/sys/dev/ic/wdc.c b/sys/dev/ic/wdc.c index 2dc11adc4f3..b858ee32164 100644 --- a/sys/dev/ic/wdc.c +++ b/sys/dev/ic/wdc.c @@ -1,4 +1,4 @@ -/* $NetBSD: wdc.c,v 1.69 1999/07/30 14:59:10 bouyer Exp $ */ +/* $NetBSD: wdc.c,v 1.70 1999/08/06 12:00:25 bouyer Exp $ */ /* @@ -533,7 +533,6 @@ wdcintr(arg) } WDCDEBUG_PRINT(("wdcintr\n"), DEBUG_INTR); - untimeout(wdctimeout, chp); chp->ch_flags &= ~WDCF_IRQ_WAIT; xfer = chp->ch_queue->sc_xfer.tqh_first; return xfer->c_intr(chp, xfer, 1); @@ -595,16 +594,32 @@ __wdcwait_reset(chp, drv_mask) { int timeout; u_int8_t st0, st1; +#ifdef WDCDEBUG + u_int8_t sc0, sn0, cl0, ch0; + u_int8_t sc1, sn1, cl1, ch1; +#endif /* wait for BSY to deassert */ for (timeout = 0; timeout < WDCNDELAY_RST;timeout++) { bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, WDSD_IBM); /* master */ delay(10); st0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status); +#ifdef WDCDEBUG + sc0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_seccnt); + sn0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_sector); + cl0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo); + ch0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_hi); +#endif bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, WDSD_IBM | 0x10); /* slave */ delay(10); st1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status); +#ifdef WDCDEBUG + sc1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_seccnt); + sn1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_sector); + cl1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo); + ch1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_hi); +#endif if ((drv_mask & 0x01) == 0) { /* no master */ @@ -632,6 +647,15 @@ __wdcwait_reset(chp, drv_mask) if (st1 & WDCS_BSY) drv_mask &= ~0x02; end: + WDCDEBUG_PRINT(("%s:%d:0: after reset, sc=0x%x sn=0x%x " + "cl=0x%x ch=0x%x\n", + chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe", + chp->channel, sc0, sn0, cl0, ch0), DEBUG_PROBE); + WDCDEBUG_PRINT(("%s:%d:1: after reset, sc=0x%x sn=0x%x " + "cl=0x%x ch=0x%x\n", + chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe", + chp->channel, sc1, sn1, cl1, ch1), DEBUG_PROBE); + WDCDEBUG_PRINT(("%s:%d: wdcwait_reset() end, st0=0x%x, st1=0x%x\n", chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe", chp->channel, st0, st1), DEBUG_PROBE); @@ -717,7 +741,11 @@ wdctimeout(arg) * Call the interrupt routine. If we just missed and interrupt, * it will do what's needed. Else, it will take the needed * action (reset the device). + * Before that we need to reinstall the timeout callback, + * in case it will miss another irq while in this transfer + * We arbitray chose it to be 1s */ + timeout(wdctimeout, chp, hz); xfer->c_flags |= C_TIMEOU; chp->ch_flags &= ~WDCF_IRQ_WAIT; xfer->c_intr(chp, xfer, 1); @@ -1121,6 +1149,9 @@ __wdccommand_done(chp, xfer) WDCDEBUG_PRINT(("__wdccommand_done %s:%d:%d\n", chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), DEBUG_FUNCS); + + untimeout(wdctimeout, chp); + if (chp->ch_status & WDCS_DWF) wdc_c->flags |= AT_DF; if (chp->ch_status & WDCS_ERR) { diff --git a/sys/dev/scsipi/atapi_wdc.c b/sys/dev/scsipi/atapi_wdc.c index 0db4d23ea55..e118708cd05 100644 --- a/sys/dev/scsipi/atapi_wdc.c +++ b/sys/dev/scsipi/atapi_wdc.c @@ -1,4 +1,4 @@ -/* $NetBSD: atapi_wdc.c,v 1.23 1999/05/05 21:35:15 perry Exp $ */ +/* $NetBSD: atapi_wdc.c,v 1.24 1999/08/06 12:00:26 bouyer Exp $ */ /* * Copyright (c) 1998 Manuel Bouyer. @@ -238,6 +238,9 @@ wdc_atapi_start(chp, xfer) xfer->c_flags |= C_DMA; else xfer->c_flags &= ~C_DMA; + /* start timeout machinery */ + if ((sc_xfer->flags & SCSI_POLL) == 0) + timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000); /* Do control operations specially. */ if (drvp->state < READY) { if (drvp->state != PIOMODE) { @@ -285,7 +288,6 @@ wdc_atapi_start(chp, xfer) wdc_atapi_intr(chp, xfer, 0); } else { chp->ch_flags |= WDCF_IRQ_WAIT; - timeout(wdctimeout, chp, hz); } if (sc_xfer->flags & SCSI_POLL) { while ((sc_xfer->flags & ITSDONE) == 0) { @@ -322,6 +324,15 @@ wdc_atapi_intr(chp, xfer, irq) drvp->state); panic("wdc_atapi_intr: bad state\n"); } + /* + * If we missed an interrupt in a PIO transfer, reset and restart. + * Don't try to continue transfer, we may have missed cycles. + */ + if ((xfer->c_flags & (C_TIMEOU | C_DMA)) == C_TIMEOU) { + sc_xfer->error = XS_TIMEOUT; + wdc_atapi_reset(chp, xfer); + } + /* Ack interrupt done in wait_for_unbusy */ bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, WDSD_IBM | (xfer->drive << 4)); @@ -425,7 +436,6 @@ again: if ((sc_xfer->flags & SCSI_POLL) == 0) { chp->ch_flags |= WDCF_IRQ_WAIT; - timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000); } return 1; @@ -503,7 +513,6 @@ again: } if ((sc_xfer->flags & SCSI_POLL) == 0) { chp->ch_flags |= WDCF_IRQ_WAIT; - timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000); } return 1; @@ -580,7 +589,6 @@ again: } if ((sc_xfer->flags & SCSI_POLL) == 0) { chp->ch_flags |= WDCF_IRQ_WAIT; - timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000); } return 1; @@ -636,6 +644,7 @@ again: sizeof(sc_xfer->sense.scsi_sense); xfer->c_skip = 0; xfer->c_flags |= C_SENSE; + untimeout(wdctimeout, chp); wdc_atapi_start(chp, xfer); return 1; } @@ -753,13 +762,13 @@ piomode: ready: drvp->state = READY; xfer->c_intr = wdc_atapi_intr; + untimeout(wdctimeout, chp); wdc_atapi_start(chp, xfer); return 1; } if ((sc_xfer->flags & SCSI_POLL) == 0) { chp->ch_flags |= WDCF_IRQ_WAIT; xfer->c_intr = wdc_atapi_ctrl; - timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000); } else { goto again; } @@ -797,6 +806,7 @@ wdc_atapi_done(chp, xfer) WDCDEBUG_PRINT(("wdc_atapi_done %s:%d:%d: flags 0x%x\n", chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, (u_int)xfer->c_flags), DEBUG_XFERS); + untimeout(wdctimeout, chp); /* remove this command from xfer queue */ wdc_free_xfer(chp, xfer); sc_xfer->flags |= ITSDONE; |
