Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev reintroduce ATACH_IRQ_WAIT flag for attachments usin...



details:   https://anonhg.NetBSD.org/src/rev/4ccb4b7f0525
branches:  trunk
changeset: 827165:4ccb4b7f0525
user:      jdolecek <jdolecek%NetBSD.org@localhost>
date:      Tue Oct 17 18:52:50 2017 +0000

description:
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

diffstat:

 sys/dev/ata/ata_subr.c      |   6 +++---
 sys/dev/ata/ata_wdc.c       |  11 ++++++++---
 sys/dev/ata/atavar.h        |   3 ++-
 sys/dev/ic/wdc.c            |  16 ++++++++++++++--
 sys/dev/pci/pciide_common.c |   8 ++++++--
 sys/dev/scsipi/atapi_wdc.c  |  26 ++++++++++++++++++++------
 6 files changed, 53 insertions(+), 17 deletions(-)

diffs (262 lines):

diff -r 0ac39e42893c -r 4ccb4b7f0525 sys/dev/ata/ata_subr.c
--- a/sys/dev/ata/ata_subr.c    Tue Oct 17 16:24:14 2017 +0000
+++ b/sys/dev/ata/ata_subr.c    Tue Oct 17 18:52:50 2017 +0000
@@ -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 @@
                /* 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
 
diff -r 0ac39e42893c -r 4ccb4b7f0525 sys/dev/ata/ata_wdc.c
--- a/sys/dev/ata/ata_wdc.c     Tue Oct 17 16:24:14 2017 +0000
+++ b/sys/dev/ata/ata_wdc.c     Tue Oct 17 18:52:50 2017 +0000
@@ -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 @@
 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",
diff -r 0ac39e42893c -r 4ccb4b7f0525 sys/dev/ata/atavar.h
--- a/sys/dev/ata/atavar.h      Tue Oct 17 16:24:14 2017 +0000
+++ b/sys/dev/ata/atavar.h      Tue Oct 17 18:52:50 2017 +0000
@@ -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 @@
        /* 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 */
diff -r 0ac39e42893c -r 4ccb4b7f0525 sys/dev/ic/wdc.c
--- a/sys/dev/ic/wdc.c  Tue Oct 17 16:24:14 2017 +0000
+++ b/sys/dev/ic/wdc.c  Tue Oct 17 18:52:50 2017 +0000
@@ -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 @@
                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 @@
                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 @@
        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 @@
        }
 
        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 @@
                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);
diff -r 0ac39e42893c -r 4ccb4b7f0525 sys/dev/pci/pciide_common.c
--- a/sys/dev/pci/pciide_common.c       Tue Oct 17 16:24:14 2017 +0000
+++ b/sys/dev/pci/pciide_common.c       Tue Oct 17 18:52:50 2017 +0000
@@ -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 @@
                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 */
diff -r 0ac39e42893c -r 4ccb4b7f0525 sys/dev/scsipi/atapi_wdc.c
--- a/sys/dev/scsipi/atapi_wdc.c        Tue Oct 17 16:24:14 2017 +0000
+++ b/sys/dev/scsipi/atapi_wdc.c        Tue Oct 17 18:52:50 2017 +0000
@@ -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 @@
        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 @@
                        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 @@
                        (*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 @@
 
                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 @@
                        (*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 @@
 
                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 @@
                }
        }
 
-
        /*
         * Some drive occasionally set WDCS_ERR with
         * "ATA illegal length indication" in the error



Home | Main Index | Thread Index | Old Index