summaryrefslogtreecommitdiff
path: root/usr.sbin/bhyve
diff options
context:
space:
mode:
authorChuck Tuffli <chuck@FreeBSD.org>2020-06-29 00:32:08 +0000
committerChuck Tuffli <chuck@FreeBSD.org>2020-06-29 00:32:08 +0000
commit106329ef33054b93d72eb0219eaff392f53665a3 (patch)
tree8ebc0429c5926f2469a5f23dcf484f6e61c7b4aa /usr.sbin/bhyve
parent8bba8666e2487df4fc2422357d61a479576d51fb (diff)
downloadsrc-test2-106329ef33054b93d72eb0219eaff392f53665a3.tar.gz
src-test2-106329ef33054b93d72eb0219eaff392f53665a3.zip
Notes
Diffstat (limited to 'usr.sbin/bhyve')
-rw-r--r--usr.sbin/bhyve/pci_nvme.c121
1 files changed, 115 insertions, 6 deletions
diff --git a/usr.sbin/bhyve/pci_nvme.c b/usr.sbin/bhyve/pci_nvme.c
index a8034b17dc3e..b151d561f038 100644
--- a/usr.sbin/bhyve/pci_nvme.c
+++ b/usr.sbin/bhyve/pci_nvme.c
@@ -251,6 +251,11 @@ struct nvme_feature_obj {
#define NVME_FID_MAX (NVME_FEAT_ENDURANCE_GROUP_EVENT_CONFIGURATION + 1)
+struct pci_nvme_aer {
+ STAILQ_ENTRY(pci_nvme_aer) link;
+ uint16_t cid; /* Command ID of the submitted AER */
+};
+
struct pci_nvme_softc {
struct pci_devinst *nsc_pi;
@@ -296,6 +301,9 @@ struct pci_nvme_softc {
__uint128_t write_commands;
uint32_t read_dunits_remainder;
uint32_t write_dunits_remainder;
+
+ STAILQ_HEAD(, pci_nvme_aer) aer_list;
+ uint32_t aer_count;
};
@@ -604,6 +612,93 @@ pci_nvme_init_features(struct pci_nvme_softc *sc)
}
static void
+pci_nvme_aer_init(struct pci_nvme_softc *sc)
+{
+
+ STAILQ_INIT(&sc->aer_list);
+ sc->aer_count = 0;
+}
+
+static void
+pci_nvme_aer_destroy(struct pci_nvme_softc *sc)
+{
+ struct pci_nvme_aer *aer = NULL;
+
+ while (!STAILQ_EMPTY(&sc->aer_list)) {
+ aer = STAILQ_FIRST(&sc->aer_list);
+ STAILQ_REMOVE_HEAD(&sc->aer_list, link);
+ free(aer);
+ }
+
+ pci_nvme_aer_init(sc);
+}
+
+static bool
+pci_nvme_aer_available(struct pci_nvme_softc *sc)
+{
+
+ return (!STAILQ_EMPTY(&sc->aer_list));
+}
+
+static bool
+pci_nvme_aer_limit_reached(struct pci_nvme_softc *sc)
+{
+ struct nvme_controller_data *cd = &sc->ctrldata;
+
+ /* AERL is a zero based value while aer_count is one's based */
+ return (sc->aer_count == (cd->aerl + 1));
+}
+
+/*
+ * Add an Async Event Request
+ *
+ * Stores an AER to be returned later if the Controller needs to notify the
+ * host of an event.
+ * Note that while the NVMe spec doesn't require Controllers to return AER's
+ * in order, this implementation does preserve the order.
+ */
+static int
+pci_nvme_aer_add(struct pci_nvme_softc *sc, uint16_t cid)
+{
+ struct pci_nvme_aer *aer = NULL;
+
+ if (pci_nvme_aer_limit_reached(sc))
+ return (-1);
+
+ aer = calloc(1, sizeof(struct pci_nvme_aer));
+ if (aer == NULL)
+ return (-1);
+
+ sc->aer_count++;
+
+ /* Save the Command ID for use in the completion message */
+ aer->cid = cid;
+ STAILQ_INSERT_TAIL(&sc->aer_list, aer, link);
+
+ return (0);
+}
+
+/*
+ * Get an Async Event Request structure
+ *
+ * Returns a pointer to an AER previously submitted by the host or NULL if
+ * no AER's exist. Caller is responsible for freeing the returned struct.
+ */
+static struct pci_nvme_aer *
+pci_nvme_aer_get(struct pci_nvme_softc *sc)
+{
+ struct pci_nvme_aer *aer = NULL;
+
+ aer = STAILQ_FIRST(&sc->aer_list);
+ if (aer != NULL) {
+ STAILQ_REMOVE_HEAD(&sc->aer_list, link);
+ sc->aer_count--;
+ }
+
+ return (aer);
+}
+
+static void
pci_nvme_reset_locked(struct pci_nvme_softc *sc)
{
uint32_t i;
@@ -641,6 +736,8 @@ pci_nvme_reset_locked(struct pci_nvme_softc *sc)
}
sc->num_q_is_set = false;
+
+ pci_nvme_aer_destroy(sc);
}
static void
@@ -1376,13 +1473,26 @@ nvme_opc_async_event_req(struct pci_nvme_softc* sc,
{
DPRINTF("%s async event request 0x%x", __func__, command->cdw11);
+ /* Don't exceed the Async Event Request Limit (AERL). */
+ if (pci_nvme_aer_limit_reached(sc)) {
+ pci_nvme_status_tc(&compl->status, NVME_SCT_COMMAND_SPECIFIC,
+ NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED);
+ return (1);
+ }
+
+ if (pci_nvme_aer_add(sc, command->cid)) {
+ pci_nvme_status_tc(&compl->status, NVME_SCT_GENERIC,
+ NVME_SC_INTERNAL_DEVICE_ERROR);
+ return (1);
+ }
+
/*
- * TODO: raise events when they happen based on the Set Features cmd.
+ * Raise events when they happen based on the Set Features cmd.
* These events happen async, so only set completion successful if
* there is an event reflective of the request to get event.
*/
- pci_nvme_status_tc(&compl->status, NVME_SCT_COMMAND_SPECIFIC,
- NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED);
+ compl->status = NVME_NO_STATUS;
+
return (0);
}
@@ -1449,10 +1559,7 @@ pci_nvme_handle_admin_cmd(struct pci_nvme_softc* sc, uint64_t value)
break;
case NVME_OPC_ASYNC_EVENT_REQUEST:
DPRINTF("%s command ASYNC_EVENT_REQ", __func__);
- /* XXX dont care, unhandled for now
nvme_opc_async_event_req(sc, cmd, &compl);
- */
- compl.status = NVME_NO_STATUS;
break;
case NVME_OPC_FORMAT_NVM:
DPRINTF("%s command FORMAT_NVM", __func__);
@@ -2620,6 +2727,8 @@ pci_nvme_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
pci_nvme_init_logpages(sc);
pci_nvme_init_features(sc);
+ pci_nvme_aer_init(sc);
+
pci_nvme_reset(sc);
pci_lintr_request(pi);