Source-Changes-HG archive

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

[src/jdolecek-ncq]: src/sys/dev adjust reset channel and dump paths



details:   https://anonhg.NetBSD.org/src/rev/2ae4f97bb5a3
branches:  jdolecek-ncq
changeset: 822924:2ae4f97bb5a3
user:      jdolecek <jdolecek%NetBSD.org@localhost>
date:      Fri Jun 16 20:40:49 2017 +0000

description:
adjust reset channel and dump paths
- channel reset now always kills active transfer, even on dump path, but
  now doesn't touch the queued waiting transfers; also kill_xfer hook is
  always called, so that HBA can free any private xfer resources and thus
  the dump request has chance to work
- kill_xfer routines now always call ata_deactivate_xfer(); added KASSERT()s
  to ata_free_xfer() to expect deactivated xfer
- when called during channel reset before dump, ata_kill_active() drops
  any queued waiting transfers without processing
- do not (re)queue any transfers in wddone() when dumping
- kill AT_RST_NOCMD flag

This should also hopefully fix the 'polled command has been queued' panic
as reported in:
PR kern/11811 by John Hawkinson
PR kern/47041 by Taylor R Campbell
PR kern/51979 by Martin Husemann

dump tested working with piixide(4) and ahci(4). mvsata(4) dump times out,
but otherwise tested working, will be fixed separately. siisata(4) mechanically
changed and not tested.

diffstat:

 sys/dev/ata/ata.c          |  35 ++++++++++++++++----
 sys/dev/ata/ata_wdc.c      |   6 ++-
 sys/dev/ata/atavar.h       |   9 ++--
 sys/dev/ata/wd.c           |  21 ++++++-----
 sys/dev/ic/ahcisata_core.c |  43 +++++++++---------------
 sys/dev/ic/mvsata.c        |  31 +++++++----------
 sys/dev/ic/siisata.c       |  14 ++++----
 sys/dev/ic/wdc.c           |  80 +++++++++++++++------------------------------
 sys/dev/scsipi/atapi_wdc.c |   6 ++-
 9 files changed, 116 insertions(+), 129 deletions(-)

diffs (truncated from 739 to 300 lines):

diff -r 01f19f60d2be -r 2ae4f97bb5a3 sys/dev/ata/ata.c
--- a/sys/dev/ata/ata.c Fri Jun 16 18:01:10 2017 +0000
+++ b/sys/dev/ata/ata.c Fri Jun 16 20:40:49 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ata.c,v 1.132.8.8 2017/04/24 22:20:23 jdolecek Exp $   */
+/*     $NetBSD: ata.c,v 1.132.8.9 2017/06/16 20:40:49 jdolecek Exp $   */
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.8 2017/04/24 22:20:23 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.9 2017/06/16 20:40:49 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -187,6 +187,8 @@
        TAILQ_INIT(&chq->active_xfers);
        chq->queue_freeze = 0;
        chq->queue_active = 0;
+       chq->active_xfers_used = 0;
+       chq->queue_xfers_avail = (1 << chq->queue_openings) - 1;
 }
 
 struct ata_xfer *
@@ -207,6 +209,18 @@
            chq->active_xfers_used);
 }
 
+/*
+ * This interface is supposed only to be used when there is exactly
+ * one outstanding command, and there is no information about the slot,
+ * which triggered the command. ata_queue_hwslot_to_xfer() interface
+ * is preferred in all standard cases.
+ */
+struct ata_xfer *
+ata_queue_active_xfer_peek(struct ata_queue *chq)
+{
+       return TAILQ_FIRST(&chq->active_xfers);
+}
+
 void
 ata_xfer_init(struct ata_xfer *xfer, bool zero)
 {
@@ -241,7 +255,6 @@
            M_DEVBUF, M_WAITOK | M_ZERO);
 
        chq->queue_openings = openings;
-       chq->queue_xfers_avail = (1 << openings) - 1;
        ata_queue_reset(chq);
 
        for (uint8_t i = 0; i < openings; i++)
@@ -258,7 +271,6 @@
        KASSERT(openings < chq->queue_openings);
 
        chq->queue_openings = openings;
-       chq->queue_xfers_avail = (1 << openings) - 1;
        ata_queue_reset(chq);
 }
 
@@ -1136,6 +1148,8 @@
        xfer = &chq->queue_xfers[slot];
        chq->queue_xfers_avail &= ~__BIT(slot);
 
+       KASSERT((chq->active_xfers_used & __BIT(slot)) == 0);
+
        /* zero everything after the callout member */
        memset(&xfer->c_startzero, 0,
            sizeof(struct ata_xfer) - offsetof(struct ata_xfer, c_startzero));
