Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/ic implement DIOCGCACHE



details:   https://anonhg.NetBSD.org/src/rev/3acda8c7681e
branches:  trunk
changeset: 351832:3acda8c7681e
user:      jdolecek <jdolecek%NetBSD.org@localhost>
date:      Tue Feb 28 20:53:50 2017 +0000

description:
implement DIOCGCACHE

diffstat:

 sys/dev/ic/ld_nvme.c |  132 ++++++++++++++++++++++++++++++++++++++++++++++----
 sys/dev/ic/nvme.c    |   70 +++++++++++++++++++++++++-
 sys/dev/ic/nvmereg.h |    7 ++-
 sys/dev/ic/nvmevar.h |    6 +-
 4 files changed, 196 insertions(+), 19 deletions(-)

diffs (truncated from 361 to 300 lines):

diff -r d094dc8a8fa8 -r 3acda8c7681e sys/dev/ic/ld_nvme.c
--- a/sys/dev/ic/ld_nvme.c      Tue Feb 28 17:35:29 2017 +0000
+++ b/sys/dev/ic/ld_nvme.c      Tue Feb 28 20:53:50 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ld_nvme.c,v 1.12 2017/02/27 21:48:34 jdolecek Exp $    */
+/*     $NetBSD: ld_nvme.c,v 1.13 2017/02/28 20:53:50 jdolecek Exp $    */
 
 /*-
  * Copyright (C) 2016 NONAKA Kimihiro <nonaka%netbsd.org@localhost>
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_nvme.c,v 1.12 2017/02/27 21:48:34 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_nvme.c,v 1.13 2017/02/28 20:53:50 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -49,6 +49,14 @@
        struct nvme_softc       *sc_nvme;
 
        uint16_t                sc_nsid;
+
+       /* getcache handling */
+       kmutex_t                sc_getcache_lock;
+       kcondvar_t              sc_getcache_cv;
+       kcondvar_t              sc_getcache_ready_cv;
+       bool                    sc_getcache_waiting;
+       bool                    sc_getcache_ready;
+       int                     sc_getcache_result;
 };
 
 static int     ld_nvme_match(device_t, cfdata_t, void *);
@@ -61,10 +69,12 @@
 static int     ld_nvme_start(struct ld_softc *, struct buf *);
 static int     ld_nvme_dump(struct ld_softc *, void *, int, int);
 static int     ld_nvme_flush(struct ld_softc *, bool);
+static int     ld_nvme_getcache(struct ld_softc *, int *);
 static int     ld_nvme_ioctl(struct ld_softc *, u_long, void *, int32_t, bool);
 
-static void    ld_nvme_biodone(void *, struct buf *, uint16_t);
-static void    ld_nvme_syncdone(void *, struct buf *, uint16_t);
+static void    ld_nvme_biodone(void *, struct buf *, uint16_t, uint32_t);
+static void    ld_nvme_syncdone(void *, struct buf *, uint16_t, uint32_t);
+static void    ld_nvme_getcache_done(void *, struct buf *, uint16_t, uint32_t);
 
 static int
 ld_nvme_match(device_t parent, cfdata_t match, void *aux)
@@ -93,6 +103,10 @@
        sc->sc_nvme = nsc;
        sc->sc_nsid = naa->naa_nsid;
 
+       mutex_init(&sc->sc_getcache_lock, MUTEX_DEFAULT, IPL_SOFTBIO);
+       cv_init(&sc->sc_getcache_cv, "nvmegcq");
+       cv_init(&sc->sc_getcache_ready_cv, "nvmegcr");
+
        aprint_naive("\n");
        aprint_normal("\n");
 
@@ -159,7 +173,7 @@
 }
 
 static void
-ld_nvme_biodone(void *xc, struct buf *bp, uint16_t cmd_status)
+ld_nvme_biodone(void *xc, struct buf *bp, uint16_t cmd_status, uint32_t cdw0)
 {
        struct ld_nvme_softc *sc = xc;
        uint16_t status = NVME_CQE_SC(cmd_status);
@@ -190,6 +204,104 @@
            ld_nvme_syncdone);
 }
 
