diff options
| author | bouyer <bouyer@NetBSD.org> | 1999-08-06 12:00:23 +0000 |
|---|---|---|
| committer | bouyer <bouyer@NetBSD.org> | 1999-08-06 12:00:23 +0000 |
| commit | fae9929734603cdb453786d8d06e44e1d0674fc2 (patch) | |
| tree | 4688ce17e79e267016ba10e055802dde29999973 /sys/dev/ic | |
| parent | 54f2532106ef57336a675b068398fe8a3b64904a (diff) | |
- Add some debug printf (WDCPROBE) in _wdcreset_wait(), I've needed these
2 times in the past
- Set up timeout per xfer instead of per interrupt. This helps with
PIO transfer (we would call timeout()/untimout() several times for a
transfer).
- If we missed an interrupt for a PIO transfer, reset and restart it
immedialy, don't try to recover and continue. If we missed an interrupt we
may have lost a read/write cycle on the IDE bus. If this happens 1) we
corrupt data and 2) we enter an interrupt loop at the end of the xfer, as
the drive has some more data to read/write, but the host thinks the xfer is
done.
This last change fix the (or at last some of the) 'lookup after lost interrupt'
some peoples have been experiencing.
Diffstat (limited to 'sys/dev/ic')
| -rw-r--r-- | sys/dev/ic/wdc.c | 35 |
1 files changed, 33 insertions, 2 deletions
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) { |
