Source-Changes-HG archive

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

[src/jdolecek-ncq]: src/sys/dev add ata_channel lock, use it to protect queue...



details:   https://anonhg.NetBSD.org/src/rev/5df027757de3
branches:  jdolecek-ncq
changeset: 822930:5df027757de3
user:      jdolecek <jdolecek%NetBSD.org@localhost>
date:      Mon Jun 19 21:00:00 2017 +0000

description:
add ata_channel lock, use it to protect queue manipulation (only that for now);
add ata_channel_detach() to destroy the locks

change ata_get_xfer() so that it can wait for xfer, convert all on-stack
xfer code to use the blocking variant

fix siisata_reset_drive() to use polled reset and not try ata_activate_xfer(),
convert drive probe code also over from slot0 XXX to ata_get_xfer()

drive reset and PMP now works on siisata(4) too; changes tested also
on piixide(4), ahci(4), mvsata(4)

diffstat:

 sys/dev/ata/TODO.ncq       |   10 +-
 sys/dev/ata/ata.c          |   88 ++++++++++++++++---
 sys/dev/ata/atavar.h       |   22 ++--
 sys/dev/ata/satapmp_subr.c |   80 +++++++++--------
 sys/dev/ata/wd.c           |  200 ++++++++++++++++++++++++--------------------
 sys/dev/ic/ahcisata_core.c |    8 +-
 sys/dev/ic/mvsata.c        |    6 +-
 sys/dev/ic/siisata.c       |   51 +++++++---
 sys/dev/ic/wdc.c           |    5 +-
 sys/dev/scsipi/atapi_wdc.c |   34 ++++---
 sys/dev/usb/umass_isdata.c |   29 +++--
 11 files changed, 324 insertions(+), 209 deletions(-)

diffs (truncated from 1292 to 300 lines):

diff -r ce7393941e5d -r 5df027757de3 sys/dev/ata/TODO.ncq
--- a/sys/dev/ata/TODO.ncq      Mon Jun 19 17:11:24 2017 +0000
+++ b/sys/dev/ata/TODO.ncq      Mon Jun 19 21:00:00 2017 +0000
@@ -6,11 +6,11 @@
 siisata - fix all new XXX and unmergable bits, fix PMP
 
 test crashdump with siisata
-
-reset channel and PMP doesn't work with siisata - siisata_reset_drive()
-uses ata_get_xfer() and this can clash on slot 0 with on-stack xfers
+- fails with recursive panic via pmap_kremove_local() regardless if
+  drive connected via PMP or direct
 
 test wd* at umass?, confirm the ata_channel kludge works
++ add detach code (channel detach, free queue)
 
 is ata_exec_xfer() + POLL safe wrt. more outstanding I/Os? why is it waiting
 until xfer is head of queue? also layer violation with the ata_xfer_free() call
@@ -30,6 +30,10 @@
   to have active or pending transfers (e.g. when non-NCQ device is attached
   while there is already NCQ device present)
 
+add mechanics to re-check queue when xfer is finished - needed on PMP
+and for IDE disks, when one drive uses up all available xfers nothing
+ever restarts queue for the other drives
+
 Other random notes (do outside the NCQ branch):
 -----------------------------------------------------
 change wd(4) to use dk_open()
diff -r ce7393941e5d -r 5df027757de3 sys/dev/ata/ata.c
--- a/sys/dev/ata/ata.c Mon Jun 19 17:11:24 2017 +0000
+++ b/sys/dev/ata/ata.c Mon Jun 19 21:00:00 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ata.c,v 1.132.8.10 2017/06/17 14:01:36 jdolecek Exp $  */
+/*     $NetBSD: ata.c,v 1.132.8.11 2017/06/19 21:00:00 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.10 2017/06/17 14:01:36 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.11 2017/06/19 21:00:00 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -129,6 +129,9 @@
 static bool atabus_suspend(device_t, const pmf_qual_t *);
 static void atabusconfig_thread(void *);
 
+static void ata_xfer_init(struct ata_xfer *, bool);
+static void ata_xfer_destroy(struct ata_xfer *);
+
 /*
  * atabus_init:
  *
@@ -221,7 +224,7 @@
        return TAILQ_FIRST(&chq->active_xfers);
 }
 
-void
+static void
 ata_xfer_init(struct ata_xfer *xfer, bool zero)
 {
        if (zero)
@@ -230,7 +233,7 @@
        callout_init(&xfer->c_timo_callout, 0);         /* XXX MPSAFE */
 }
 
