From b43b844f6ff4fdb9d63fa2e3793b07825f6b3832 Mon Sep 17 00:00:00 2001 From: bouyer Date: Thu, 1 Apr 1999 21:46:28 +0000 Subject: [PATCH] - change the interrupt routines to take a 3rd arguments, set to 1 if we are called from the interrupt or timeout handler, 0 otherwise. - use this to know if we can busy-wait for wait_for_unbusy or wait_for_ready This fixes a bug where CDs withot the DRQ_INTR capability would not busy-wait for the CMDOUT phase. While I'm there change 2 delay() to DELAY() for consistency, and garbage-collect some old code from wdcintr() which has been ifdef'd out for some time now. --- sys/dev/ata/ata_wdc.c | 27 +++++++++++----------- sys/dev/ic/wdc.c | 46 ++++++++------------------------------ sys/dev/ic/wdcvar.h | 4 ++-- sys/dev/scsipi/atapi_wdc.c | 41 ++++++++++++++++----------------- 4 files changed, 46 insertions(+), 72 deletions(-) diff --git a/sys/dev/ata/ata_wdc.c b/sys/dev/ata/ata_wdc.c index a829d31a9909..14e74ad4eca2 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.18 1999/03/25 16:17:36 bouyer Exp $ */ +/* $NetBSD: ata_wdc.c,v 1.19 1999/04/01 21:46:28 bouyer Exp $ */ /* * Copyright (c) 1998 Manuel Bouyer. @@ -117,9 +117,9 @@ int wdcdebug_wd_mask = 0; #define ATA_DELAY 10000 /* 10s for a drive I/O */ void wdc_ata_bio_start __P((struct channel_softc *,struct wdc_xfer *)); -int wdc_ata_bio_intr __P((struct channel_softc *, struct wdc_xfer *)); +int wdc_ata_bio_intr __P((struct channel_softc *, struct wdc_xfer *, int)); void wdc_ata_bio_done __P((struct channel_softc *, struct wdc_xfer *)); -int wdc_ata_ctrl_intr __P((struct channel_softc *, struct wdc_xfer *)); +int wdc_ata_ctrl_intr __P((struct channel_softc *, struct wdc_xfer *, int)); int wdc_ata_err __P((struct ata_drive_datas *, struct ata_bio *)); #define WDC_ATA_NOERR 0x00 /* Drive doesn't report an error */ #define WDC_ATA_RECOV 0x01 /* There was a recovered error */ @@ -199,8 +199,8 @@ wdc_ata_bio_start(chp, xfer) ATA_DELAY / 1000 * hz); } else { /* Wait for at last 400ns for status bit to be valid */ - delay(1); - wdc_ata_ctrl_intr(chp, xfer); + DELAY(1); + wdc_ata_ctrl_intr(chp, xfer, 0); } return; } @@ -372,7 +372,7 @@ intr: /* Wait for IRQ (either real or polled) */ } else { /* Wait for at last 400ns for status bit to be valid */ delay(1); - wdc_ata_bio_intr(chp, xfer); + wdc_ata_bio_intr(chp, xfer, 0); if ((ata_bio->flags & ATA_ITSDONE) == 0) goto again; } @@ -388,9 +388,10 @@ timeout: } int -wdc_ata_bio_intr(chp, xfer) +wdc_ata_bio_intr(chp, xfer, irq) struct channel_softc *chp; struct wdc_xfer *xfer; + int irq; { struct ata_bio *ata_bio = xfer->cmd; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; @@ -417,9 +418,8 @@ wdc_ata_bio_intr(chp, xfer) /* Ack interrupt done by wait_for_unbusy */ if (wait_for_unbusy(chp, - (ata_bio->flags & ATA_POLL) ? ATA_DELAY : 0) < 0) { - if ((ata_bio->flags & ATA_POLL) == 0 && - (xfer->c_flags & C_TIMEOU) == 0) + (irq == 0) ? ATA_DELAY : 0) < 0) { + if (irq && (xfer->c_flags & C_TIMEOU) == 0) return 0; /* IRQ was not for us */ printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip%d\n", chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, @@ -585,14 +585,15 @@ wdc_ata_bio_done(chp, xfer) * Implement operations needed before read/write. */ int -wdc_ata_ctrl_intr(chp, xfer) +wdc_ata_ctrl_intr(chp, xfer, irq) struct channel_softc *chp; struct wdc_xfer *xfer; + int irq; { struct ata_bio *ata_bio = xfer->cmd; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; char *errstring = NULL; - int delay = (ata_bio->flags & ATA_POLL) ? ATA_DELAY : 0; + int delay = (irq == 0) ? ATA_DELAY : 0; WDCDEBUG_PRINT(("wdc_ata_ctrl_intr: state %d\n", drvp->state), DEBUG_FUNCS); @@ -708,7 +709,7 @@ again: return 1; timeout: - if ((xfer->c_flags & C_TIMEOU) == 0 && delay == 0) { + if (irq && (xfer->c_flags & C_TIMEOU) == 0) { return 0; /* IRQ was not for us */ } printf("%s:%d:%d: %s timed out\n", diff --git a/sys/dev/ic/wdc.c b/sys/dev/ic/wdc.c index 9d28848c41b8..32b25b55ed37 100644 --- a/sys/dev/ic/wdc.c +++ b/sys/dev/ic/wdc.c @@ -1,4 +1,4 @@ -/* $NetBSD: wdc.c,v 1.65 1999/03/31 11:18:31 bouyer Exp $ */ +/* $NetBSD: wdc.c,v 1.66 1999/04/01 21:46:29 bouyer Exp $ */ /* @@ -117,7 +117,7 @@ static void __wdcerror __P((struct channel_softc*, char *)); static int __wdcwait_reset __P((struct channel_softc *, int)); void __wdccommand_done __P((struct channel_softc *, struct wdc_xfer *)); void __wdccommand_start __P((struct channel_softc *, struct wdc_xfer *)); -int __wdccommand_intr __P((struct channel_softc *, struct wdc_xfer *)); +int __wdccommand_intr __P((struct channel_softc *, struct wdc_xfer *, int)); int wdprint __P((void *, const char *)); @@ -518,35 +518,7 @@ wdcintr(arg) struct wdc_xfer *xfer; if ((chp->ch_flags & WDCF_IRQ_WAIT) == 0) { -#if 0 - /* Clear the pending interrupt and abort. */ - u_int8_t s = - bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status); -#ifdef WDCDEBUG - u_int8_t e = - bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error); - u_int8_t i = - bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_seccnt); -#else - bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error); - bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_seccnt); -#endif - - WDCDEBUG_PRINT(("wdcintr: inactive controller, " - "punting st=%02x er=%02x irr=%02x\n", s, e, i), DEBUG_INTR); - - if (s & WDCS_DRQ) { - int len; - len = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_cyl_lo) + 256 * bus_space_read_1(chp->cmd_iot, - chp->cmd_ioh, wd_cyl_hi); - WDCDEBUG_PRINT(("wdcintr: clearing up %d bytes\n", - len), DEBUG_INTR); - wdcbit_bucket (chp, len); - } -#else WDCDEBUG_PRINT(("wdcintr: inactive controller\n"), DEBUG_INTR); -#endif return 0; } @@ -554,7 +526,7 @@ wdcintr(arg) untimeout(wdctimeout, chp); chp->ch_flags &= ~WDCF_IRQ_WAIT; xfer = chp->ch_queue->sc_xfer.tqh_first; - return xfer->c_intr(chp, xfer); + return xfer->c_intr(chp, xfer, 1); } /* Put all disk in RESET state */ @@ -738,7 +710,7 @@ wdctimeout(arg) */ xfer->c_flags |= C_TIMEOU; chp->ch_flags &= ~WDCF_IRQ_WAIT; - xfer->c_intr(chp, xfer); + xfer->c_intr(chp, xfer, 1); } else __wdcerror(chp, "missing untimeout"); splx(s); @@ -1079,13 +1051,14 @@ __wdccommand_start(chp, xfer) * Wait for at last 400ns for status bit to be valid. */ delay(10); - __wdccommand_intr(chp, xfer); + __wdccommand_intr(chp, xfer, 0); } int -__wdccommand_intr(chp, xfer) +__wdccommand_intr(chp, xfer, irq) struct channel_softc *chp; struct wdc_xfer *xfer; + int irq; { struct wdc_command *wdc_c = xfer->cmd; int bcount = wdc_c->bcount; @@ -1094,9 +1067,8 @@ __wdccommand_intr(chp, xfer) WDCDEBUG_PRINT(("__wdccommand_intr %s:%d:%d\n", chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), DEBUG_INTR); if (wdcwait(chp, wdc_c->r_st_pmask, wdc_c->r_st_pmask, - (wdc_c->flags & AT_POLL) ? wdc_c->timeout : 0)) { - if ((xfer->c_flags & C_TIMEOU) == 0 && - (wdc_c->flags & AT_POLL) == 0) + (irq == 0) ? wdc_c->timeout : 0)) { + if (irq && (xfer->c_flags & C_TIMEOU) == 0) return 0; /* IRQ was not for us */ wdc_c->flags |= AT_TIMEOU; __wdccommand_done(chp, xfer); diff --git a/sys/dev/ic/wdcvar.h b/sys/dev/ic/wdcvar.h index bf2f8502d636..f5f0436e03a6 100644 --- a/sys/dev/ic/wdcvar.h +++ b/sys/dev/ic/wdcvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: wdcvar.h,v 1.15 1999/02/08 15:22:29 bouyer Exp $ */ +/* $NetBSD: wdcvar.h,v 1.16 1999/04/01 21:46:30 bouyer Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -145,7 +145,7 @@ struct wdc_xfer { TAILQ_ENTRY(wdc_xfer) c_xferchain; 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 (*c_intr) __P((struct channel_softc *, struct wdc_xfer *, int)); }; /* diff --git a/sys/dev/scsipi/atapi_wdc.c b/sys/dev/scsipi/atapi_wdc.c index 9a3911d1f32e..57efb270eace 100644 --- a/sys/dev/scsipi/atapi_wdc.c +++ b/sys/dev/scsipi/atapi_wdc.c @@ -1,4 +1,4 @@ -/* $NetBSD: atapi_wdc.c,v 1.19 1999/03/25 16:17:37 bouyer Exp $ */ +/* $NetBSD: atapi_wdc.c,v 1.20 1999/04/01 21:46:30 bouyer Exp $ */ /* * Copyright (c) 1998 Manuel Bouyer. @@ -86,8 +86,8 @@ int wdcdebug_atapi_mask = 0; void wdc_atapi_minphys __P((struct buf *bp)); void wdc_atapi_start __P((struct channel_softc *,struct wdc_xfer *)); -int wdc_atapi_intr __P((struct channel_softc *, struct wdc_xfer *)); -int wdc_atapi_ctrl __P((struct channel_softc *, struct wdc_xfer *)); +int wdc_atapi_intr __P((struct channel_softc *, struct wdc_xfer *, int)); +int wdc_atapi_ctrl __P((struct channel_softc *, struct wdc_xfer *, int)); void wdc_atapi_done __P((struct channel_softc *, struct wdc_xfer *)); void wdc_atapi_reset __P((struct channel_softc *, struct wdc_xfer *)); int wdc_atapi_send_cmd __P((struct scsipi_xfer *sc_xfer)); @@ -246,7 +246,7 @@ wdc_atapi_start(chp, xfer) xfer->drive, drvp->state); panic("wdc_atapi_start: bad state"); } - wdc_atapi_ctrl(chp, xfer); + wdc_atapi_ctrl(chp, xfer, 0); return; } bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, @@ -281,26 +281,23 @@ wdc_atapi_start(chp, xfer) if ((sc_xfer->sc_link->scsipi_atapi.cap & 0x0300) != ACAP_DRQ_INTR || sc_xfer->flags & SCSI_POLL) { /* Wait for at last 400ns for status bit to be valid */ - delay(1); - if (wdc_atapi_intr(chp, xfer) == 0) { - sc_xfer->error = XS_TIMEOUT; - wdc_atapi_reset(chp, xfer); - return; - } + DELAY(1); + wdc_atapi_intr(chp, xfer, 0); } if (sc_xfer->flags & SCSI_POLL) { while ((sc_xfer->flags & ITSDONE) == 0) { /* Wait for at last 400ns for status bit to be valid */ - delay(1); - wdc_atapi_intr(chp, xfer); + DELAY(1); + wdc_atapi_intr(chp, xfer, 0); } } } int -wdc_atapi_intr(chp, xfer) +wdc_atapi_intr(chp, xfer, irq) struct channel_softc *chp; struct wdc_xfer *xfer; + int irq; { struct scsipi_xfer *sc_xfer = xfer->cmd; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; @@ -326,9 +323,8 @@ wdc_atapi_intr(chp, xfer) bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, WDSD_IBM | (xfer->drive << 4)); if (wait_for_unbusy(chp, - (sc_xfer->flags & SCSI_POLL) ? sc_xfer->timeout : 0) != 0) { - if ((sc_xfer->flags & SCSI_POLL) == 0 && - (xfer->c_flags & C_TIMEOU) == 0) + (irq == 0) ? sc_xfer->timeout : 0) != 0) { + if (irq && (xfer->c_flags & C_TIMEOU) == 0) return 0; /* IRQ was not for us */ printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d\n", chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, @@ -592,7 +588,11 @@ again: if (xfer->c_flags & C_DMA) { dma_err = (*chp->wdc->dma_finish)(chp->wdc->dma_arg, chp->channel, xfer->drive, dma_flags); - xfer->c_bcount -= sc_xfer->datalen; + if (xfer->c_flags & C_SENSE) + xfer->c_bcount -= + sizeof(sc_xfer->sense.scsi_sense); + else + xfer->c_bcount -= sc_xfer->datalen; } if (xfer->c_flags & C_SENSE) { if ((chp->ch_status & WDCS_ERR) || dma_err < 0) { @@ -680,14 +680,15 @@ again: } int -wdc_atapi_ctrl(chp, xfer) +wdc_atapi_ctrl(chp, xfer, irq) struct channel_softc *chp; struct wdc_xfer *xfer; + int irq; { struct scsipi_xfer *sc_xfer = xfer->cmd; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; char *errstring = NULL; - int delay = (sc_xfer->flags & SCSI_POLL) ? ATAPI_DELAY : 0; + int delay = (irq == 0) ? ATAPI_DELAY : 0; /* Ack interrupt done in wait_for_unbusy */ again: @@ -753,7 +754,7 @@ again: return 1; timeout: - if ((xfer->c_flags & C_TIMEOU) == 0 && delay == 0) { + if (irq && (xfer->c_flags & C_TIMEOU) == 0) { return 0; /* IRQ was not for us */ } printf("%s:%d:%d: %s timed out\n",