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

Reply via email to