diff options
author | Constantine Sapuntzakis <csapuntz@cvs.openbsd.org> | 2001-07-31 06:14:06 +0000 |
---|---|---|
committer | Constantine Sapuntzakis <csapuntz@cvs.openbsd.org> | 2001-07-31 06:14:06 +0000 |
commit | 14a2cd20d08133deb909c4b5f5efc3d5230ec84b (patch) | |
tree | 03e3ed814ca11fe1c285b938253a53af889b79b9 | |
parent | 7b7c3f33cbbf0a158f7555eecbdbc09f48d46008 (diff) |
On DMA timeouts, stop busmaster PCIIDE and reset channel. Avoid reading
device registers as this may cause lock-ups on some chipsets
Clean-up in atapiscsi. Get rid of claim_irq. Instead, atapiscsi always
returns -1 (maybe) from the interrupt handler.
-rw-r--r-- | sys/dev/ata/ata_wdc.c | 64 | ||||
-rw-r--r-- | sys/dev/atapiscsi/atapiscsi.c | 205 | ||||
-rw-r--r-- | sys/dev/ic/wdcvar.h | 3 | ||||
-rw-r--r-- | sys/dev/pci/pciide.c | 49 |
4 files changed, 193 insertions, 128 deletions
diff --git a/sys/dev/ata/ata_wdc.c b/sys/dev/ata/ata_wdc.c index 31a93134f43..532cb9413db 100644 --- a/sys/dev/ata/ata_wdc.c +++ b/sys/dev/ata/ata_wdc.c @@ -141,7 +141,8 @@ wdc_ata_bio(drvp, ata_bio) return WDC_TRY_AGAIN; if (ata_bio->flags & ATA_POLL) xfer->c_flags |= C_POLL; - if ((drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) && + if (!(ata_bio->flags & ATA_POLL) && + (drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) && (ata_bio->flags & ATA_SINGLE) == 0) xfer->c_flags |= C_DMA; xfer->drive = drvp->drive; @@ -394,62 +395,31 @@ wdc_ata_bio_intr(chp, xfer, irq) } /* - * if we missed an interrupt in a PIO transfer, reset and restart. - * Don't try to continue transfer, we may have missed cycles. + * reset on timeout. This will cause extra resets in the case + * of occasional lost interrupts */ - if ((xfer->c_flags & (C_TIMEOU | C_DMA)) == C_TIMEOU) { - ata_bio->error = TIMEOUT; - wdc_ata_bio_done(chp, xfer); - return 1; - } + if (xfer->c_flags & C_TIMEOU) + goto timeout; /* Ack interrupt done by wait_for_unbusy */ if (wait_for_unbusy(chp, (irq == 0) ? ATA_DELAY : 0) < 0) { - if (irq && (xfer->c_flags & C_TIMEOU) == 0) + if (irq) 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, xfer->c_bcount, xfer->c_skip); - /* if we were using DMA, stop channel and deal with error */ - if (xfer->c_flags & C_DMA) { - chp->wdc->dma_status = - (*chp->wdc->dma_finish)(chp->wdc->dma_arg, - chp->channel, - xfer->drive); - ata_dmaerr(drvp); - } - - ata_bio->error = TIMEOUT; - wdc_ata_bio_done(chp, xfer); - return 1; + goto timeout; } drv_err = wdc_ata_err(drvp, ata_bio); - /* If we were using DMA, Turn off the DMA channel and check for error */ if (xfer->c_flags & C_DMA) { - if (ata_bio->flags & ATA_POLL) { - /* - * IDE drives deassert WDCS_BSY before transfer is - * complete when using DMA. Polling for DRQ to deassert - * is not enouth DRQ is not required to be - * asserted for DMA transfers, so poll for DRDY. - */ - if (wdcwait(chp, WDCS_DRDY | WDCS_DRQ, WDCS_DRDY, - ATA_DELAY) < 0) { - printf("%s:%d:%d: polled transfer timed out " - "(st=0x%x)\n", chp->wdc->sc_dev.dv_xname, - chp->channel, xfer->drive, chp->ch_status); - ata_bio->error = TIMEOUT; - drv_err = WDC_ATA_ERR; - } - } - chp->wdc->dma_status = - (*chp->wdc->dma_finish)(chp->wdc->dma_arg, chp->channel, - xfer->drive); + (*chp->wdc->dma_finish)(chp->wdc->dma_arg, + chp->channel, xfer->drive); + if (chp->wdc->dma_status != 0) { if (drv_err != WDC_ATA_ERR) { ata_bio->error = ERR_DMA; @@ -511,6 +481,18 @@ end: wdc_ata_bio_done(chp, xfer); } return 1; + +timeout: + if (xfer->c_flags & C_DMA) { + chp->wdc->dma_status = + (*chp->wdc->dma_finish)(chp->wdc->dma_arg, + chp->channel, xfer->drive); + ata_dmaerr(drvp); + } + + ata_bio->error = TIMEOUT; + wdc_ata_bio_done(chp, xfer); + return 1; } void diff --git a/sys/dev/atapiscsi/atapiscsi.c b/sys/dev/atapiscsi/atapiscsi.c index 27581c27e23..2a1a8c586a8 100644 --- a/sys/dev/atapiscsi/atapiscsi.c +++ b/sys/dev/atapiscsi/atapiscsi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: atapiscsi.c,v 1.49 2001/07/21 09:08:49 csapuntz Exp $ */ +/* $OpenBSD: atapiscsi.c,v 1.50 2001/07/31 06:14:05 csapuntz Exp $ */ /* * This code is derived from code with the copyright below. @@ -92,10 +92,10 @@ enum atapi_drive_states { #define DEBUG_ERRORS 0x80 /* Debug error handling code */ #if defined(WDCDEBUG) -int wdcdebug_atapi_mask = 0x0; +int wdcdebug_atapi_mask = 0; #define WDCDEBUG_PRINT(args, level) \ if (wdcdebug_atapi_mask & (level)) \ - printf args + lprintf args #else #define WDCDEBUG_PRINT(args, level) #endif @@ -123,7 +123,7 @@ 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 *, +void wdc_atapi_pio_intr __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 *)); @@ -155,7 +155,7 @@ struct atapiscsi_softc { struct device sc_dev; struct scsi_link sc_adapterlink; struct channel_softc *chp; - enum atapi_state { as_none, as_cmdout, as_data, as_completed }; + enum atapi_state { as_none, as_data, as_completed }; enum atapi_state protocol_phase; int drive; @@ -315,8 +315,9 @@ wdc_atapi_send_cmd(sc_xfer) struct ata_drive_datas *drvp = &chp->ch_drive[as->drive]; struct wdc_xfer *xfer; int s, ret; + int idx; - WDCDEBUG_PRINT(("wdc_atapi_send_cmd %s:%d:%d\n", + WDCDEBUG_PRINT(("wdc_atapi_send_cmd %s:%d:%d start\n", chp->wdc->sc_dev.dv_xname, chp->channel, as->drive), DEBUG_XFERS); if (sc_xfer->sc_link->target != 0) { @@ -341,6 +342,17 @@ wdc_atapi_send_cmd(sc_xfer) timeout_set(&xfer->atapi_poll_to, wdc_atapi_timer_handler, chp); + WDCDEBUG_PRINT(("wdc_atapi_send_cmd %s:%d:%d ", + chp->wdc->sc_dev.dv_xname, chp->channel, as->drive), + DEBUG_XFERS | DEBUG_ERRORS); + + for (idx = 0; idx < sc_xfer->cmdlen; idx++) { + WDCDEBUG_PRINT((" %02x", + ((unsigned char *)sc_xfer->cmd)[idx]), + DEBUG_XFERS | DEBUG_ERRORS); + } + WDCDEBUG_PRINT(("\n"), DEBUG_XFERS | DEBUG_ERRORS); + s = splbio(); if (drvp->atapi_cap & ACAP_DSC) { @@ -499,10 +511,10 @@ enum atapi_context { ctxt_interrupt = 2 }; -int wdc_atapi_the_machine __P((struct channel_softc *, struct wdc_xfer *, +void wdc_atapi_the_machine __P((struct channel_softc *, struct wdc_xfer *, enum atapi_context)); -int wdc_atapi_the_poll_machine __P((struct channel_softc *, struct wdc_xfer *)); +void wdc_atapi_the_poll_machine __P((struct channel_softc *, struct wdc_xfer *)); void wdc_atapi_start(chp, xfer) @@ -549,22 +561,24 @@ wdc_atapi_intr(chp, xfer, irq) /* XXX we should consider an alternate signaling regime here */ if (xfer->c_flags & C_TIMEOU) { xfer->c_flags &= ~C_TIMEOU; - return (wdc_atapi_the_machine(chp, xfer, ctxt_timer)); + wdc_atapi_the_machine(chp, xfer, ctxt_timer); + return (0); } - return (wdc_atapi_the_machine(chp, xfer, ctxt_interrupt)); + wdc_atapi_the_machine(chp, xfer, ctxt_interrupt); + + return (-1); } struct atapi_return_args { int timeout; int delay; int expect_irq; - int claim_irq; }; -#define ARGS_INIT {-1, 0, 0, -1} +#define ARGS_INIT {-1, 0, 0} -int +void wdc_atapi_the_poll_machine(chp, xfer) struct channel_softc *chp; struct wdc_xfer *xfer; @@ -583,7 +597,7 @@ wdc_atapi_the_poll_machine(chp, xfer) if (xfer->next == NULL) { wdc_free_xfer(chp, xfer); wdcstart(chp); - return (0); + return; } if (retargs.timeout != -1) { @@ -601,14 +615,13 @@ wdc_atapi_the_poll_machine(chp, xfer) } -int +void wdc_atapi_the_machine(chp, xfer, ctxt) struct channel_softc *chp; struct wdc_xfer *xfer; enum atapi_context ctxt; { int idx = 0; - int claim_irq = 0; extern int ticks; int timeout_delay = hz / 10; @@ -617,11 +630,11 @@ wdc_atapi_the_machine(chp, xfer, ctxt) if (ctxt == ctxt_interrupt) xfer->endticks = 1; - return (0); + return; } wdc_atapi_the_poll_machine(chp, xfer); - return (0); + return; } /* Don't go through more than 50 state machine steps @@ -642,12 +655,6 @@ wdc_atapi_the_machine(chp, xfer, ctxt) xfer->endticks = max((retargs.timeout * hz) / 1000, 1) + 1 + ticks; - if (retargs.claim_irq) { - claim_irq = retargs.claim_irq; - if (chp->wdc->cap & WDC_CAPABILITY_IRQACK) - chp->wdc->irqack(chp); - } - if (xfer->next == NULL) { if (xfer->c_flags & C_POLL_MACHINE) timeout_del(&xfer->atapi_poll_to); @@ -655,13 +662,13 @@ wdc_atapi_the_machine(chp, xfer, ctxt) wdc_free_xfer(chp, xfer); wdcstart(chp); - return (claim_irq); + return; } if (retargs.expect_irq) { chp->ch_flags |= WDCF_IRQ_WAIT; timeout_add(&chp->ch_timo, xfer->endticks - ticks); - return (claim_irq); + return; } if (retargs.delay != 0) { @@ -675,7 +682,7 @@ wdc_atapi_the_machine(chp, xfer, ctxt) timeout_add(&xfer->atapi_poll_to, timeout_delay); xfer->c_flags |= C_POLL_MACHINE; - return (claim_irq); + return; } @@ -709,10 +716,6 @@ wdc_atapi_real_start(chp, xfer, timeout, ret) #endif struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; - WDCDEBUG_PRINT(("wdc_atapi_start %s:%d:%d, scsi flags 0x%x\n", - chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive, - sc_xfer->flags), DEBUG_XFERS); - /* * Only set the DMA flag if the transfer is reasonably large. * At least one older drive failed to complete a 4 byte DMA transfer. @@ -720,7 +723,7 @@ wdc_atapi_real_start(chp, xfer, timeout, ret) /* Turn off DMA flag on REQUEST SENSE */ - if (!(xfer->c_flags & (C_POLL | C_SENSE)) && + if (!(xfer->c_flags & (C_POLL | C_SENSE | C_MEDIA_ACCESS)) && (drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) && (xfer->c_bcount > 100)) xfer->c_flags |= C_DMA; @@ -735,6 +738,11 @@ wdc_atapi_real_start(chp, xfer, timeout, ret) xfer->next = wdc_atapi_real_start_2; ret->timeout = ATAPI_DELAY; + WDCDEBUG_PRINT(("wdc_atapi_start %s:%d:%d, scsi flags 0x%x, ATA flags 0x%x\n", + chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive, + sc_xfer->flags, xfer->c_flags), DEBUG_XFERS); + + return; } @@ -785,6 +793,8 @@ wdc_atapi_send_packet(chp, xfer, timeout, ret) struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc; + wdc_enable_intr(chp); + /* * Even with WDCS_ERR, the device should accept a command packet * Limit length to what can be stuffed into the cylinder register @@ -799,18 +809,21 @@ wdc_atapi_send_packet(chp, xfer, timeout, ret) 0, 0, 0, (xfer->c_flags & C_DMA) ? ATAPI_PKT_CMD_FTRE_DMA : 0); - as->protocol_phase = as_cmdout; as->retries = 0; DELAY(1); - xfer->next = wdc_atapi_intr_for_us; + xfer->next = wdc_atapi_intr_command; 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 */ ret->expect_irq = 1; } + + WDCDEBUG_PRINT(("wdc_atapi_send_packet %s:%d:%d command sent\n", + chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive + ), DEBUG_XFERS); return; } @@ -830,6 +843,18 @@ wdc_atapi_intr_command(chp, xfer, timeout, ret) int cmdlen = (drvp->atapi_cap & ACAP_LEN) ? 16 : 12; int dma_flags = ((sc_xfer->flags & SCSI_DATA_IN) || (xfer->c_flags & C_SENSE)) ? WDC_DMA_READ : 0; + + wdc_atapi_update_status(chp); + + if ((chp->ch_status & WDCS_BSY) || !(chp->ch_status & WDCS_DRQ)) { + if (timeout) + goto timeout; + + return; + } + + if (chp->wdc->cap & WDC_CAPABILITY_IRQACK) + chp->wdc->irqack(chp); bzero(cmd, sizeof(cmd)); @@ -851,7 +876,7 @@ wdc_atapi_intr_command(chp, xfer, timeout, ret) xfer->c_bcount, dma_flags) != 0) { sc_xfer->error = XS_DRIVER_STUFFUP; - xfer->next = wdc_atapi_done; + xfer->next = wdc_atapi_reset; return; } } @@ -862,12 +887,15 @@ wdc_atapi_intr_command(chp, xfer, timeout, ret) if (xfer->c_flags & C_DMA) { (*chp->wdc->dma_start)(chp->wdc->dma_arg, chp->channel, xfer->drive); - } + xfer->next = wdc_atapi_intr_complete; + } else { + if (xfer->c_bcount == 0) + as->protocol_phase = as_completed; + else + as->protocol_phase = as_data; - if (xfer->c_bcount == 0 || (xfer->c_flags & C_DMA)) - as->protocol_phase = as_completed; - else - as->protocol_phase = as_data; + xfer->next = wdc_atapi_pio_intr; + } ret->expect_irq = 1; @@ -891,6 +919,14 @@ wdc_atapi_intr_command(chp, xfer, timeout, ret) } return; + + timeout: + printf ("%s:%d:%d: device timeout waiting to send SCSI packet\n", + chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive); + + sc_xfer->error = XS_TIMEOUT; + xfer->next = wdc_atapi_reset; + return; } @@ -968,6 +1004,9 @@ wdc_atapi_intr_data(chp, xfer, timeout, ret) Give the drive 100ms to get its house in order before we try again. */ + WDCDEBUG_PRINT(("wdc_atapi_intr: %s\n", message), + DEBUG_ERRORS); + if (!timeout) { ret->delay = 100; return; @@ -1020,12 +1059,11 @@ wdc_atapi_intr_data(chp, xfer, timeout, ret) } ret->expect_irq = 1; - xfer->next = wdc_atapi_intr_for_us; + xfer->next = wdc_atapi_pio_intr; return; } - void wdc_atapi_intr_complete(chp, xfer, timeout, ret) struct channel_softc *chp; @@ -1040,14 +1078,41 @@ wdc_atapi_intr_complete(chp, xfer, timeout, ret) WDCDEBUG_PRINT(("PHASE_COMPLETED\n"), DEBUG_INTR); if (xfer->c_flags & C_DMA) { + int retry; + + if (timeout) { + chp->wdc->dma_status = + (*chp->wdc->dma_finish) + (chp->wdc->dma_arg, chp->channel, + xfer->drive); + + sc_xfer->error = XS_TIMEOUT; + drvp->n_dmaerrs++; + + xfer->next = wdc_atapi_reset; + return; + } + + for (retry = 5; retry > 0; retry--) { + wdc_atapi_update_status(chp); + if ((chp->ch_status & (WDCS_BSY | WDCS_DRQ)) == 0) + break; + DELAY(5); + } + if (retry == 0) { + ret->expect_irq = 1; + return; + } + chp->wdc->dma_status = - (*chp->wdc->dma_finish)(chp->wdc->dma_arg, chp->channel, + (*chp->wdc->dma_finish) + (chp->wdc->dma_arg, chp->channel, xfer->drive); if (chp->wdc->dma_status & WDC_DMAST_UNDER) xfer->c_bcount = 1; else - xfer->c_bcount = 0; + xfer->c_bcount = 0; } as->protocol_phase = as_none; @@ -1068,7 +1133,7 @@ wdc_atapi_intr_complete(chp, xfer, timeout, ret) */ sc_xfer->error = XS_SHORTSENSE; } else if (xfer->c_bcount < sizeof(sc_xfer->sense)) { - /* use the sense we just read */ + /* use the sense we just read */ sc_xfer->error = XS_SENSE; } else { /* @@ -1133,19 +1198,16 @@ wdc_atapi_intr_complete(chp, xfer, timeout, ret) } void -wdc_atapi_intr_for_us(chp, xfer, timeout, ret) +wdc_atapi_pio_intr(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]; struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc; u_int8_t ireason; -#if 0 - WDCDEBUG_PRINT(("ATAPI_INTR\n"), DEBUG_INTR); -#endif + wdc_atapi_update_status(chp); if (chp->ch_status & WDCS_BSY) { @@ -1157,6 +1219,7 @@ wdc_atapi_intr_for_us(chp, xfer, timeout, ret) if (!wdc_atapi_drive_selected(chp, xfer->drive)) { + WDCDEBUG_PRINT(("wdc_atapi_intr_for_us: wrong drive selected\n"), DEBUG_INTR); CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (xfer->drive << 4)); delay (1); @@ -1164,8 +1227,7 @@ wdc_atapi_intr_for_us(chp, xfer, timeout, ret) return; } - if (as->protocol_phase != as_cmdout && - (xfer->c_flags & C_MEDIA_ACCESS) && + if ((xfer->c_flags & C_MEDIA_ACCESS) && !(chp->ch_status & (WDCS_DSC | WDCS_DRQ))) { if (timeout) goto timeout; @@ -1174,23 +1236,13 @@ wdc_atapi_intr_for_us(chp, xfer, timeout, ret) return; } - ret->claim_irq = -1; + if (chp->wdc->cap & WDC_CAPABILITY_IRQACK) + chp->wdc->irqack(chp); ireason = CHP_READ_REG(chp, wdr_ireason); - WDCDEBUG_PRINT(("(%x, %x) ", chp->ch_status, ireason), DEBUG_INTR ); + WDCDEBUG_PRINT(("Phase %d, (%x, %x) ", as->protocol_phase, chp->ch_status, ireason), DEBUG_INTR ); switch (as->protocol_phase) { - case as_cmdout: - if (timeout) - goto timeout; - - if (!(chp->ch_status & WDCS_DRQ)) { - return; - } - - wdc_atapi_intr_command(chp, xfer, timeout, ret); - return; - case as_data: if ((chp->ch_status & WDCS_DRQ) || (ireason & 3) != 3) { @@ -1223,23 +1275,12 @@ wdc_atapi_intr_for_us(chp, xfer, timeout, ret) return; timeout: - printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d\n", - chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, - xfer->c_bcount, xfer->c_skip); - - if (xfer->c_flags & C_DMA) { - ireason = CHP_READ_REG(chp, wdr_ireason); + ireason = CHP_READ_REG(chp, wdr_ireason); - chp->wdc->dma_status = - (*chp->wdc->dma_finish)(chp->wdc->dma_arg, - chp->channel, xfer->drive); - - WDCDEBUG_PRINT(("Drive status: %02x %02x %02x\n", - chp->ch_status, chp->ch_error, ireason), - DEBUG_ERRORS); - - drvp->n_dmaerrs++; - } + printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d, " + "status=%02x, ireason=%02x\n", + chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, + xfer->c_bcount, xfer->c_skip, chp->ch_status, ireason); sc_xfer->error = XS_TIMEOUT; xfer->next = wdc_atapi_reset; @@ -1325,8 +1366,6 @@ wdc_atapi_ctrl(chp, xfer, timeout, ret) chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive, drvp->state), DEBUG_INTR | DEBUG_FUNCS); - ret->claim_irq = -1; - switch (drvp->state) { /* My ATAPI slave device likes to assert DASP-/PDIAG- until it is DEVICE RESET. This causes the LED to stay on. diff --git a/sys/dev/ic/wdcvar.h b/sys/dev/ic/wdcvar.h index 25cc4140ff4..fcaa870b74b 100644 --- a/sys/dev/ic/wdcvar.h +++ b/sys/dev/ic/wdcvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: wdcvar.h,v 1.19 2001/06/25 19:31:50 csapuntz Exp $ */ +/* $OpenBSD: wdcvar.h,v 1.20 2001/07/31 06:14:05 csapuntz Exp $ */ /* $NetBSD: wdcvar.h,v 1.17 1999/04/11 20:50:29 bouyer Exp $ */ /*- @@ -68,7 +68,6 @@ struct channel_softc { /* Per channel data */ #define WDCF_ACTIVE 0x01 /* channel is active */ #define WDCF_ONESLAVE 0x02 /* slave-only channel */ #define WDCF_IRQ_WAIT 0x10 /* controller is waiting for irq */ -#define WDCF_DMA_WAIT 0x20 /* controller is waiting for DMA */ #define WDCF_VERBOSE_PROBE 0x40 /* verbose probe */ u_int8_t ch_status; /* copy of status register */ u_int8_t ch_error; /* copy of error register */ diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c index a0c3c5fea89..7ee28e1141f 100644 --- a/sys/dev/pci/pciide.c +++ b/sys/dev/pci/pciide.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pciide.c,v 1.58 2001/07/20 05:56:25 csapuntz Exp $ */ +/* $OpenBSD: pciide.c,v 1.59 2001/07/31 06:14:05 csapuntz Exp $ */ /* $NetBSD: pciide.c,v 1.110 2001/03/20 17:56:46 bouyer Exp $ */ /* @@ -176,6 +176,7 @@ struct pciide_softc { char *name; int hw_ok; /* hardware mapped & OK? */ int compat; /* is it compat? */ + int dma_in_progress; void *ih; /* compat or pci handle */ bus_space_handle_t ctl_baseioh; /* ctrl regs blk, native mode */ /* DMA tables and DMA map for xfer, for each drive */ @@ -479,6 +480,8 @@ void pciide_unmap_compat_intr __P(( struct pci_attach_args *, struct pciide_channel *, int, int)); int pciide_compat_intr __P((void *)); int pciide_pci_intr __P((void *)); +int pciide_intr_flag(struct pciide_channel *); + const struct pciide_product_desc* pciide_lookup_product __P((u_int32_t)); const struct pciide_product_desc * @@ -787,11 +790,45 @@ pciide_mapreg_dma(sc, pa) } int +pciide_intr_flag(struct pciide_channel *cp) +{ + struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + + if (cp->dma_in_progress) { + int retry = 10; + int status; + + /* Check the status register */ + for (retry = 10; retry > 0; retry--) { + status = bus_space_read_1(sc->sc_dma_iot, + sc->sc_dma_ioh, + IDEDMA_CTL + IDEDMA_SCH_OFFSET * + cp->wdc_channel.channel); + if (status & IDEDMA_CTL_INTR) { + break; + } + DELAY(5); + } + + /* Not for us. */ + if (retry == 0) + return (0); + + return (1); + } + + return (-1); +} + +int pciide_compat_intr(arg) void *arg; { struct pciide_channel *cp = arg; + if (pciide_intr_flag(cp) == 0) + return 0; + #ifdef DIAGNOSTIC /* should only be called for a compat channel */ if (cp->compat == 0) @@ -821,6 +858,9 @@ pciide_pci_intr(arg) if ((wdc_cp->ch_flags & WDCF_IRQ_WAIT) == 0) continue; + if (pciide_intr_flag(cp) == 0) + continue; + crv = wdcintr(wdc_cp); if (crv == 0) ; /* leave rv alone */ @@ -1046,6 +1086,8 @@ pciide_dma_start(v, channel, drive) IDEDMA_CMD + IDEDMA_SCH_OFFSET * channel, bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CMD + IDEDMA_SCH_OFFSET * channel) | IDEDMA_CMD_START); + + sc->pciide_channels[channel].dma_in_progress = 1; } int @@ -1059,6 +1101,8 @@ pciide_dma_finish(v, channel, drive) struct pciide_dma_maps *dma_maps = &sc->pciide_channels[channel].dma_maps[drive]; + sc->pciide_channels[channel].dma_in_progress = 0; + status = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CTL + IDEDMA_SCH_OFFSET * channel); WDCDEBUG_PRINT(("pciide_dma_finish: status 0x%x\n", status), @@ -3304,7 +3348,7 @@ hpt_pci_intr(arg) if ((dmastat & IDEDMA_CTL_INTR) == 0) continue; cp = &sc->pciide_channels[i]; - wdc_cp = &cp->wdc_channel; + wdc_cp = &cp->wdc_channel; crv = wdcintr(wdc_cp); if (crv == 0) { printf("%s:%d: bogus intr\n", @@ -3640,6 +3684,7 @@ pdc20265_pci_intr(arg) sc->sc_dma_ioh, IDEDMA_CTL + IDEDMA_SCH_OFFSET * i); if((dmastat & IDEDMA_CTL_INTR) == 0) continue; + crv = wdcintr(wdc_cp); if (crv == 0) printf("%s:%d: bogus intr\n", |