Module Name: src
Committed By: jdolecek
Date: Tue Oct 17 18:52:51 UTC 2017
Modified Files:
src/sys/dev/ata: ata_subr.c ata_wdc.c atavar.h
src/sys/dev/ic: wdc.c
src/sys/dev/pci: pciide_common.c
src/sys/dev/scsipi: atapi_wdc.c
Log Message:
reintroduce ATACH_IRQ_WAIT flag for attachments using wdcintr(), only
process the interrupt when the flag is set - this fixes spurious interrupt
during post-reset drive setup in wdc_ata_bio_start(), and wdc_atapi_start()
while those functions set WDCTL_IDS, this seems to be ignored by certain
(maybe all) PCI-IDE controllers; usually the implicit KERNEL_LOCK() would
prevent the interrupt anyway, but not when the start routine is started
from the atabus thread, which doesn't take it
fixes 'panic: wdc_ata_bio_intr: bad state' reported on current-users
by Chavdar Ivanov
To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/dev/ata/ata_subr.c
cvs rdiff -u -r1.108 -r1.109 src/sys/dev/ata/ata_wdc.c
cvs rdiff -u -r1.94 -r1.95 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.286 -r1.287 src/sys/dev/ic/wdc.c
cvs rdiff -u -r1.63 -r1.64 src/sys/dev/pci/pciide_common.c
cvs rdiff -u -r1.128 -r1.129 src/sys/dev/scsipi/atapi_wdc.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/ata/ata_subr.c
diff -u src/sys/dev/ata/ata_subr.c:1.1 src/sys/dev/ata/ata_subr.c:1.2
--- src/sys/dev/ata/ata_subr.c:1.1 Tue Oct 10 17:19:38 2017
+++ src/sys/dev/ata/ata_subr.c Tue Oct 17 18:52:50 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ata_subr.c,v 1.1 2017/10/10 17:19:38 jdolecek Exp $ */
+/* $NetBSD: ata_subr.c,v 1.2 2017/10/17 18:52:50 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@@ -25,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.1 2017/10/10 17:19:38 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.2 2017/10/17 18:52:50 jdolecek Exp $");
#include "opt_ata.h"
@@ -334,7 +334,7 @@ ata_free_xfer(struct ata_channel *chp, s
/* finish the busmastering PIO */
(*wdc->piobm_done)(wdc->dma_arg,
chp->ch_channel, xfer->c_drive);
- chp->ch_flags &= ~(ATACH_DMA_WAIT | ATACH_PIOBM_WAIT);
+ chp->ch_flags &= ~(ATACH_DMA_WAIT | ATACH_PIOBM_WAIT | ATACH_IRQ_WAIT);
}
#endif
Index: src/sys/dev/ata/ata_wdc.c
diff -u src/sys/dev/ata/ata_wdc.c:1.108 src/sys/dev/ata/ata_wdc.c:1.109
--- src/sys/dev/ata/ata_wdc.c:1.108 Sun Oct 15 11:27:14 2017
+++ src/sys/dev/ata/ata_wdc.c Tue Oct 17 18:52:50 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ata_wdc.c,v 1.108 2017/10/15 11:27:14 jdolecek Exp $ */
+/* $NetBSD: ata_wdc.c,v 1.109 2017/10/17 18:52:50 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001, 2003 Manuel Bouyer.
@@ -54,7 +54,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.108 2017/10/15 11:27:14 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.109 2017/10/17 18:52:50 jdolecek Exp $");
#include "opt_ata.h"
#include "opt_wdc.h"
@@ -592,7 +592,12 @@ _wdc_ata_bio_start(struct ata_channel *c
intr:
#endif
/* Wait for IRQ (either real or polled) */
- return (ata_bio->flags & ATA_POLL) ? ATASTART_POLL : ATASTART_STARTED;
+ if ((ata_bio->flags & ATA_POLL) == 0) {
+ chp->ch_flags |= ATACH_IRQ_WAIT;
+ return ATASTART_STARTED;
+ } else {
+ return ATASTART_POLL;
+ }
timeout:
printf("%s:%d:%d: not ready, st=0x%02x, err=0x%02x\n",
Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.94 src/sys/dev/ata/atavar.h:1.95
--- src/sys/dev/ata/atavar.h:1.94 Tue Oct 10 17:19:38 2017
+++ src/sys/dev/ata/atavar.h Tue Oct 17 18:52:50 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: atavar.h,v 1.94 2017/10/10 17:19:38 jdolecek Exp $ */
+/* $NetBSD: atavar.h,v 1.95 2017/10/17 18:52:50 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -399,6 +399,7 @@ struct ata_channel {
/* Our state */
volatile int ch_flags;
#define ATACH_SHUTDOWN 0x02 /* channel is shutting down */
+#define ATACH_IRQ_WAIT 0x10 /* controller is waiting for irq */
#define ATACH_DMA_WAIT 0x20 /* controller is waiting for DMA */
#define ATACH_PIOBM_WAIT 0x40 /* controller is waiting for busmastering PIO */
#define ATACH_DISABLED 0x80 /* channel is disabled */
Index: src/sys/dev/ic/wdc.c
diff -u src/sys/dev/ic/wdc.c:1.286 src/sys/dev/ic/wdc.c:1.287
--- src/sys/dev/ic/wdc.c:1.286 Mon Oct 16 05:52:43 2017
+++ src/sys/dev/ic/wdc.c Tue Oct 17 18:52:50 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: wdc.c,v 1.286 2017/10/16 05:52:43 jdolecek Exp $ */
+/* $NetBSD: wdc.c,v 1.287 2017/10/17 18:52:50 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001, 2003 Manuel Bouyer. All rights reserved.
@@ -58,7 +58,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.286 2017/10/16 05:52:43 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.287 2017/10/17 18:52:50 jdolecek Exp $");
#include "opt_ata.h"
#include "opt_wdc.h"
@@ -879,6 +879,11 @@ wdcintr(void *arg)
return (0);
}
+ if ((chp->ch_flags & ATACH_IRQ_WAIT) == 0) {
+ ATADEBUG_PRINT(("wdcintr: irq not expected\n"), DEBUG_INTR);
+ goto ignore;
+ }
+
xfer = ata_queue_get_active_xfer(chp);
if (xfer == NULL) {
ATADEBUG_PRINT(("wdcintr: inactive controller\n"), DEBUG_INTR);
@@ -915,8 +920,11 @@ ignore:
chp->ch_flags &= ~ATACH_DMA_WAIT;
}
#endif
+ chp->ch_flags &= ~ATACH_IRQ_WAIT;
KASSERT(xfer->c_intr != NULL);
ret = xfer->c_intr(chp, xfer, 1);
+ if (ret == 0) /* irq was not for us, still waiting for irq */
+ chp->ch_flags |= ATACH_IRQ_WAIT;
return (ret);
}
@@ -943,6 +951,8 @@ wdc_reset_channel(struct ata_channel *ch
struct wdc_softc *wdc = CHAN_TO_WDC(chp);
#endif
+ chp->ch_flags &= ~ATACH_IRQ_WAIT;
+
/*
* if the current command is on an ATAPI device, issue a
* ATAPI_SOFT_RESET
@@ -1465,6 +1475,7 @@ __wdccommand_start(struct ata_channel *c
}
if ((ata_c->flags & AT_POLL) == 0) {
+ chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
callout_reset(&xfer->c_timo_callout, ata_c->timeout / 1000 * hz,
wdctimeout, xfer);
return ATASTART_STARTED;
@@ -1587,6 +1598,7 @@ again:
wdc->dataout_pio(chp, drive_flags, data, bcount);
ata_c->flags |= AT_XFDONE;
if ((ata_c->flags & AT_POLL) == 0) {
+ chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
callout_reset(&xfer->c_timo_callout,
mstohz(ata_c->timeout), wdctimeout, xfer);
ata_channel_unlock(chp);
Index: src/sys/dev/pci/pciide_common.c
diff -u src/sys/dev/pci/pciide_common.c:1.63 src/sys/dev/pci/pciide_common.c:1.64
--- src/sys/dev/pci/pciide_common.c:1.63 Sat Oct 7 16:05:33 2017
+++ src/sys/dev/pci/pciide_common.c Tue Oct 17 18:52:50 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: pciide_common.c,v 1.63 2017/10/07 16:05:33 jdolecek Exp $ */
+/* $NetBSD: pciide_common.c,v 1.64 2017/10/17 18:52:50 jdolecek Exp $ */
/*
@@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pciide_common.c,v 1.63 2017/10/07 16:05:33 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pciide_common.c,v 1.64 2017/10/17 18:52:50 jdolecek Exp $");
#include <sys/param.h>
@@ -553,6 +553,10 @@ pciide_pci_intr(void *arg)
if (cp->compat)
continue;
+ /* if this channel not waiting for intr, skip */
+ if ((wdc_cp->ch_flags & ATACH_IRQ_WAIT) == 0)
+ continue;
+
crv = wdcintr(wdc_cp);
if (crv == 0)
; /* leave rv alone */
Index: src/sys/dev/scsipi/atapi_wdc.c
diff -u src/sys/dev/scsipi/atapi_wdc.c:1.128 src/sys/dev/scsipi/atapi_wdc.c:1.129
--- src/sys/dev/scsipi/atapi_wdc.c:1.128 Tue Oct 10 21:37:49 2017
+++ src/sys/dev/scsipi/atapi_wdc.c Tue Oct 17 18:52:51 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: atapi_wdc.c,v 1.128 2017/10/10 21:37:49 jdolecek Exp $ */
+/* $NetBSD: atapi_wdc.c,v 1.129 2017/10/17 18:52:51 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -25,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.128 2017/10/10 21:37:49 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.129 2017/10/17 18:52:51 jdolecek Exp $");
#ifndef ATADEBUG
#define ATADEBUG
@@ -672,8 +672,10 @@ ready:
if ((sc_xfer->xs_periph->periph_cap & ATAPI_CFG_DRQ_MASK) !=
ATAPI_CFG_IRQ_DRQ || (sc_xfer->xs_control & XS_CTL_POLL))
return ATASTART_POLL;
- else
+ else {
+ chp->ch_flags |= ATACH_IRQ_WAIT;
return ATASTART_STARTED;
+ }
timeout:
printf("%s:%d:%d: %s timed out\n",
@@ -884,6 +886,11 @@ again:
chp->ch_flags |= ATACH_DMA_WAIT;
}
#endif
+
+ if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) {
+ chp->ch_flags |= ATACH_IRQ_WAIT;
+ }
+
ata_channel_unlock(chp);
return 1;
@@ -917,7 +924,8 @@ again:
(*wdc->piobm_start)(wdc->dma_arg,
chp->ch_channel, xfer->c_drive,
xfer->c_skip, len, WDC_PIOBM_XFER_IRQ);
- chp->ch_flags |= ATACH_DMA_WAIT | ATACH_PIOBM_WAIT;
+ chp->ch_flags |= ATACH_DMA_WAIT | ATACH_IRQ_WAIT |
+ ATACH_PIOBM_WAIT;
ata_channel_unlock(chp);
return 1;
}
@@ -934,6 +942,9 @@ again:
xfer->c_skip += len;
xfer->c_bcount -= len;
+ if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) {
+ chp->ch_flags |= ATACH_IRQ_WAIT;
+ }
ata_channel_unlock(chp);
return 1;
@@ -967,7 +978,8 @@ again:
(*wdc->piobm_start)(wdc->dma_arg,
chp->ch_channel, xfer->c_drive,
xfer->c_skip, len, WDC_PIOBM_XFER_IRQ);
- chp->ch_flags |= ATACH_DMA_WAIT | ATACH_PIOBM_WAIT;
+ chp->ch_flags |= ATACH_DMA_WAIT | ATACH_IRQ_WAIT |
+ ATACH_PIOBM_WAIT;
ata_channel_unlock(chp);
return 1;
}
@@ -983,6 +995,9 @@ again:
xfer->c_skip += len;
xfer->c_bcount -= len;
+ if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) {
+ chp->ch_flags |= ATACH_IRQ_WAIT;
+ }
ata_channel_unlock(chp);
return 1;
@@ -1080,7 +1095,6 @@ wdc_atapi_phase_complete(struct ata_xfer
}
}
-
/*
* Some drive occasionally set WDCS_ERR with
* "ATA illegal length indication" in the error