summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2016-04-14 11:18:33 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2016-04-14 11:18:33 +0000
commita83f0a2f27b718b4ef79f53dcd5eeb5a50f0073a (patch)
tree285c890c0d54feeedd6cc3b24b3671f19bd7f9b7
parent1f16d0bb2330b81223fb626ae8a17335ad06f231 (diff)
provide a shutdown hook that follows the procedure in the docs
-rw-r--r--sys/dev/ic/nvme.c96
-rw-r--r--sys/dev/ic/nvmereg.h11
-rw-r--r--sys/dev/ic/nvmevar.h8
-rw-r--r--sys/dev/pci/nvme_pci.c6
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));
}