+static void
+ld_nvme_syncdone(void *xc, struct buf *bp, uint16_t cmd_status, uint32_t cdw0)
+{
+       /* nothing to do */
+}
+
+static int
+ld_nvme_getcache(struct ld_softc *ld, int *addr)
+{
+       int error;
+       struct ld_nvme_softc *sc = device_private(ld->sc_dv);
+
+       *addr = 0;
+
+       if (!nvme_has_volatile_write_cache(sc->sc_nvme)) {
+               /* cache simply not present */
+               return 0;
+       }
+
+       /*
+        * This is admin queue request. The queue is relatively limited in size,
+        * and this is not performance critical call, so have at most one pending
+        * cache request at a time to avoid spurious EWOULDBLOCK failures.
+        */ 
+       mutex_enter(&sc->sc_getcache_lock);
+       while (sc->sc_getcache_waiting) {
+               error = cv_wait_sig(&sc->sc_getcache_cv, &sc->sc_getcache_lock);
+               if (error)
+                       goto out;
+       }
+       sc->sc_getcache_waiting = true;
+       sc->sc_getcache_ready = false;
+       mutex_exit(&sc->sc_getcache_lock);
+
+       error = nvme_admin_getcache(sc->sc_nvme, sc, ld_nvme_getcache_done);
+       if (error) {
+               mutex_enter(&sc->sc_getcache_lock);
+               goto out;
+       }
+
+       mutex_enter(&sc->sc_getcache_lock);
+       while (!sc->sc_getcache_ready) {
+               error = cv_wait_sig(&sc->sc_getcache_ready_cv,
+                   &sc->sc_getcache_lock);
+               if (error)
+                       goto out;
+       }
+
+       KDASSERT(sc->sc_getcache_ready);
+
+       if (sc->sc_getcache_result >= 0)
+               *addr |= sc->sc_getcache_result;
+       else
+               error = EINVAL;
+
+    out:
+       sc->sc_getcache_waiting = false;
+
+       /* wake one of eventual waiters */
+       cv_signal(&sc->sc_getcache_cv);
+
+       mutex_exit(&sc->sc_getcache_lock);
+
+       return error;
+}
+
+static void
+ld_nvme_getcache_done(void *xc, struct buf *bp, uint16_t cmd_status, uint32_t cdw0)
+{
+       struct ld_nvme_softc *sc = xc;
+       uint16_t status = NVME_CQE_SC(cmd_status);
+       int result;
+
+       if (status == NVME_CQE_SC_SUCCESS) {
+               result = 0;
+
+               if (cdw0 & NVME_CQE_CDW0_VWC_WCE)
+                       result |= DKCACHE_WRITE;
+
+               /*
+                * If volatile write cache is present, the flag shall also be
+                * settable.
+                */
+               result |= DKCACHE_WCHANGE;
+       } else {
+               result = -1;
+       }
+
+       mutex_enter(&sc->sc_getcache_lock);
+       sc->sc_getcache_result = result;
+       sc->sc_getcache_ready = true;
+
+       /* wake up the waiter */
+       cv_signal(&sc->sc_getcache_ready_cv);
+
+       mutex_exit(&sc->sc_getcache_lock);
+}
+
 static int
 ld_nvme_ioctl(struct ld_softc *ld, u_long cmd, void *addr, int32_t flag, bool poll)
 {
@@ -200,6 +312,10 @@
                error = ld_nvme_flush(ld, poll);
                break;
 
+       case DIOCGCACHE:
+               error = ld_nvme_getcache(ld, (int *)addr);
+               break;
+
        default:
                error = EPASSTHROUGH;
                break;
@@ -208,12 +324,6 @@
        return error;
 }
 
-static void
-ld_nvme_syncdone(void *xc, struct buf *bp, uint16_t cmd_status)
-{
-       /* nothing to do */
-}
-
 MODULE(MODULE_CLASS_DRIVER, ld_nvme, "ld,nvme");
 
 #ifdef _MODULE
