summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>2001-03-15 23:08:17 +0000
committerConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>2001-03-15 23:08:17 +0000
commit4e86011290953ecbcd38757b9a78aa276edb93b0 (patch)
tree239f3046e7245a4530e37e8bc4c6d9a10011efe1 /sys
parent3b275b9c90b2348ddbd2dce437b35af141c0dd0a (diff)
Fix races between timeouts and interrupts.
Cleanup atapiscsi driver a bit by moving fields out of xfer.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/atapiscsi/atapiscsi.c387
-rw-r--r--sys/dev/ic/wdc.c12
-rw-r--r--sys/dev/ic/wdcvar.h17
3 files changed, 214 insertions, 202 deletions
diff --git a/sys/dev/atapiscsi/atapiscsi.c b/sys/dev/atapiscsi/atapiscsi.c
index 539c2bba649..9aa669f3274 100644
--- a/sys/dev/atapiscsi/atapiscsi.c
+++ b/sys/dev/atapiscsi/atapiscsi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atapiscsi.c,v 1.37 2001/03/05 16:04:12 ho Exp $ */
+/* $OpenBSD: atapiscsi.c,v 1.38 2001/03/15 23:08:16 csapuntz Exp $ */
/*
* This code is derived from code with the copyright below.
@@ -109,36 +109,37 @@ void wdc_atapi_start __P((struct channel_softc *,struct wdc_xfer *));
void wdc_atapi_timer_handler __P((void *));
-int wdc_atapi_real_start __P((struct channel_softc *, struct wdc_xfer *,
- int));
-int wdc_atapi_real_start_2 __P((struct channel_softc *, struct wdc_xfer *,
- int));
-int wdc_atapi_intr_command __P((struct channel_softc *, struct wdc_xfer *,
- int));
-
-int wdc_atapi_intr_data __P((struct channel_softc *, struct wdc_xfer *,
- int));
-int wdc_atapi_intr_complete __P((struct channel_softc *, struct wdc_xfer *,
- int));
-
-int wdc_atapi_intr_for_us __P((struct channel_softc *, struct wdc_xfer *,
- int));
-
-int wdc_atapi_send_packet __P((struct channel_softc *, struct wdc_xfer *,
- int));
+void wdc_atapi_real_start __P((struct channel_softc *, struct wdc_xfer *,
+ int, struct atapi_return_args *));
+void wdc_atapi_real_start_2 __P((struct channel_softc *, struct wdc_xfer *,
+ int, struct atapi_return_args *));
+void wdc_atapi_intr_command __P((struct channel_softc *, struct wdc_xfer *,
+ int, struct atapi_return_args *));
+void wdc_atapi_intr_data __P((struct channel_softc *, struct wdc_xfer *,
+ int, struct atapi_return_args *));
+void wdc_atapi_intr_complete __P((struct channel_softc *, struct wdc_xfer *,
+ int, struct atapi_return_args *));
+void wdc_atapi_intr_for_us __P((struct channel_softc *, struct wdc_xfer *,
+ int, struct atapi_return_args *));
+void wdc_atapi_send_packet __P((struct channel_softc *, struct wdc_xfer *,
+ int, struct atapi_return_args *));
int wdc_atapi_dma_flags __P((struct wdc_xfer *));
+void wdc_atapi_ctrl __P((struct channel_softc *, struct wdc_xfer *,
+ int, struct atapi_return_args *));
-int wdc_atapi_ctrl __P((struct channel_softc *, struct wdc_xfer *, int));
char *wdc_atapi_in_data_phase __P((struct wdc_xfer *, int, int));
int wdc_atapi_intr __P((struct channel_softc *, struct wdc_xfer *, int));
-
-int wdc_atapi_done __P((struct channel_softc *, struct wdc_xfer *, int));
-int wdc_atapi_reset __P((struct channel_softc *, struct wdc_xfer *, int));
-int wdc_atapi_reset_2 __P((struct channel_softc *, struct wdc_xfer *, int));
+void wdc_atapi_done __P((struct channel_softc *, struct wdc_xfer *,
+ int, struct atapi_return_args *));
+void wdc_atapi_reset __P((struct channel_softc *, struct wdc_xfer *,
+ int, struct atapi_return_args *));
+void wdc_atapi_reset_2 __P((struct channel_softc *, struct wdc_xfer *,
+ int, struct atapi_return_args *));
int wdc_atapi_send_cmd __P((struct scsi_xfer *sc_xfer));
-int wdc_atapi_tape_done __P((struct channel_softc *, struct wdc_xfer *, int));
+void wdc_atapi_tape_done __P((struct channel_softc *, struct wdc_xfer *,
+ int, struct atapi_return_args *));
#define MAX_SIZE MAXPHYS
struct atapiscsi_softc;
@@ -147,13 +148,8 @@ struct atapiscsi_xfer;
int atapiscsi_match __P((struct device *, void *, void *));
void atapiscsi_attach __P((struct device *, struct device *, void *));
-int wdc_atapi_get_params __P((struct channel_softc *, u_int8_t, struct ataparams *));
-
-int atapi_dsc_wait __P((struct ata_drive_datas *, int));
-int atapi_dsc_ready __P((void *));
-void atapi_dsc_check __P((void *));
-int atapi_dsc_semiready __P((void *));
-int atapi_poll_wait __P((int (*) __P((void *)), void *, int, int, char *));
+int wdc_atapi_get_params __P((struct channel_softc *, u_int8_t,
+ struct ataparams *));
int atapi_to_scsi_sense __P((struct scsi_xfer *, u_int8_t));
struct atapiscsi_softc {
@@ -444,7 +440,7 @@ wdc_atapi_send_cmd(sc_xfer)
xfer->c_start = wdc_atapi_start;
xfer->c_intr = wdc_atapi_intr;
- timeout_set(&xfer->atapi_poll_to, wdc_atapi_timer_handler, xfer);
+ timeout_set(&xfer->atapi_poll_to, wdc_atapi_timer_handler, chp);
s = splbio();
@@ -599,14 +595,19 @@ void
wdc_atapi_timer_handler(arg)
void *arg;
{
- struct wdc_xfer *xfer = arg;
- struct channel_softc *chp = xfer->chp;
+ struct channel_softc *chp = arg;
+ struct wdc_xfer *xfer;
int s;
- xfer->c_flags &= ~C_POLL_MACHINE;
-
- /* There is a race here between us and the interrupt */
s = splbio();
+ xfer = TAILQ_FIRST(&chp->ch_queue->sc_xfer);
+ if (xfer == NULL ||
+ !timeout_triggered(&xfer->atapi_poll_to)) {
+ splx(s);
+ return;
+ }
+ xfer->c_flags &= ~C_POLL_MACHINE;
+ timeout_del(&xfer->atapi_poll_to);
chp->ch_flags &= ~WDCF_IRQ_WAIT;
wdc_atapi_the_machine(chp, xfer, ctxt_timer);
splx(s);
@@ -628,66 +629,63 @@ wdc_atapi_intr(chp, xfer, irq)
return (wdc_atapi_the_machine(chp, xfer, ctxt_interrupt));
}
-#define CONTINUE_POLL 0
-#define GOTO_NEXT 1
-#define DONE 2
+struct atapi_return_args {
+ int timeout;
+ int delay;
+ int expect_irq;
+ int claim_irq;
+};
+
+#define ARGS_INIT {-1, 0, 0, -1}
int
wdc_atapi_the_poll_machine(chp, xfer)
struct channel_softc *chp;
struct wdc_xfer *xfer;
{
- int idx = 0, ret;
+ int idx = 0;
int current_timeout = 10;
- xfer->timeout = -1;
while (1) {
+ struct atapi_return_args retargs = ARGS_INIT;
idx++;
- xfer->timeout = -1;
- xfer->delay = 0;
- xfer->expect_irq = 0;
+ (xfer->next)(chp, xfer, (current_timeout * 1000 <= idx),
+ &retargs);
- ret = (xfer->next)(chp, xfer, (current_timeout * 1000 <= idx));
+ if (xfer->next == NULL) {
+ wdc_free_xfer(chp, xfer);
+ wdcstart(chp);
+ return (0);
+ }
- if (xfer->timeout != -1) {
- current_timeout = xfer->timeout;
+ if (retargs.timeout != -1) {
+ current_timeout = retargs.timeout;
idx = 0;
}
- if (xfer->delay != 0) {
- delay (1000 * xfer->delay);
- idx += 1000 * xfer->delay;
+ if (retargs.delay != 0) {
+ delay (1000 * retargs.delay);
+ idx += 1000 * retargs.delay;
}
- switch (ret) {
- case GOTO_NEXT:
- break;
-
- case CONTINUE_POLL:
- DELAY(1);
- break;
-
- case DONE:
- wdc_free_xfer(chp, xfer);
- wdcstart(chp);
- return (0);
- }
+ DELAY(1);
}
}
+
int
wdc_atapi_the_machine(chp, xfer, ctxt)
struct channel_softc *chp;
struct wdc_xfer *xfer;
enum atapi_context ctxt;
{
- int idx = 0, ret;
+ int idx = 0;
int claim_irq = 0;
extern int ticks;
int timeout_delay = hz / 10;
-
+
if (xfer->c_flags & C_POLL) {
if (ctxt != ctxt_process)
return (0);
@@ -696,57 +694,49 @@ wdc_atapi_the_machine(chp, xfer, ctxt)
return (0);
}
- do_op:
- idx++;
+ /* Don't go through more than 50 state machine steps
+ before yielding. This tries to limit the amount of time
+ spent at high SPL */
+ for (idx = 0; idx < 50; idx++) {
+ struct atapi_return_args retargs = ARGS_INIT;
- xfer->timeout = -1;
- xfer->claim_irq = 0;
- xfer->delay = 0;
-
- ret = (xfer->next)(chp, xfer,
- xfer->endticks && (ticks - xfer->endticks >= 0));
-
- if (xfer->timeout != -1)
- /*
- * Add 1 tick to compensate for the fact that we can be just
- * microseconds before the tick changes.
- */
- xfer->endticks =
- max((xfer->timeout * hz) / 1000, 1) + 1 + ticks;
+ (xfer->next)(chp, xfer,
+ xfer->endticks && (ticks - xfer->endticks >= 0),
+ &retargs);
+
+ if (retargs.timeout != -1)
+ /*
+ * Add 1 tick to compensate for the fact that we
+ * can be just microseconds before the tick changes.
+ */
+ xfer->endticks =
+ max((retargs.timeout * hz) / 1000, 1) + 1 + ticks;
- if (xfer->claim_irq) claim_irq = xfer->claim_irq;
+ if (retargs.claim_irq) claim_irq = retargs.claim_irq;
+
+ if (xfer->next == NULL) {
+ if (xfer->c_flags & C_POLL_MACHINE)
+ timeout_del(&xfer->atapi_poll_to);
+
+ wdc_free_xfer(chp, xfer);
+ wdcstart(chp);
+
+ return (claim_irq);
+ }
- if (xfer->delay) timeout_delay = max(xfer->delay * hz / 1000, 1);
+ if (retargs.delay)
+ timeout_delay = max(retargs.delay * hz / 1000, 1);
- switch (ret) {
- case GOTO_NEXT:
- if (xfer->expect_irq) {
+ if (retargs.expect_irq) {
chp->ch_flags |= WDCF_IRQ_WAIT;
- xfer->expect_irq = 0;
timeout_add(&chp->ch_timo, xfer->endticks - ticks);
return (claim_irq);
}
-
- if (xfer->delay)
+
+ if (retargs.delay != 0)
break;
- goto do_op;
-
- case CONTINUE_POLL:
- if (xfer->delay) break;
- if (idx >= 50) break;
-
DELAY(1);
- goto do_op;
-
- case DONE:
- if (xfer->c_flags & C_POLL_MACHINE)
- timeout_del(&xfer->atapi_poll_to);
-
- wdc_free_xfer(chp, xfer);
- wdcstart(chp);
-
- return (claim_irq);
}
timeout_add(&xfer->atapi_poll_to, timeout_delay);
@@ -773,11 +763,12 @@ wdc_atapi_update_status(chp)
chp->ch_error = CHP_READ_REG(chp, wdr_error);
}
-int
-wdc_atapi_real_start(chp, xfer, timeout)
+void
+wdc_atapi_real_start(chp, xfer, timeout, ret)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int timeout;
+ struct atapi_return_args *ret;
{
#ifdef WDCDEBUG
struct scsi_xfer *sc_xfer = xfer->cmd;
@@ -808,17 +799,18 @@ wdc_atapi_real_start(chp, xfer, timeout)
DELAY(1);
xfer->next = wdc_atapi_real_start_2;
- xfer->timeout = ATAPI_DELAY;
+ ret->timeout = ATAPI_DELAY;
- return (GOTO_NEXT);
+ return;
}
-int
-wdc_atapi_real_start_2(chp, xfer, timeout)
+void
+wdc_atapi_real_start_2(chp, xfer, timeout, ret)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int timeout;
+ struct atapi_return_args *ret;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
@@ -829,12 +821,12 @@ wdc_atapi_real_start_2(chp, xfer, timeout)
sc_xfer->error = XS_TIMEOUT;
xfer->next = wdc_atapi_reset;
- return (GOTO_NEXT);
+ return;
} else {
wdc_atapi_update_status(chp);
if (chp->ch_status & WDCS_BSY)
- return (CONTINUE_POLL);
+ return;
}
/* Do control operations specially. */
@@ -847,19 +839,20 @@ wdc_atapi_real_start_2(chp, xfer, timeout)
}
xfer->next = wdc_atapi_ctrl;
- return (GOTO_NEXT);
+ return;
}
xfer->next = wdc_atapi_send_packet;
- return (GOTO_NEXT);
+ return;
}
-int
-wdc_atapi_send_packet(chp, xfer, timeout)
+void
+wdc_atapi_send_packet(chp, xfer, timeout, ret)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int timeout;
+ struct atapi_return_args *ret;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
@@ -885,13 +878,13 @@ wdc_atapi_send_packet(chp, xfer, timeout)
DELAY(1);
xfer->next = wdc_atapi_intr_for_us;
- xfer->timeout = sc_xfer->timeout;
+ ret->timeout = sc_xfer->timeout;
if ((drvp->atapi_cap & ATAPI_CFG_DRQ_MASK) == ATAPI_CFG_IRQ_DRQ) {
/* We expect an IRQ to tell us of the next state */
- xfer->expect_irq = 1;
+ ret->expect_irq = 1;
}
- return (GOTO_NEXT);
+ return;
}
int
@@ -908,11 +901,12 @@ wdc_atapi_dma_flags(xfer)
return (dma_flags);
}
-int
-wdc_atapi_intr_command(chp, xfer, timeout)
+void
+wdc_atapi_intr_command(chp, xfer, timeout, ret)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int timeout;
+ struct atapi_return_args *ret;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
@@ -946,7 +940,7 @@ wdc_atapi_intr_command(chp, xfer, timeout)
sc_xfer->error = XS_DRIVER_STUFFUP;
xfer->next = wdc_atapi_done;
- return (GOTO_NEXT);
+ return;
}
}
@@ -964,7 +958,7 @@ wdc_atapi_intr_command(chp, xfer, timeout)
else
as->protocol_phase = as_data;
- xfer->expect_irq = 1;
+ ret->expect_irq = 1;
/* If we read/write to a tape we will get into buffer
availability mode. */
@@ -985,7 +979,7 @@ wdc_atapi_intr_command(chp, xfer, timeout)
}
}
- return (GOTO_NEXT);
+ return;
}
@@ -1040,11 +1034,12 @@ wdc_atapi_in_data_phase(xfer, len, ire)
return (message);
}
-int
-wdc_atapi_intr_data(chp, xfer, timeout)
+void
+wdc_atapi_intr_data(chp, xfer, timeout, ret)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int timeout;
+ struct atapi_return_args *ret;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
@@ -1063,8 +1058,8 @@ wdc_atapi_intr_data(chp, xfer, timeout)
Give the drive 100ms to get its house in order
before we try again. */
if (!timeout) {
- xfer->delay = 100;
- return (CONTINUE_POLL);
+ ret->delay = 100;
+ return;
}
}
@@ -1073,7 +1068,7 @@ wdc_atapi_intr_data(chp, xfer, timeout)
sc_xfer->error = XS_RESET;
xfer->next = wdc_atapi_reset;
- return (GOTO_NEXT);
+ return;
}
@@ -1121,19 +1116,19 @@ wdc_atapi_intr_data(chp, xfer, timeout)
xfer->c_bcount = 0;
}
- xfer->expect_irq = 1;
+ ret->expect_irq = 1;
xfer->next = wdc_atapi_intr_for_us;
- return (GOTO_NEXT);
+ return;
}
-int
-wdc_atapi_intr_complete(chp, xfer, timeout)
+void
+wdc_atapi_intr_complete(chp, xfer, timeout, ret)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int timeout;
-
+ struct atapi_return_args *ret;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
@@ -1161,7 +1156,7 @@ wdc_atapi_intr_complete(chp, xfer, timeout)
"calling wdc_atapi_done()"
), DEBUG_INTR);
xfer->next = wdc_atapi_done;
- return (GOTO_NEXT);
+ return;
}
/*
@@ -1171,7 +1166,7 @@ wdc_atapi_intr_complete(chp, xfer, timeout)
sc_xfer->error = XS_RESET;
xfer->next = wdc_atapi_reset;
- return (GOTO_NEXT);
+ return;
} else if (xfer->c_bcount < sizeof(sc_xfer->sense)) {
/* use the sense we just read */
@@ -1199,7 +1194,7 @@ wdc_atapi_intr_complete(chp, xfer, timeout)
xfer->c_done = NULL;
xfer->c_flags |= C_SENSE;
xfer->next = wdc_atapi_real_start;
- return (GOTO_NEXT);
+ return;
}
}
}
@@ -1209,7 +1204,7 @@ wdc_atapi_intr_complete(chp, xfer, timeout)
sc_xfer->error = XS_RESET;
xfer->next = wdc_atapi_reset;
- return (GOTO_NEXT);
+ return;
}
@@ -1229,20 +1224,20 @@ wdc_atapi_intr_complete(chp, xfer, timeout)
DEBUG_INTR);
- if (xfer->c_done)
+ if (xfer->c_done)
xfer->next = xfer->c_done;
else
xfer->next = wdc_atapi_done;
- return (GOTO_NEXT);
+ return;
}
-int
-wdc_atapi_intr_for_us(chp, xfer, timeout)
+void
+wdc_atapi_intr_for_us(chp, xfer, timeout, ret)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int timeout;
-
+ struct atapi_return_args *ret;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
@@ -1263,29 +1258,29 @@ wdc_atapi_intr_for_us(chp, xfer, timeout)
sc_xfer->error = XS_TIMEOUT;
xfer->next = wdc_atapi_reset;
- return (GOTO_NEXT);
+ return;
}
if (chp->ch_status & WDCS_BSY)
- return (CONTINUE_POLL);
+ return;
if (!wdc_atapi_drive_selected(chp, xfer->drive))
{
CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (xfer->drive << 4));
delay (1);
- return (CONTINUE_POLL);
+ return;
}
if (as->protocol_phase != as_cmdout &&
(xfer->c_flags & C_MEDIA_ACCESS) &&
!(chp->ch_status & (WDCS_DSC | WDCS_DRQ))) {
- xfer->delay = 100;
- return (CONTINUE_POLL);
+ ret->delay = 100;
+ return;
}
- xfer->claim_irq = 1;
+ ret->claim_irq = -1;
ireason = CHP_READ_REG(chp, wdr_ireason);
WDCDEBUG_PRINT(("(%x, %x) ", chp->ch_status, ireason), DEBUG_INTR );
@@ -1293,37 +1288,42 @@ wdc_atapi_intr_for_us(chp, xfer, timeout)
switch (as->protocol_phase) {
case as_cmdout:
if (!(chp->ch_status & WDCS_DRQ))
- return (CONTINUE_POLL);
+ return;
- return (wdc_atapi_intr_command(chp, xfer, timeout));
+ wdc_atapi_intr_command(chp, xfer, timeout, ret);
+ return;
case as_data:
if ((chp->ch_status & WDCS_DRQ) ||
- (ireason & 3) != 3)
- return (wdc_atapi_intr_data(chp, xfer, timeout));
+ (ireason & 3) != 3) {
+ wdc_atapi_intr_data(chp, xfer, timeout, ret);
+ return;
+ }
case as_completed:
if ((chp->ch_status & WDCS_DRQ) ||
(ireason & 3) != 3) {
- xfer->delay = 100;
- return (CONTINUE_POLL);
+ ret->delay = 100;
+ return;
}
- return (wdc_atapi_intr_complete(chp, xfer, timeout));
+ wdc_atapi_intr_complete(chp, xfer, timeout, ret);
+ return;
default:
printf ("atapiscsi: Shouldn't get here\n");
sc_xfer->error = XS_DRIVER_STUFFUP;
xfer->next = wdc_atapi_reset;
- return (GOTO_NEXT);
+ return;
}
}
-int
-wdc_atapi_ctrl(chp, xfer, timeout)
+void
+wdc_atapi_ctrl(chp, xfer, timeout, ret)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int timeout;
+ struct atapi_return_args *ret;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
@@ -1360,25 +1360,25 @@ wdc_atapi_ctrl(chp, xfer, timeout)
#endif
sc_xfer->error = XS_DRIVER_STUFFUP;
xfer->next = wdc_atapi_done;
- return (GOTO_NEXT);
+ return;
}
}
wdc_atapi_update_status(chp);
if (chp->ch_status & WDCS_BSY)
- return (CONTINUE_POLL);
+ return;
if (!wdc_atapi_drive_selected(chp, xfer->drive))
{
CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (xfer->drive << 4));
delay (1);
- return (CONTINUE_POLL);
+ return;
}
- xfer->claim_irq = 1;
+ ret->claim_irq = -1;
WDCDEBUG_PRINT(("wdc_atapi_ctrl %s:%d:%d state %d\n",
chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive, drvp->state),
@@ -1392,8 +1392,8 @@ wdc_atapi_ctrl(chp, xfer, timeout)
case IDENTIFY:
wdccommandshort(chp, drvp->drive, ATAPI_IDENTIFY_DEVICE);
drvp->state = IDENTIFY_WAIT;
- xfer->timeout = ATAPI_CTRL_WAIT;
- xfer->expect_irq = 1;
+ ret->timeout = ATAPI_CTRL_WAIT;
+ ret->expect_irq = 1;
break;
case IDENTIFY_WAIT:
@@ -1402,7 +1402,7 @@ wdc_atapi_ctrl(chp, xfer, timeout)
if (!(chp->ch_status & WDCS_ERR)) {
wdcbit_bucket(chp, 512);
- xfer->timeout = 100;
+ ret->timeout = 100;
drvp->state = PIOMODE;
break;
}
@@ -1420,8 +1420,8 @@ piomode:
wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
0x08 | drvp->PIO_mode, WDSF_SET_MODE);
drvp->state = PIOMODE_WAIT;
- xfer->timeout = ATAPI_CTRL_WAIT;
- xfer->expect_irq = 1;
+ ret->timeout = ATAPI_CTRL_WAIT;
+ ret->expect_irq = 1;
break;
case PIOMODE_WAIT:
if (chp->ch_status & WDCS_ERR) {
@@ -1458,8 +1458,8 @@ piomode:
}
drvp->state = DMAMODE_WAIT;
- xfer->timeout = ATAPI_CTRL_WAIT;
- xfer->expect_irq = 1;
+ ret->timeout = ATAPI_CTRL_WAIT;
+ ret->expect_irq = 1;
break;
case DMAMODE_WAIT:
@@ -1473,28 +1473,29 @@ piomode:
xfer->next = wdc_atapi_real_start;
break;
}
- return (GOTO_NEXT);
+ return;
timeout:
printf("%s:%d:%d: %s timed out\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, errstring);
sc_xfer->error = XS_TIMEOUT;
xfer->next = wdc_atapi_reset;
- return (GOTO_NEXT);
+ return;
}
-int
-wdc_atapi_tape_done(chp, xfer, timeout)
+void
+wdc_atapi_tape_done(chp, xfer, timeout, ret)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int timeout;
+ struct atapi_return_args *ret;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
if (sc_xfer->error != XS_NOERROR) {
xfer->next = wdc_atapi_done;
- return (GOTO_NEXT);
+ return;
}
_lto3b(xfer->transfer_len,
@@ -1506,15 +1507,16 @@ wdc_atapi_tape_done(chp, xfer, timeout)
xfer->c_skip = 0;
xfer->next = wdc_atapi_real_start;
- return (GOTO_NEXT);
+ return;
}
-int
-wdc_atapi_done(chp, xfer, timeout)
+void
+wdc_atapi_done(chp, xfer, timeout, ret)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int timeout;
+ struct atapi_return_args *ret;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
@@ -1541,15 +1543,17 @@ wdc_atapi_done(chp, xfer, timeout)
scsi_done(sc_xfer);
}
- return (DONE);
+ xfer->next = NULL;
+ return;
}
-int
-wdc_atapi_reset(chp, xfer, timeout)
+void
+wdc_atapi_reset(chp, xfer, timeout, ret)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int timeout;
+ struct atapi_return_args *ret;
{
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
@@ -1560,16 +1564,17 @@ wdc_atapi_reset(chp, xfer, timeout)
brains after a reset
*/
xfer->next = wdc_atapi_reset_2;
- xfer->delay = 10;
- xfer->timeout = ATAPI_RESET_WAIT;
- return (GOTO_NEXT);
+ ret->delay = 10;
+ ret->timeout = ATAPI_RESET_WAIT;
+ return;
}
-int
-wdc_atapi_reset_2(chp, xfer, timeout)
+void
+wdc_atapi_reset_2(chp, xfer, timeout, ret)
struct channel_softc *chp;
struct wdc_xfer *xfer;
int timeout;
+ struct atapi_return_args *ret;
{
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
struct scsi_xfer *sc_xfer = xfer->cmd;
@@ -1582,16 +1587,16 @@ wdc_atapi_reset_2(chp, xfer, timeout)
wdc_reset_channel(drvp);
xfer->next = wdc_atapi_done;
- return (GOTO_NEXT);
+ return;
}
wdc_atapi_update_status(chp);
if (chp->ch_status & (WDCS_BSY | WDCS_DRQ)) {
- return (CONTINUE_POLL);
+ return;
}
xfer->next = wdc_atapi_done;
- return (GOTO_NEXT);
+ return;
}
diff --git a/sys/dev/ic/wdc.c b/sys/dev/ic/wdc.c
index e8ebd216814..575b40474f0 100644
--- a/sys/dev/ic/wdc.c
+++ b/sys/dev/ic/wdc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: wdc.c,v 1.26 2001/01/29 02:18:33 niklas Exp $ */
+/* $OpenBSD: wdc.c,v 1.27 2001/03/15 23:08:16 csapuntz Exp $ */
/* $NetBSD: wdc.c,v 1.68 1999/06/23 19:00:17 bouyer Exp $ */
@@ -1094,12 +1094,20 @@ wdctimeout(arg)
void *arg;
{
struct channel_softc *chp = (struct channel_softc *)arg;
- struct wdc_xfer *xfer = chp->ch_queue->sc_xfer.tqh_first;
+ struct wdc_xfer *xfer;
int s;
WDCDEBUG_PRINT(("wdctimeout\n"), DEBUG_FUNCS);
s = splbio();
+ xfer = TAILQ_FIRST(&chp->ch_queue->sc_xfer);
+
+ /* Did we lose a race with the interrupt? */
+ if (xfer == NULL ||
+ !timeout_triggered(&chp->ch_timo)) {
+ splx(s);
+ return;
+ }
if ((chp->ch_flags & WDCF_IRQ_WAIT) != 0) {
__wdcerror(chp, "timeout");
printf("\ttype: %s\n", (xfer->c_flags & C_ATAPI) ?
diff --git a/sys/dev/ic/wdcvar.h b/sys/dev/ic/wdcvar.h
index 7d444b59fd2..76f227cdacc 100644
--- a/sys/dev/ic/wdcvar.h
+++ b/sys/dev/ic/wdcvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: wdcvar.h,v 1.14 2001/03/05 16:04:11 ho Exp $ */
+/* $OpenBSD: wdcvar.h,v 1.15 2001/03/15 23:08:16 csapuntz Exp $ */
/* $NetBSD: wdcvar.h,v 1.17 1999/04/11 20:50:29 bouyer Exp $ */
/*-
@@ -186,6 +186,8 @@ struct wdc_softc { /* Per controller state */
* Description of a command to be handled by a controller.
* These commands are queued in a list.
*/
+struct atapi_return_args;
+
struct wdc_xfer {
volatile u_int c_flags;
#define C_INUSE 0x0001 /* xfer struct is in use */
@@ -211,18 +213,15 @@ struct wdc_xfer {
LIST_ENTRY(wdc_xfer) free_list;
void (*c_start) __P((struct channel_softc *, struct wdc_xfer *));
int (*c_intr) __P((struct channel_softc *, struct wdc_xfer *, int));
- int (*c_done) __P((struct channel_softc *, struct wdc_xfer *, int));
void (*c_kill_xfer) __P((struct channel_softc *, struct wdc_xfer *));
/* Used by ATAPISCSI */
- int timeout;
- int endticks;
- int delay;
+ int endticks;
struct timeout atapi_poll_to;
- unsigned int expect_irq:1;
- unsigned int claim_irq:1;
-
- int (*next) __P((struct channel_softc *, struct wdc_xfer *, int));
+ void (*next) __P((struct channel_softc *, struct wdc_xfer *, int,
+ struct atapi_return_args *));
+ void (*c_done) __P((struct channel_softc *, struct wdc_xfer *, int,
+ struct atapi_return_args *));
/* Used for tape devices */
int transfer_len;