summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>2001-07-31 06:14:06 +0000
committerConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>2001-07-31 06:14:06 +0000
commit14a2cd20d08133deb909c4b5f5efc3d5230ec84b (patch)
tree03e3ed814ca11fe1c285b938253a53af889b79b9
parent7b7c3f33cbbf0a158f7555eecbdbc09f48d46008 (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.c64
-rw-r--r--sys/dev/atapiscsi/atapiscsi.c205
-rw-r--r--sys/dev/ic/wdcvar.h3
-rw-r--r--sys/dev/pci/pciide.c49
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",