-void
+static void
 ata_xfer_destroy(struct ata_xfer *xfer)
 {
        callout_halt(&xfer->c_timo_callout, NULL);      /* XXX MPSAFE */
@@ -257,6 +260,8 @@
        chq->queue_openings = openings;
        ata_queue_reset(chq);
 
+       cv_init(&chq->queue_busy, "ataqbusy");
+
        for (uint8_t i = 0; i < openings; i++)
                ata_xfer_init(&chq->queue_xfers[i], false);
 
@@ -283,6 +288,12 @@
        free(chq, M_DEVBUF);
 }
 
+void
+ata_channel_init(struct ata_channel *chp)
+{
+       mutex_init(&chp->ch_lock, MUTEX_DEFAULT, IPL_BIO);
+}
+
 /*
  * ata_channel_attach:
  *
@@ -291,17 +302,37 @@
 void
 ata_channel_attach(struct ata_channel *chp)
 {
-       struct ata_queue * const chq = chp->ch_queue;
-
        if (chp->ch_flags & ATACH_DISABLED)
                return;
 
-       ata_queue_reset(chq);
+       KASSERT(chp->ch_queue != NULL);
+
+       ata_channel_init(chp);
 
        chp->atabus = config_found_ia(chp->ch_atac->atac_dev, "ata", chp,
                atabusprint);
 }
 
+void
+ata_channel_destroy(struct ata_channel *chp)
+{
+       mutex_destroy(&chp->ch_lock);
+}
+
+/*
+ * ata_channel_detach:
+ *
+ *     Common parts of detaching an atabus to an ATA controller channel.
+ */
+void
+ata_channel_detach(struct ata_channel *chp)
+{
+       if (chp->ch_flags & ATACH_DISABLED)
+               return;
+
+       ata_channel_destroy(chp);
+}
+
 static void
 atabusconfig(struct atabus_softc *atabus_sc)
 {
@@ -1130,17 +1161,27 @@
 }
 
 struct ata_xfer *
-ata_get_xfer(struct ata_channel *chp)
+ata_get_xfer(struct ata_channel *chp, bool wait)
 {
        struct ata_queue *chq = chp->ch_queue;
        struct ata_xfer *xfer = NULL;
-       int s;
        uint32_t avail, slot;
+       int error;
+
+       mutex_enter(&chp->ch_lock);
 
-       s = splbio();
+retry:
        avail = ffs32(chq->queue_xfers_avail);
-       if (avail == 0)
+       if (avail == 0) {
+               if (wait) {
+                       chq->queue_flags |= QF_NEED_XFER;
+                       error = cv_wait_sig(&chq->queue_busy, &chp->ch_lock);
+                       if (error == 0)
+                               goto retry;
+               }
+
                goto out;
+       }
 
        slot = avail - 1;
        xfer = &chq->queue_xfers[slot];
@@ -1154,7 +1195,7 @@
        xfer->c_slot = slot;
 
 out:
-       splx(s);
+       mutex_exit(&chp->ch_lock);
        return xfer;
 }
 
@@ -1165,13 +1206,14 @@
 ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
 {
        struct ata_queue *chq = chp->ch_queue;
-       int s;
+
+       mutex_enter(&chp->ch_lock);
 
        if (xfer->c_flags & C_WAITACT) {
                /* Someone is waiting for this xfer, so we can't free now */
                xfer->c_flags |= C_FREE;
                wakeup(xfer);
-               return;
+               goto out;
        }
 
 #if NATA_PIOBM         /* XXX wdc dependent code */
@@ -1185,11 +1227,17 @@
        }
 #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);
