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