summaryrefslogtreecommitdiff
path: root/sys/dev/ata
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ata')
-rw-r--r--sys/dev/ata/ata_wdc.c23
-rw-r--r--sys/dev/ata/atavar.h18
-rw-r--r--sys/dev/ata/wd.c9
3 files changed, 40 insertions, 10 deletions
diff --git a/sys/dev/ata/ata_wdc.c b/sys/dev/ata/ata_wdc.c
index 4a6bc577bff..02da34e06e5 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.57 2004/06/22 19:20:56 mycroft Exp $ */
+/* $NetBSD: ata_wdc.c,v 1.58 2004/07/31 21:26:43 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001, 2003 Manuel Bouyer.
@@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.57 2004/06/22 19:20:56 mycroft Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.58 2004/07/31 21:26:43 bouyer Exp $");
#ifndef WDCDEBUG
#define WDCDEBUG
@@ -119,7 +119,8 @@ static void wdc_ata_bio_start(struct wdc_channel *,struct ata_xfer *);
static void _wdc_ata_bio_start(struct wdc_channel *,struct ata_xfer *);
static int wdc_ata_bio_intr(struct wdc_channel *, struct ata_xfer *,
int);
-static void wdc_ata_bio_kill_xfer(struct wdc_channel *,struct ata_xfer *);
+static void wdc_ata_bio_kill_xfer(struct wdc_channel *,
+ struct ata_xfer *, int);
static void wdc_ata_bio_done(struct wdc_channel *, struct ata_xfer *);
static int wdc_ata_err(struct ata_drive_datas *, struct ata_bio *);
#define WDC_ATA_NOERR 0x00 /* Drive doesn't report an error */
@@ -740,7 +741,8 @@ wdc_ata_kill_pending(struct ata_drive_datas *drvp)
}
static void
-wdc_ata_bio_kill_xfer(struct wdc_channel *chp, struct ata_xfer *xfer)
+wdc_ata_bio_kill_xfer(struct wdc_channel *chp, struct ata_xfer *xfer,
+ int reason)
{
struct ata_bio *ata_bio = xfer->c_cmd;
int drive = xfer->c_drive;
@@ -750,7 +752,18 @@ wdc_ata_bio_kill_xfer(struct wdc_channel *chp, struct ata_xfer *xfer)
wdc_free_xfer(chp, xfer);
ata_bio->flags |= ATA_ITSDONE;
- ata_bio->error = ERR_NODEV;
+ switch (reason) {
+ case KILL_GONE:
+ ata_bio->error = ERR_NODEV;
+ break;
+ case KILL_RESET:
+ ata_bio->error = ERR_RESET;
+ break;
+ default:
+ printf("wdc_ata_bio_kill_xfer: unknown reason %d\n",
+ reason);
+ panic("wdc_ata_bio_kill_xfer");
+ }
ata_bio->r_error = WDCE_ABRT;
WDCDEBUG_PRINT(("wdc_ata_done: drv_done\n"), DEBUG_XFERS);
(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
diff --git a/sys/dev/ata/atavar.h b/sys/dev/ata/atavar.h
index ac922ca7865..0844268b652 100644
--- a/sys/dev/ata/atavar.h
+++ b/sys/dev/ata/atavar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: atavar.h,v 1.43 2004/06/01 19:32:30 mycroft Exp $ */
+/* $NetBSD: atavar.h,v 1.44 2004/07/31 21:26:43 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -58,14 +58,19 @@ struct ata_xfer {
/* Low-level protocol handlers. */
void (*c_start)(struct wdc_channel *, struct ata_xfer *);
int (*c_intr)(struct wdc_channel *, struct ata_xfer *, int);
- void (*c_kill_xfer)(struct wdc_channel *, struct ata_xfer *);
+ void (*c_kill_xfer)(struct wdc_channel *, struct ata_xfer *, int);
};
+/* vlags in c_flags */
#define C_ATAPI 0x0001 /* xfer is ATAPI request */
#define C_TIMEOU 0x0002 /* xfer processing timed out */
#define C_POLL 0x0004 /* command is polled */
#define C_DMA 0x0008 /* command uses DMA */
+/* reasons for c_kill_xfer() */
+#define KILL_GONE 1 /* device is gone */
+#define KILL_RESET 2 /* xfer was reset */
+
/* Per-channel queue of ata_xfers. May be shared by multiple channels. */
struct ata_queue {
TAILQ_HEAD(, ata_xfer) queue_xfer;
@@ -192,6 +197,7 @@ struct ata_bio {
#define ERR_DMA 3 /* DMA error */
#define TIMEOUT 4 /* device timed out */
#define ERR_NODEV 5 /* device has been gone */
+#define ERR_RESET 6 /* command was terminated by channel reset */
u_int8_t r_error;/* copy of error register */
daddr_t badsect[127];/* 126 plus trailing -1 marker */
};
@@ -232,7 +238,9 @@ struct wdc_command {
#define AT_ERROR 0x0080 /* command is done with error */
#define AT_TIMEOU 0x0100 /* command timed out */
#define AT_DF 0x0200 /* Drive fault */
-#define AT_READREG 0x0400 /* Read registers on completion */
+#define AT_RESET 0x0400 /* command terminated by channel reset */
+#define AT_GONE 0x0800 /* command terminated because device is gone */
+#define AT_READREG 0x1000 /* Read registers on completion */
int timeout; /* timeout (in ms) */
void *data; /* Data buffer address */
@@ -249,6 +257,10 @@ struct ata_bustype {
int bustype_type; /* symbolic name of type */
int (*ata_bio)(struct ata_drive_datas *, struct ata_bio *);
void (*ata_reset_channel)(struct ata_drive_datas *, int);
+/* extra flags for ata_reset_channel(), in addition to AT_* */
+#define AT_RST_EMERG 0x10000 /* emergency - e.g. for a dump */
+#define AT_RST_NOCMD 0x20000 /* XXX has to go - temporary until we have tagged queuing */
+
int (*ata_exec_command)(struct ata_drive_datas *,
struct wdc_command *);
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;
}