+
+out:
+       if (chq->queue_flags & QF_NEED_XFER) {
+               chq->queue_flags &= ~QF_NEED_XFER;
+               cv_broadcast(&chq->queue_busy);
+       }
+
+       mutex_exit(&chp->ch_lock);
 }
 
 void
@@ -1197,6 +1245,8 @@
 {
        struct ata_queue * const chq = chp->ch_queue;
 
+       mutex_enter(&chp->ch_lock);
+
        KASSERT(chq->queue_active < chq->queue_openings);
        KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0);
 
@@ -1204,6 +1254,8 @@
        TAILQ_INSERT_TAIL(&chq->active_xfers, xfer, c_activechain);
        chq->active_xfers_used |= __BIT(xfer->c_slot);
        chq->queue_active++;
+
+       mutex_exit(&chp->ch_lock);
 }
 
 void
@@ -1211,6 +1263,8 @@
 {
        struct ata_queue * const chq = chp->ch_queue;
 
+       mutex_enter(&chp->ch_lock);
+
        KASSERT(chq->queue_active > 0);
        KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) != 0);
 
@@ -1219,6 +1273,8 @@
        TAILQ_REMOVE(&chq->active_xfers, xfer, c_activechain);
        chq->active_xfers_used &= ~__BIT(xfer->c_slot);
        chq->queue_active--;
+
+       mutex_exit(&chp->ch_lock);
 }
 
 
diff -r ce7393941e5d -r 5df027757de3 sys/dev/ata/atavar.h
--- a/sys/dev/ata/atavar.h      Mon Jun 19 17:11:24 2017 +0000
+++ b/sys/dev/ata/atavar.h      Mon Jun 19 21:00:00 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: atavar.h,v 1.92.8.9 2017/06/16 20:40:49 jdolecek Exp $ */
+/*     $NetBSD: atavar.h,v 1.92.8.10 2017/06/19 21:00:00 jdolecek Exp $        */
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -186,12 +186,14 @@
 /* Per-channel queue of ata_xfers */
 struct ata_queue {
        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 */
-       int queue_active; /* number of active transfers */
-       int queue_openings; /* max number of active transfers */
+       int queue_freeze;               /* freeze count for the queue */
+       int8_t queue_flags;             /* flags for this queue */
+#define QF_IDLE_WAIT   0x01            /* someone wants the controller idle */
+#define QF_NEED_XFER   0x02            /* someone wants xfer */
+       int8_t queue_active;            /* number of active transfers */
+       int8_t queue_openings;          /* max number of active transfers */
 #ifdef ATABUS_PRIVATE
+       kcondvar_t queue_busy;                  /* c: waiting of xfer */
        TAILQ_HEAD(, ata_xfer) active_xfers;    /* active commands */
        uint32_t active_xfers_used;             /* mask of active commands */
        uint32_t queue_xfers_avail;             /* available xfers mask */
@@ -358,6 +360,7 @@
 struct ata_channel {
        int ch_channel;                 /* location */
        struct atac_softc *ch_atac;     /* ATA controller softc */
+       kmutex_t ch_lock;               /* channel lock - queue */
 
        /* Our state */
        volatile int ch_flags;
@@ -457,6 +460,9 @@
 
 #ifdef _KERNEL
 void   ata_channel_attach(struct ata_channel *);
+void   ata_channel_init(struct ata_channel *);
+void   ata_channel_detach(struct ata_channel *);
+void   ata_channel_destroy(struct ata_channel *);
 int    atabusprint(void *aux, const char *);
 int    ataprint(void *aux, const char *);
 
@@ -471,7 +477,7 @@



Home | Main Index | Thread Index | Old Index