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