Module Name:    src
Committed By:   jdolecek
Date:           Sat Dec  1 15:07:58 UTC 2018

Modified Files:
        src/sys/dev/ic: ld_nvme.c nvme.c nvmereg.h nvmevar.h

Log Message:
support DIOCSCACHE + DKCACHE_WRITE if volatile write cache is present

fix the Get Features call for DIOCGCACHE to actually retrieve the current
value properly


To generate a diff of this commit:
cvs rdiff -u -r1.20 -r1.21 src/sys/dev/ic/ld_nvme.c
cvs rdiff -u -r1.40 -r1.41 src/sys/dev/ic/nvme.c
cvs rdiff -u -r1.11 -r1.12 src/sys/dev/ic/nvmereg.h
cvs rdiff -u -r1.17 -r1.18 src/sys/dev/ic/nvmevar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ic/ld_nvme.c
diff -u src/sys/dev/ic/ld_nvme.c:1.20 src/sys/dev/ic/ld_nvme.c:1.21
--- src/sys/dev/ic/ld_nvme.c:1.20	Wed Apr 18 10:11:45 2018
+++ src/sys/dev/ic/ld_nvme.c	Sat Dec  1 15:07:58 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ld_nvme.c,v 1.20 2018/04/18 10:11:45 nonaka Exp $	*/
+/*	$NetBSD: ld_nvme.c,v 1.21 2018/12/01 15:07:58 jdolecek Exp $	*/
 
 /*-
  * Copyright (C) 2016 NONAKA Kimihiro <non...@netbsd.org>
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_nvme.c,v 1.20 2018/04/18 10:11:45 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_nvme.c,v 1.21 2018/12/01 15:07:58 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -200,6 +200,14 @@ ld_nvme_getcache(struct ld_softc *ld, in
 }
 
 static int
+ld_nvme_setcache(struct ld_softc *ld, int addr)
+{
+	struct ld_nvme_softc *sc = device_private(ld->sc_dv);
+
+	return nvme_admin_setcache(sc->sc_nvme, addr);
+}
+
+static int
 ld_nvme_ioctl(struct ld_softc *ld, u_long cmd, void *addr, int32_t flag, bool poll)
 {
 	int error;
@@ -213,6 +221,10 @@ ld_nvme_ioctl(struct ld_softc *ld, u_lon
 		error = ld_nvme_getcache(ld, (int *)addr);
 		break;
 
+	case DIOCSCACHE:
+		error = ld_nvme_setcache(ld, *(int *)addr);
+		break;
+
 	default:
 		error = EPASSTHROUGH;
 		break;

Index: src/sys/dev/ic/nvme.c
diff -u src/sys/dev/ic/nvme.c:1.40 src/sys/dev/ic/nvme.c:1.41
--- src/sys/dev/ic/nvme.c:1.40	Sat Dec  1 08:03:44 2018
+++ src/sys/dev/ic/nvme.c	Sat Dec  1 15:07:58 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvme.c,v 1.40 2018/12/01 08:03:44 jdolecek Exp $	*/
+/*	$NetBSD: nvme.c,v 1.41 2018/12/01 15:07:58 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.40 2018/12/01 08:03:44 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvme.c,v 1.41 2018/12/01 15:07:58 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -902,6 +902,7 @@ nvme_getcache_fill(struct nvme_queue *q,
 
 	sqe->opcode = NVM_ADMIN_GET_FEATURES;
 	htolem32(&sqe->cdw10, NVM_FEATURE_VOLATILE_WRITE_CACHE);
+	htolem32(&sqe->cdw11, NVM_VOLATILE_WRITE_CACHE_WCE);
 }
 
 static void
@@ -922,7 +923,7 @@ nvme_getcache_done(struct nvme_queue *q,
 		 */ 
 		result = DKCACHE_FUA;
 
-		if (cdw0 & NVME_CQE_CDW0_VWC_WCE)
+		if (cdw0 & NVM_VOLATILE_WRITE_CACHE_WCE)
 			result |= DKCACHE_WRITE;
 
 		/*
@@ -930,6 +931,14 @@ nvme_getcache_done(struct nvme_queue *q,
 		 * settable.
 		 */
 		result |= DKCACHE_WCHANGE;
+
+		/*
+		 * ONCS field indicates whether the optional SAVE is also
+		 * supported for Set Features. According to spec v1.3,
+		 * Volatile Write Cache however doesn't support persistency
+		 * across power cycle/reset.
+		 */
+
 	} else {
 		result = -1;
 	}
@@ -939,6 +948,95 @@ nvme_getcache_done(struct nvme_queue *q,
 	nvme_ccb_put(q, ccb);
 }
 
