diff options
author | Constantine Sapuntzakis <csapuntz@cvs.openbsd.org> | 2001-03-15 23:08:17 +0000 |
---|---|---|
committer | Constantine Sapuntzakis <csapuntz@cvs.openbsd.org> | 2001-03-15 23:08:17 +0000 |
commit | 4e86011290953ecbcd38757b9a78aa276edb93b0 (patch) | |
tree | 239f3046e7245a4530e37e8bc4c6d9a10011efe1 /sys | |
parent | 3b275b9c90b2348ddbd2dce437b35af141c0dd0a (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.c | 387 | ||||
-rw-r--r-- | sys/dev/ic/wdc.c | 12 | ||||
-rw-r--r-- | sys/dev/ic/wdcvar.h | 17 |
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; |