summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2011-04-15 20:53:29 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2011-04-15 20:53:29 +0000
commit62106b0b2072837cb16ef80f9ce1d816218db92d (patch)
tree260678456a8f6b70c8fc250bd4e61eaa09762301 /sys
parent41664536ca087a7e316bcdae0d145df6461e98f9 (diff)
Change wdc_reset_channel() to take a `no wait' argument. Pass in turn this
argument to wdcreset(), to have it skip waiting until active channels see their BUSY bit clear in the status register. Use this feature in the resume path, during the first reset operation. The first reset is supposed to only wake up the controller, and the disks don't come back until the second reset is issued, therefore waiting for them to report themselves as ready after the first reset, but before the second, is moot - and as a matter of fact some controllers, such as the AMD 754 and clones/offspring (e.g. Geode) keep the BUSY bit asserted after the first reset. Last, but not least, make sure wd@ata invokes wd_get_params() again before returning from the resume code, as we will still be using polled transfers for a short while. This causes the Lemote Yeelong to resume within less than one second, instead of the lousy 30 seconds wait between the two resets; and the wd_get_params() voodoo prevents it from getting spurious ide interrupts afterwards. wd_get_params() magic from dlg; rest of the work by yours truly after enough prodding by dlg@ and pirofti@, among others. ok deraadt@ dlg@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ata/atavar.h4
-rw-r--r--sys/dev/ata/wd.c11
-rw-r--r--sys/dev/atapiscsi/atapiscsi.c8
-rw-r--r--sys/dev/ic/wdc.c16
-rw-r--r--sys/dev/ic/wdcvar.h7
5 files changed, 26 insertions, 20 deletions
diff --git a/sys/dev/ata/atavar.h b/sys/dev/ata/atavar.h
index 8214bc07358..9a57392b8ac 100644
--- a/sys/dev/ata/atavar.h
+++ b/sys/dev/ata/atavar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: atavar.h,v 1.19 2010/07/23 07:47:13 jsg Exp $ */
+/* $OpenBSD: atavar.h,v 1.20 2011/04/15 20:53:28 miod Exp $ */
/* $NetBSD: atavar.h,v 1.13 1999/03/10 13:11:43 bouyer Exp $ */
/*
@@ -164,7 +164,7 @@ void wdc_probe_caps(struct ata_drive_datas*, struct ataparams *);
void wdc_print_caps(struct ata_drive_datas*);
int wdc_downgrade_mode(struct ata_drive_datas*);
-void wdc_reset_channel(struct ata_drive_datas *);
+void wdc_reset_channel(struct ata_drive_datas *, int);
int wdc_ata_addref(struct ata_drive_datas *);
void wdc_ata_delref(struct ata_drive_datas *);
diff --git a/sys/dev/ata/wd.c b/sys/dev/ata/wd.c
index 23ba6e1ae2b..eedfac0c256 100644
--- a/sys/dev/ata/wd.c
+++ b/sys/dev/ata/wd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: wd.c,v 1.98 2011/04/05 19:57:40 deraadt Exp $ */
+/* $OpenBSD: wd.c,v 1.99 2011/04/15 20:53:28 miod Exp $ */
/* $NetBSD: wd.c,v 1.193 1999/02/28 17:15:27 explorer Exp $ */
/*
@@ -355,13 +355,14 @@ wdactivate(struct device *self, int act)
/*
* Do two resets separated by a small delay. The
* first wakes the controller, the second resets
- * the channel
+ * the channel.
*/
wdc_disable_intr(wd->drvp->chnl_softc);
- wdc_reset_channel(wd->drvp);
+ wdc_reset_channel(wd->drvp, 1);
delay(10000);
- wdc_reset_channel(wd->drvp);
+ wdc_reset_channel(wd->drvp, 0);
wdc_enable_intr(wd->drvp->chnl_softc);
+ wd_get_params(wd, at_poll, &wd->sc_params);
break;
}
return (rv);
@@ -582,7 +583,7 @@ wddone(void *v)
sizeof buf);
retry:
/* Just reset and retry. Can we do more ? */
- wdc_reset_channel(wd->drvp);
+ wdc_reset_channel(wd->drvp, 0);
diskerr(bp, "wd", errbuf, LOG_PRINTF,
wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label);
if (wd->retries++ < WDIORETRIES) {
diff --git a/sys/dev/atapiscsi/atapiscsi.c b/sys/dev/atapiscsi/atapiscsi.c
index f40a8c2c9a1..4e324450c4b 100644
--- a/sys/dev/atapiscsi/atapiscsi.c
+++ b/sys/dev/atapiscsi/atapiscsi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atapiscsi.c,v 1.96 2010/11/18 21:13:19 miod Exp $ */
+/* $OpenBSD: atapiscsi.c,v 1.97 2011/04/15 20:53:28 miod Exp $ */
/*
* This code is derived from code with the copyright below.
@@ -311,9 +311,9 @@ atapiscsi_activate(struct device *self, int act)
* the channel
*/
wdc_disable_intr(chp);
- wdc_reset_channel(drvp);
+ wdc_reset_channel(drvp, 1);
delay(10000);
- wdc_reset_channel(drvp);
+ wdc_reset_channel(drvp, 0);
wdc_enable_intr(chp);
break;
}
@@ -1626,7 +1626,7 @@ wdc_atapi_reset_2(chp, xfer, timeout, ret)
chp->wdc->sc_dev.dv_xname, chp->channel,
xfer->drive);
sc_xfer->error = XS_SELTIMEOUT;
- wdc_reset_channel(drvp);
+ wdc_reset_channel(drvp, 0);
xfer->next = wdc_atapi_done;
return;
diff --git a/sys/dev/ic/wdc.c b/sys/dev/ic/wdc.c
index 19f561ed66e..a43eb881501 100644
--- a/sys/dev/ic/wdc.c
+++ b/sys/dev/ic/wdc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: wdc.c,v 1.111 2011/04/05 19:57:40 deraadt Exp $ */
+/* $OpenBSD: wdc.c,v 1.112 2011/04/15 20:53:28 miod Exp $ */
/* $NetBSD: wdc.c,v 1.68 1999/06/23 19:00:17 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@@ -934,7 +934,7 @@ wdcintr(void *arg)
/* Put all disk in RESET state */
void
-wdc_reset_channel(struct ata_drive_datas *drvp)
+wdc_reset_channel(struct ata_drive_datas *drvp, int nowait)
{
struct channel_softc *chp = drvp->chnl_softc;
int drive;
@@ -942,14 +942,14 @@ wdc_reset_channel(struct ata_drive_datas *drvp)
WDCDEBUG_PRINT(("ata_reset_channel %s:%d for drive %d\n",
chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive),
DEBUG_FUNCS);
- (void) wdcreset(chp, VERBOSE);
+ (void) wdcreset(chp, nowait ? NOWAIT : VERBOSE);
for (drive = 0; drive < 2; drive++) {
chp->ch_drive[drive].state = 0;
}
}
int
-wdcreset(struct channel_softc *chp, int verb)
+wdcreset(struct channel_softc *chp, int flags)
{
int drv_mask1, drv_mask2;
@@ -958,10 +958,14 @@ wdcreset(struct channel_softc *chp, int verb)
chp->wdc->reset(chp);
+ if (flags & NOWAIT)
+ return 0;
+
drv_mask1 = (chp->ch_drive[0].drive_flags & DRIVE) ? 0x01:0x00;
drv_mask1 |= (chp->ch_drive[1].drive_flags & DRIVE) ? 0x02:0x00;
drv_mask2 = __wdcwait_reset(chp, drv_mask1);
- if (verb && drv_mask2 != drv_mask1) {
+
+ if ((flags & VERBOSE) && drv_mask2 != drv_mask1) {
printf("%s channel %d: reset failed for",
chp->wdc->sc_dev.dv_xname, chp->channel);
if ((drv_mask1 & 0x01) != 0 && (drv_mask2 & 0x01) == 0)
@@ -1554,7 +1558,7 @@ wdc_downgrade_mode(struct ata_drive_datas *drvp)
wdc->set_modes(chp);
/* reset the channel, which will schedule all drives for setup */
- wdc_reset_channel(drvp);
+ wdc_reset_channel(drvp, 0);
return 1;
}
diff --git a/sys/dev/ic/wdcvar.h b/sys/dev/ic/wdcvar.h
index d18eb944659..7e67e635ec7 100644
--- a/sys/dev/ic/wdcvar.h
+++ b/sys/dev/ic/wdcvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: wdcvar.h,v 1.47 2011/04/05 19:57:40 deraadt Exp $ */
+/* $OpenBSD: wdcvar.h,v 1.48 2011/04/15 20:53:28 miod Exp $ */
/* $NetBSD: wdcvar.h,v 1.17 1999/04/11 20:50:29 bouyer Exp $ */
/*-
@@ -271,8 +271,9 @@ struct wdc_xfer *wdc_get_xfer(int); /* int = WDC_NOSLEEP/CANSLEEP */
void wdc_free_xfer(struct channel_softc *, struct wdc_xfer *);
void wdcstart(struct channel_softc *);
int wdcreset(struct channel_softc *, int);
-#define VERBOSE 1
-#define SILENT 0 /* wdcreset will not print errors */
+#define NOWAIT 0x02
+#define VERBOSE 0x01
+#define SILENT 0x00 /* wdcreset will not print errors */
int wdc_wait_for_status(struct channel_softc *, int, int, int);
int wdc_dmawait(struct channel_softc *, struct wdc_xfer *, int);
void wdcbit_bucket(struct channel_softc *, int);