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);