+struct nvme_setcache_state {
+	int dkcache;
+	int result;
+};
+
+static bool
+nvme_setcache_finished(void *xc)
+{
+	struct nvme_setcache_state *st = xc;
+
+	return (st->result != 0);
+}
+
+static void
+nvme_setcache_fill(struct nvme_queue *q, struct nvme_ccb *ccb, void *slot)
+{
+	struct nvme_sqe *sqe = slot;
+	struct nvme_setcache_state *st = ccb->ccb_cookie;
+
+	sqe->opcode = NVM_ADMIN_SET_FEATURES;
+	htolem32(&sqe->cdw10, NVM_FEATURE_VOLATILE_WRITE_CACHE);
+	if (st->dkcache & DKCACHE_WRITE)
+		htolem32(&sqe->cdw11, NVM_VOLATILE_WRITE_CACHE_WCE);
+}
+
+static void
+nvme_setcache_done(struct nvme_queue *q, struct nvme_ccb *ccb,
+    struct nvme_cqe *cqe)
+{
+	struct nvme_setcache_state *st = ccb->ccb_cookie;
+	uint16_t status = NVME_CQE_SC(lemtoh16(&cqe->flags));
+
+	if (status == NVME_CQE_SC_SUCCESS) {
+		st->result = 1;
+	} else {
+		st->result = -1;
+	}
+
+	nvme_ccb_put(q, ccb);
+}
+
+/*
+ * Set status of volatile write cache. Always asynchronous.
+ */
+int
+nvme_admin_setcache(struct nvme_softc *sc, int dkcache)
+{
+	struct nvme_ccb *ccb;
+	struct nvme_queue *q = sc->sc_admin_q;
+	int error;
+	struct nvme_setcache_state st;
+
+	if (!nvme_has_volatile_write_cache(sc)) {
+		/* cache simply not present */
+		return EOPNOTSUPP;
+	}
+
+	if (dkcache & ~(DKCACHE_WRITE)) {
+		/* unsupported parameters */
+		return EOPNOTSUPP;
+	}
+
+	ccb = nvme_ccb_get(q, true);
+	KASSERT(ccb != NULL);
+
+	memset(&st, 0, sizeof(st));
+	st.dkcache = dkcache;
+
+	ccb->ccb_done = nvme_setcache_done;
+	ccb->ccb_cookie = &st;
+
+	/* namespace context */
+	ccb->nnc_flags = 0;
+	ccb->nnc_done = NULL;
+
+	nvme_q_submit(sc, q, ccb, nvme_setcache_fill);
+
+	/* wait for completion */
+	nvme_q_wait_complete(sc, q, nvme_setcache_finished, &st);
+	KASSERT(st.result != 0);
+
+	if (st.result > 0)
+		error = 0;
+	else
+		error = EINVAL;
+
+	return error;
+}
+
 void
 nvme_ns_free(struct nvme_softc *sc, uint16_t nsid)
 {

Index: src/sys/dev/ic/nvmereg.h
diff -u src/sys/dev/ic/nvmereg.h:1.11 src/sys/dev/ic/nvmereg.h:1.12
--- src/sys/dev/ic/nvmereg.h:1.11	Wed Apr 18 10:10:26 2018
+++ src/sys/dev/ic/nvmereg.h	Sat Dec  1 15:07:58 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvmereg.h,v 1.11 2018/04/18 10:10:26 nonaka Exp $	*/
+/*	$NetBSD: nvmereg.h,v 1.12 2018/12/01 15:07:58 jdolecek Exp $	*/
 /*	$OpenBSD: nvmereg.h,v 1.10 2016/04/14 11:18:32 dlg Exp $ */
 
 /*
@@ -230,7 +230,6 @@ NVME_CTASSERT(sizeof(struct nvme_sqe_io)
 
 struct nvme_cqe {
 	uint32_t	cdw0;
-#define NVME_CQE_CDW0_VWC_WCE	__BIT(1)	/* Volatile Write Cache Enable */
 
 	uint32_t	_reserved;
 
@@ -369,6 +368,10 @@ NVME_CTASSERT(sizeof(struct nvme_cqe) ==
 /* 0x84-0xBF - command set specific (reserved) */
 /* 0xC0-0xFF - vendor specific */
 
+#define NVM_SET_FEATURES_SV		__BIT(31)	/* Persist */
+
+#define NVM_VOLATILE_WRITE_CACHE_WCE	__BIT(0) 	/* Write Cache Enable */
+
 /* Power State Descriptor Data */
 struct nvm_identify_psd {
 	uint16_t	mp;		/* Max Power */
@@ -514,8 +517,9 @@ struct nvm_identify_controller {
 	uint32_t	nn;		/* Number of Namespaces */
 
 	uint16_t	oncs;		/* Optional NVM Command Support */
+#define	NVME_ID_CTRLR_ONCS_TIMESTAMP	__BIT(6)
 #define	NVME_ID_CTRLR_ONCS_RESERVATION	__BIT(5)
-#define	NVME_ID_CTRLR_ONCS_SET_FEATURES	__BIT(4)
+#define	NVME_ID_CTRLR_ONCS_SAVE		__BIT(4)
 #define	NVME_ID_CTRLR_ONCS_WRITE_ZERO	__BIT(3)
 #define	NVME_ID_CTRLR_ONCS_DSM		__BIT(2)
 #define	NVME_ID_CTRLR_ONCS_WRITE_UNC	__BIT(1)

Index: src/sys/dev/ic/nvmevar.h
diff -u src/sys/dev/ic/nvmevar.h:1.17 src/sys/dev/ic/nvmevar.h:1.18
--- src/sys/dev/ic/nvmevar.h:1.17	Thu Apr 19 21:50:08 2018
+++ src/sys/dev/ic/nvmevar.h	Sat Dec  1 15:07:58 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvmevar.h,v 1.17 2018/04/19 21:50:08 christos Exp $	*/
+/*	$NetBSD: nvmevar.h,v 1.18 2018/12/01 15:07:58 jdolecek Exp $	*/
 /*	$OpenBSD: nvmevar.h,v 1.8 2016/04/14 11:18:32 dlg Exp $ */
 
 /*
@@ -186,3 +186,4 @@ int	nvme_ns_dobio(struct nvme_softc *, u
     struct buf *, void *, size_t, int, daddr_t, int, nvme_nnc_done);
 int	nvme_ns_sync(struct nvme_softc *, uint16_t, int);
 int	nvme_admin_getcache(struct nvme_softc *, int *);
+int	nvme_admin_setcache(struct nvme_softc *, int);

Reply via email to