@@ -1146,6 +1160,9 @@
        return xfer;
 }
 
+/*
+ * ata_deactivate_xfer() must be always called prior to ata_free_xfer()
+ */
 void
 ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
 {
@@ -1171,6 +1188,7 @@
 #endif
 
        s = splbio();
+       KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0);
        KASSERT((chq->queue_xfers_avail & __BIT(xfer->c_slot)) == 0);
        chq->queue_xfers_avail |= __BIT(xfer->c_slot);
        splx(s);
@@ -1236,7 +1254,7 @@
  * Must be called at splbio().
  */
 void
-ata_kill_active(struct ata_channel *chp, int reason)
+ata_kill_active(struct ata_channel *chp, int reason, int flags)
 {
        struct ata_queue * const chq = chp->ch_queue;
        struct ata_xfer *xfer, *xfernext;
@@ -1244,6 +1262,9 @@
        TAILQ_FOREACH_SAFE(xfer, &chq->active_xfers, c_activechain, xfernext) {
                (*xfer->c_kill_xfer)(xfer->c_chp, xfer, reason);
        }
+
+       if (flags & AT_RST_EMERG)
+               ata_queue_reset(chq);
 }
 
 /*
@@ -1322,7 +1343,7 @@
                        return;
                }
                chp->ch_flags |= ATACH_TH_RESET;
-               chp->ch_reset_flags = flags & (AT_RST_EMERG | AT_RST_NOCMD);
+               chp->ch_reset_flags = flags & AT_RST_EMERG;
                wakeup(&chp->ch_thread);
                return;
        }
@@ -1486,7 +1507,7 @@
        (*atac->atac_set_modes)(chp);
        ata_print_modes(chp);
        /* reset the channel, which will schedule all drives for setup */
-       ata_reset_channel(chp, flags | AT_RST_NOCMD);
+       ata_reset_channel(chp, flags);
        return 1;
 }
 #endif /* NATA_DMA */
diff -r 01f19f60d2be -r 2ae4f97bb5a3 sys/dev/ata/ata_wdc.c
--- a/sys/dev/ata/ata_wdc.c     Fri Jun 16 18:01:10 2017 +0000
+++ b/sys/dev/ata/ata_wdc.c     Fri Jun 16 20:40:49 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ata_wdc.c,v 1.105.6.3 2017/04/19 20:49:17 jdolecek Exp $       */
+/*     $NetBSD: ata_wdc.c,v 1.105.6.4 2017/06/16 20:40:49 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.105.6.3 2017/04/19 20:49:17 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.105.6.4 2017/06/16 20:40:49 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wdc.h"
@@ -775,6 +775,8 @@
        struct ata_bio *ata_bio = &xfer->c_bio;
        int drive = xfer->c_drive;
 
+       ata_deactivate_xfer(chp, xfer);
+
        ata_bio->flags |= ATA_ITSDONE;
        switch (reason) {
        case KILL_GONE:
diff -r 01f19f60d2be -r 2ae4f97bb5a3 sys/dev/ata/atavar.h
--- a/sys/dev/ata/atavar.h      Fri Jun 16 18:01:10 2017 +0000
+++ b/sys/dev/ata/atavar.h      Fri Jun 16 20:40:49 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: atavar.h,v 1.92.8.8 2017/04/24 22:20:23 jdolecek Exp $ */
+/*     $NetBSD: atavar.h,v 1.92.8.9 2017/06/16 20:40:49 jdolecek Exp $ */
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -185,7 +185,7 @@
 
 /* Per-channel queue of ata_xfers */
 struct ata_queue {
-       TAILQ_HEAD(, ata_xfer) queue_xfer; /* queue of pending commands */
+       TAILQ_HEAD(, ata_xfer) queue_xfer;      /* queue of pending commands */
        int queue_freeze; /* freeze count for the queue */
        int queue_flags;        /* flags for this queue */
 #define QF_IDLE_WAIT   0x01    /* someone wants the controller idle */
@@ -322,7 +322,6 @@
        void    (*ata_reset_channel)(struct ata_channel *, int);
 /* extra flags for ata_reset_*(), in addition to AT_* */
 #define AT_RST_EMERG 0x10000 /* emergency - e.g. for a dump */
-#define        AT_RST_NOCMD 0x20000 /* XXX has to go - temporary until we have tagged queuing */
 
        int     (*ata_exec_command)(struct ata_drive_datas *,
                                    struct ata_xfer *);
@@ -482,7 +481,7 @@
 
 void   ata_exec_xfer(struct ata_channel *, struct ata_xfer *);
 void   ata_kill_pending(struct ata_drive_datas *);
-void   ata_kill_active(struct ata_channel *, int);
+void   ata_kill_active(struct ata_channel *, int, int);
 void   ata_reset_channel(struct ata_channel *, int);
 
 int    ata_addref(struct ata_channel *);
@@ -505,6 +504,8 @@
 void   ata_queue_free(struct ata_queue *);
 struct ata_xfer *
        ata_queue_hwslot_to_xfer(struct ata_queue *, int);
+struct ata_xfer *
+       ata_queue_active_xfer_peek(struct ata_queue *);
 
 void   ata_delay(int, const char *, int);
 
diff -r 01f19f60d2be -r 2ae4f97bb5a3 sys/dev/ata/wd.c
--- a/sys/dev/ata/wd.c  Fri Jun 16 18:01:10 2017 +0000
+++ b/sys/dev/ata/wd.c  Fri Jun 16 20:40:49 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: wd.c,v 1.428.2.15 2017/06/14 20:17:46 jdolecek Exp $ */
+/*     $NetBSD: wd.c,v 1.428.2.16 2017/06/16 20:40:49 jdolecek Exp $ */
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -54,7 +54,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.15 2017/06/14 20:17:46 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.16 2017/06/16 20:40:49 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -168,6 +168,10 @@
        .d_flag = D_DISK | D_MPSAFE
 };
 
