Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 20 Jul 2020 00:33:17 +0000 (UTC)
From:      Chuck Tuffli <chuck@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r363354 - stable/12/usr.sbin/bhyve
Message-ID:  <202007200033.06K0XHvm001965@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: chuck
Date: Mon Jul 20 00:33:16 2020
New Revision: 363354
URL: https://svnweb.freebsd.org/changeset/base/363354

Log:
  MFC r362761 bhyve: Add AER support to NVMe emulation

Modified:
  stable/12/usr.sbin/bhyve/pci_nvme.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/usr.sbin/bhyve/pci_nvme.c
==============================================================================
--- stable/12/usr.sbin/bhyve/pci_nvme.c	Mon Jul 20 00:20:55 2020	(r363353)
+++ stable/12/usr.sbin/bhyve/pci_nvme.c	Mon Jul 20 00:33:16 2020	(r363354)
@@ -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);
 }
 
@@ -1448,10 +1558,7 @@ pci_nvme_handle_admin_cmd(struct pci_nvme_softc* sc, u
 			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__);
@@ -2618,6 +2725,8 @@ pci_nvme_init(struct vmctx *ctx, struct pci_devinst *p
 	pci_nvme_init_ctrldata(sc);
 	pci_nvme_init_logpages(sc);
 	pci_nvme_init_features(sc);
+
+	pci_nvme_aer_init(sc);
 
 	pci_nvme_reset(sc);
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202007200033.06K0XHvm001965>