diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2016-04-14 11:18:33 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2016-04-14 11:18:33 +0000 |
commit | a83f0a2f27b718b4ef79f53dcd5eeb5a50f0073a (patch) | |
tree | 285c890c0d54feeedd6cc3b24b3671f19bd7f9b7 | |
parent | 1f16d0bb2330b81223fb626ae8a17335ad06f231 (diff) |
provide a shutdown hook that follows the procedure in the docs
-rw-r--r-- | sys/dev/ic/nvme.c | 96 | ||||
-rw-r--r-- | sys/dev/ic/nvmereg.h | 11 | ||||
-rw-r--r-- | sys/dev/ic/nvmevar.h | 8 | ||||
-rw-r--r-- | sys/dev/pci/nvme_pci.c | 6 |
4 files changed, 113 insertions, 8 deletions
diff --git a/sys/dev/ic/nvme.c b/sys/dev/ic/nvme.c index b414df21883..990288365fe 100644 --- a/sys/dev/ic/nvme.c +++ b/sys/dev/ic/nvme.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nvme.c,v 1.45 2016/04/14 10:26:33 dlg Exp $ */ +/* $OpenBSD: nvme.c,v 1.46 2016/04/14 11:18:32 dlg Exp $ */ /* * Copyright (c) 2014 David Gwynne <dlg@openbsd.org> @@ -44,6 +44,7 @@ struct cfdriver nvme_cd = { int nvme_ready(struct nvme_softc *, u_int32_t); int nvme_enable(struct nvme_softc *, u_int); int nvme_disable(struct nvme_softc *); +int nvme_shutdown(struct nvme_softc *); void nvme_version(struct nvme_softc *, u_int32_t); void nvme_dumpregs(struct nvme_softc *); @@ -68,6 +69,7 @@ void nvme_empty_done(struct nvme_softc *, struct nvme_ccb *, struct nvme_queue * nvme_q_alloc(struct nvme_softc *, u_int16_t, u_int, u_int); int nvme_q_create(struct nvme_softc *, struct nvme_queue *); +int nvme_q_delete(struct nvme_softc *, struct nvme_queue *); void nvme_q_submit(struct nvme_softc *, struct nvme_queue *, struct nvme_ccb *, void (*)(struct nvme_softc *, struct nvme_ccb *, void *)); @@ -454,6 +456,59 @@ done: return (rv); } +int +nvme_shutdown(struct nvme_softc *sc) +{ + u_int32_t cc, csts; + int i; + + nvme_write4(sc, NVME_INTMC, 0); + + if (nvme_q_delete(sc, sc->sc_q) != 0) { + printf("%s: unable to delete q, disabling\n", DEVNAME(sc)); + goto disable; + } + + cc = nvme_read4(sc, NVME_CC); + CLR(cc, NVME_CC_SHN_MASK); + SET(cc, NVME_CC_SHN(NVME_CC_SHN_NORMAL)); + nvme_write4(sc, NVME_CC, cc); + + for (i = 0; i < 4000; i++) { + nvme_barrier(sc, 0, sc->sc_ios, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + csts = nvme_read4(sc, NVME_CSTS); + if ((csts & NVME_CSTS_SHST_MASK) == NVME_CSTS_SHST_DONE) + return (0); + + delay(1000); + } + + printf("%s: unable to shudown, disabling\n", DEVNAME(sc)); + +disable: + nvme_disable(sc); + return (0); +} + +int +nvme_activate(struct nvme_softc *sc, int act) +{ + int rv; + + switch (act) { + case DVACT_POWERDOWN: + rv = config_activate_children(&sc->sc_dev, act); + nvme_shutdown(sc); + break; + default: + rv = config_activate_children(&sc->sc_dev, act); + break; + } + + return (rv); +} + void nvme_scsi_cmd(struct scsi_xfer *xs) { @@ -1035,6 +1090,45 @@ fail: return (rv); } +int +nvme_q_delete(struct nvme_softc *sc, struct nvme_queue *q) +{ + struct nvme_sqe_q sqe; + struct nvme_ccb *ccb; + int rv; + + ccb = scsi_io_get(&sc->sc_iopool, 0); + KASSERT(ccb != NULL); + + ccb->ccb_done = nvme_empty_done; + ccb->ccb_cookie = &sqe; + + memset(&sqe, 0, sizeof(sqe)); + sqe.opcode = NVM_ADMIN_DEL_IOSQ; + htolem16(&sqe.qid, q->q_id); + + rv = nvme_poll(sc, sc->sc_admin_q, ccb, nvme_sqe_fill); + if (rv != 0) + goto fail; + + ccb->ccb_done = nvme_empty_done; + ccb->ccb_cookie = &sqe; + + memset(&sqe, 0, sizeof(sqe)); + sqe.opcode = NVM_ADMIN_DEL_IOCQ; + htolem64(&sqe.prp1, NVME_DMA_DVA(q->q_sq_dmamem)); + htolem16(&sqe.qid, q->q_id); + + rv = nvme_poll(sc, sc->sc_admin_q, ccb, nvme_sqe_fill); + if (rv != 0) + goto fail; + +fail: + scsi_io_put(&sc->sc_iopool, ccb); + return (rv); + +} + void nvme_fill_identify(struct nvme_softc *sc, struct nvme_ccb *ccb, void *slot) { diff --git a/sys/dev/ic/nvmereg.h b/sys/dev/ic/nvmereg.h index 2f34c03dbff..fe988d347f8 100644 --- a/sys/dev/ic/nvmereg.h +++ b/sys/dev/ic/nvmereg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: nvmereg.h,v 1.9 2016/04/13 12:49:24 dlg Exp $ */ +/* $OpenBSD: nvmereg.h,v 1.10 2016/04/14 11:18:32 dlg Exp $ */ /* * Copyright (c) 2014 David Gwynne <dlg@openbsd.org> @@ -67,6 +67,10 @@ #define NVME_CC_CSS_NVM 0 #define NVME_CC_EN (1 << 0) #define NVME_CSTS 0x001c /* Controller Status */ +#define NVME_CSTS_SHST_MASK (0x3 << 2) +#define NVME_CSTS_SHST_NONE (0x0 << 2) /* normal operation */ +#define NVME_CSTS_SHST_WAIT (0x1 << 2) /* shutdown processing occurring */ +#define NVME_CSTS_SHST_DONE (0x2 << 2) /* shutdown processing complete */ #define NVME_CSTS_CFS (1 << 1) #define NVME_CSTS_RDY (1 << 0) #define NVME_NSSR 0x0020 /* NVM Subsystem Reset (Optional) */ @@ -150,7 +154,7 @@ struct nvme_sqe_q { #define NVM_SQE_SQ_QPRIO_HI (0x1 << 1) #define NVM_SQE_SQ_QPRIO_MED (0x2 << 1) #define NVM_SQE_SQ_QPRIO_LOW (0x3 << 1) -#define NVM_SQE_CQ_IEN (1 << 1) /* interrupt enable */ +#define NVM_SQE_CQ_IEN (1 << 1) #define NVM_SQE_Q_PC (1 << 0) u_int8_t _reserved3; u_int16_t cqid; /* XXX interrupt vector for cq */ @@ -369,8 +373,7 @@ struct nvm_identify_namespace { u_int8_t mc; /* Metadata Capabilities */ u_int8_t dpc; /* End-to-end Data Protection Capabilities */ - u_int8_t dps; /* End-to-end Data Protection - Type Settings */ + u_int8_t dps; /* End-to-end Data Protection Type Settings */ u_int8_t _reserved1[98]; diff --git a/sys/dev/ic/nvmevar.h b/sys/dev/ic/nvmevar.h index 0094d004bef..f59de44967b 100644 --- a/sys/dev/ic/nvmevar.h +++ b/sys/dev/ic/nvmevar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: nvmevar.h,v 1.7 2016/04/14 00:10:37 dlg Exp $ */ +/* $OpenBSD: nvmevar.h,v 1.8 2016/04/14 11:18:32 dlg Exp $ */ /* * Copyright (c) 2014 David Gwynne <dlg@openbsd.org> @@ -39,6 +39,10 @@ struct nvme_ccb { void (*ccb_done)(struct nvme_softc *sc, struct nvme_ccb *, struct nvme_cqe *); + bus_addr_t ccb_prpl_off; + u_int64_t ccb_prpl_dva; + u_int64_t *ccb_prpl; + u_int16_t ccb_id; }; SIMPLEQ_HEAD(nvme_ccb_list, nvme_ccb); @@ -88,6 +92,7 @@ struct nvme_softc { struct mutex sc_ccb_mtx; struct nvme_ccb *sc_ccbs; struct nvme_ccb_list sc_ccb_list; + struct nvme_dmamem *sc_ccb_prpls; struct scsi_iopool sc_iopool; struct scsi_link sc_link; @@ -95,6 +100,7 @@ struct nvme_softc { }; int nvme_attach(struct nvme_softc *); +int nvme_activate(struct nvme_softc *, int); int nvme_intr(void *); #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname) diff --git a/sys/dev/pci/nvme_pci.c b/sys/dev/pci/nvme_pci.c index 534be1ea03c..1fe72591992 100644 --- a/sys/dev/pci/nvme_pci.c +++ b/sys/dev/pci/nvme_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nvme_pci.c,v 1.2 2014/04/15 10:28:07 dlg Exp $ */ +/* $OpenBSD: nvme_pci.c,v 1.3 2016/04/14 11:18:32 dlg Exp $ */ /* * Copyright (c) 2014 David Gwynne <dlg@openbsd.org> @@ -130,5 +130,7 @@ nvme_pci_detach(struct device *self, int flags) int nvme_pci_activate(struct device *self, int act) { - return (0); + struct nvme_pci_softc *psc = (struct nvme_pci_softc *)self; + + return (nvme_activate(&psc->psc_nvme, act)); } |