+/* #define WD_DUMP_NOT_TRUSTED if you just want to watch */
+static int wddoingadump = 0;
+static int wddumprecalibrated = 0;
+
 /*
  * Glue necessary to hook WDCIOCCOMMAND into physio
  */
@@ -742,6 +746,11 @@
 
        ATADEBUG_PRINT(("wddone %s\n", device_xname(wd->sc_dev)),
            DEBUG_XFERS);
+       if (wddoingadump) {
+               /* just drop it to the floor */
+               ata_free_xfer(wd->drvp->chnl_softc, xfer);
+               return;
+       }
 
        mutex_enter(&wd->sc_lock);
 
@@ -770,7 +779,7 @@
                errmsg = "error";
                do_perror = 1;
 retry:         /* Just reset and retry. Can we do more ? */
-               (*wd->atabus->ata_reset_drive)(wd->drvp, AT_RST_NOCMD, NULL);
+               (*wd->atabus->ata_reset_drive)(wd->drvp, 0, NULL);
 retry2:
                diskerr(bp, "wd", errmsg, LOG_PRINTF,
                    xfer->c_bio.blkdone, wd->sc_dk.dk_label);
@@ -1583,10 +1592,6 @@
        return (size);
 }
 
-/* #define WD_DUMP_NOT_TRUSTED if you just want to watch */
-static int wddoingadump = 0;
-static int wddumprecalibrated = 0;
-
 /*
  * Dump core after a system crash.
  */
@@ -1683,8 +1688,6 @@
                panic("wddump: unknown error type %d", err);
        }
 
-       ata_free_xfer(wd->drvp->chnl_softc, xfer);
-
        if (err != 0) {
                printf("\n");
                return err;
diff -r 01f19f60d2be -r 2ae4f97bb5a3 sys/dev/ic/ahcisata_core.c
--- a/sys/dev/ic/ahcisata_core.c        Fri Jun 16 18:01:10 2017 +0000
+++ b/sys/dev/ic/ahcisata_core.c        Fri Jun 16 20:40:49 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ahcisata_core.c,v 1.57.6.12 2017/04/25 20:55:05 jdolecek Exp $ */
+/*     $NetBSD: ahcisata_core.c,v 1.57.6.13 2017/06/16 20:40:49 jdolecek Exp $ */
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.12 2017/04/25 20:55:05 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.13 2017/06/16 20:40:49 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -673,10 +673,7 @@
                            AHCINAME(sc), chp->ch_channel, is);
                        return ERR_DF;
                }
-               if (flags & AT_WAIT)
-                       tsleep(&sc, PRIBIO, "ahcifis", 1);
-               else
-                       delay(10000);
+               ata_delay(10, "ahcifis", flags);
        }
 
        aprint_debug("%s channel %d: timeout sending FIS\n",
@@ -779,10 +776,7 @@
                sig = AHCI_READ(sc, AHCI_P_TFD(chp->ch_channel));
                if ((__SHIFTOUT(sig, AHCI_P_TFD_ST) & WDCS_BSY) == 0)



Home | Main Index | Thread Index | Old Index