diff options
| author | bouyer <bouyer@NetBSD.org> | 2004-07-31 21:26:42 +0000 |
|---|---|---|
| committer | bouyer <bouyer@NetBSD.org> | 2004-07-31 21:26:42 +0000 |
| commit | 7ffa35d1a22116956594de8f808c7abf31912a98 (patch) | |
| tree | 285bb74d8dd06591e5f2ad168be1a18315fca8d4 /sys/dev/ata/wd.c | |
| parent | 1fe630831fca7a6764e893910c062a2930cfb546 (diff) | |
Implement asynchronous channel reset.
Use this to reset the channel before doing a dump, instead of the hack in
wdc_exec_xfer() based on C_POLL. This hack was causing problems on
controllers with a shared queue, because we now can have C_POLL set during
concurent channels probes (problem found and analysed on sparc64 by
Martin Husemann).
This should even make core dumps marginally more reliable on ATA drives.
Diffstat (limited to 'sys/dev/ata/wd.c')
| -rw-r--r-- | sys/dev/ata/wd.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/sys/dev/ata/wd.c b/sys/dev/ata/wd.c index 7198f2ff256..a949e820e69 100644 --- a/sys/dev/ata/wd.c +++ b/sys/dev/ata/wd.c @@ -1,4 +1,4 @@ -/* $NetBSD: wd.c,v 1.280 2004/06/22 19:20:56 mycroft Exp $ */ +/* $NetBSD: wd.c,v 1.281 2004/07/31 21:26:43 bouyer Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved. @@ -66,7 +66,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.280 2004/06/22 19:20:56 mycroft Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.281 2004/07/31 21:26:43 bouyer Exp $"); #ifndef WDCDEBUG #define WDCDEBUG @@ -742,6 +742,9 @@ wddone(void *v) case TIMEOUT: errmsg = "device timeout"; goto retry; + case ERR_RESET: + errmsg = "channel reset"; + goto retry2; case ERROR: /* Don't care about media change bits */ if (wd->sc_wdc_bio.r_error != 0 && @@ -751,6 +754,7 @@ wddone(void *v) do_perror = 1; retry: /* Just reset and retry. Can we do more ? */ wd->atabus->ata_reset_channel(wd->drvp, 0); +retry2: diskerr(bp, "wd", errmsg, LOG_PRINTF, wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label); if (wd->retries < WDIORETRIES) @@ -1449,6 +1453,7 @@ wddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) if (wddumprecalibrated == 0) { wddumpmulti = wd->sc_multi; wddumprecalibrated = 1; + wd->atabus->ata_reset_channel(wd->drvp, AT_POLL | AT_RST_EMERG); wd->drvp->state = RESET; } |