diff -r d094dc8a8fa8 -r 3acda8c7681e sys/dev/ic/nvme.c
--- a/sys/dev/ic/nvme.c Tue Feb 28 17:35:29 2017 +0000
+++ b/sys/dev/ic/nvme.c Tue Feb 28 20:53:50 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: nvme.c,v 1.24 2017/02/13 11:11:32 nonaka Exp $ */
+/*     $NetBSD: nvme.c,v 1.25 2017/02/28 20:53:50 jdolecek Exp $       */
 /*     $OpenBSD: nvme.c,v 1.49 2016/04/18 05:59:50 dlg Exp $ */
 
 /*
@@ -18,7 +18,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvme.c,v 1.24 2017/02/13 11:11:32 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvme.c,v 1.25 2017/02/28 20:53:50 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -99,6 +99,10 @@
                    void *);
 static void    nvme_ns_sync_done(struct nvme_queue *, struct nvme_ccb *,
                    struct nvme_cqe *);
+static void    nvme_getcache_fill(struct nvme_queue *, struct nvme_ccb *,
+                   void *);
+static void    nvme_getcache_done(struct nvme_queue *, struct nvme_ccb *,
+                   struct nvme_cqe *);
 
 static void    nvme_pt_fill(struct nvme_queue *, struct nvme_ccb *,
                    void *);
@@ -753,7 +757,18 @@
        bus_dmamap_unload(sc->sc_dmat, dmap);
        nvme_ccb_put(q, ccb);
 
-       nnc_done(nnc_cookie, bp, lemtoh16(&cqe->flags));
+       nnc_done(nnc_cookie, bp, lemtoh16(&cqe->flags), lemtoh32(&cqe->cdw0));
+}
+
+/*
+ * If there is no volatile write cache, it makes no sense to issue
+ * flush commands or query for the status.
+ */
+bool
+nvme_has_volatile_write_cache(struct nvme_softc *sc)
+{
+       /* sc_identify is filled during attachment */
+       return  ((sc->sc_identify.vwc & NVME_ID_CTRLR_VWC_PRESENT) != 0);
 }
 
 int
@@ -803,7 +818,52 @@
 
        nvme_ccb_put(q, ccb);
 
-       nnc_done(cookie, NULL, lemtoh16(&cqe->flags));
+       nnc_done(cookie, NULL, lemtoh16(&cqe->flags), lemtoh32(&cqe->cdw0));
+}
+
+/*
+ * Get status of volatile write cache. Always asynchronous.
+ */
+int
+nvme_admin_getcache(struct nvme_softc *sc, void *cookie, nvme_nnc_done nnc_done)
+{
+       struct nvme_ccb *ccb;
+       struct nvme_queue *q = sc->sc_admin_q;
+
+       ccb = nvme_ccb_get(q);
+       if (ccb == NULL)
+               return EAGAIN;
+
+       ccb->ccb_done = nvme_getcache_done;
+       ccb->ccb_cookie = cookie;
+
+       /* namespace context */
+       ccb->nnc_flags = 0;
+       ccb->nnc_done = nnc_done;
+
+       nvme_q_submit(sc, q, ccb, nvme_getcache_fill);
+       return 0;
+}
+
+static void
+nvme_getcache_fill(struct nvme_queue *q, struct nvme_ccb *ccb, void *slot)
+{
+       struct nvme_sqe *sqe = slot;
+
+       sqe->opcode = NVM_ADMIN_GET_FEATURES;
+       sqe->cdw10 = NVM_FEATURE_VOLATILE_WRITE_CACHE;
+}
+
+static void
+nvme_getcache_done(struct nvme_queue *q, struct nvme_ccb *ccb,
+    struct nvme_cqe *cqe)
+{
+       void *cookie = ccb->ccb_cookie;
+       nvme_nnc_done nnc_done = ccb->nnc_done;
+
+       nvme_ccb_put(q, ccb);
+
+       nnc_done(cookie, NULL, lemtoh16(&cqe->flags), lemtoh32(&cqe->cdw0));
 }
 
 void



Home | Main Index | Thread Index | Old Index