Page MenuHomeFreeBSD

D32952.1776863428.diff
No OneTemporary

Size
8 KB
Referenced Files
None
Subscribers
None

D32952.1776863428.diff

Index: usr.sbin/bhyve/pci_nvme.c
===================================================================
--- usr.sbin/bhyve/pci_nvme.c
+++ usr.sbin/bhyve/pci_nvme.c
@@ -65,6 +65,7 @@
#include <assert.h>
#include <pthread.h>
+#include <pthread_np.h>
#include <semaphore.h>
#include <stdbool.h>
#include <stddef.h>
@@ -250,11 +251,39 @@
#define NVME_FID_MAX (NVME_FEAT_ENDURANCE_GROUP_EVENT_CONFIGURATION + 1)
+typedef enum {
+ PCI_NVME_AE_TYPE_ERROR = 0,
+ PCI_NVME_AE_TYPE_SMART,
+ PCI_NVME_AE_TYPE_NOTICE,
+ PCI_NVME_AE_TYPE_IO_CMD = 6,
+ PCI_NVME_AE_TYPE_VENDOR = 7,
+ PCI_NVME_AE_TYPE_MAX /* Must be last */
+} pci_nvme_async_type;
+
+/* Asynchronous Event Requests */
struct pci_nvme_aer {
STAILQ_ENTRY(pci_nvme_aer) link;
uint16_t cid; /* Command ID of the submitted AER */
};
+typedef enum {
+ PCI_NVME_AE_INFO_NS_ATTR_CHANGED = 0,
+ PCI_NVME_AE_INFO_FW_ACTIVATION,
+ PCI_NVME_AE_INFO_TELEMETRY_CHANGE,
+ PCI_NVME_AE_INFO_ANA_CHANGE,
+ PCI_NVME_AE_INFO_PREDICT_LATENCY_CHANGE,
+ PCI_NVME_AE_INFO_LBA_STATUS_ALERT,
+ PCI_NVME_AE_INFO_ENDURANCE_GROUP_CHANGE,
+ PCI_NVME_AE_INFO_MAX,
+} pci_nvme_async_info;
+
+/* Asynchronous Event Notifications */
+struct pci_nvme_aen {
+ pci_nvme_async_type atype;
+ uint32_t event_data;
+ bool posted;
+};
+
struct pci_nvme_softc {
struct pci_devinst *nsc_pi;
@@ -302,10 +331,21 @@
uint32_t write_dunits_remainder;
STAILQ_HEAD(, pci_nvme_aer) aer_list;
+ pthread_mutex_t aer_mtx;
uint32_t aer_count;
+ struct pci_nvme_aen aen[PCI_NVME_AE_TYPE_MAX];
+ pthread_t aen_tid;
+ pthread_mutex_t aen_mtx;
+ pthread_cond_t aen_cond;
};
+static void pci_nvme_cq_update(struct pci_nvme_softc *sc,
+ struct nvme_completion_queue *cq,
+ uint32_t cdw0,
+ uint16_t cid,
+ uint16_t sqid,
+ uint16_t status);
static struct pci_nvme_ioreq *pci_nvme_get_ioreq(struct pci_nvme_softc *);
static void pci_nvme_release_ioreq(struct pci_nvme_softc *, struct pci_nvme_ioreq *);
static void pci_nvme_io_done(struct blockif_req *, int);
@@ -360,6 +400,8 @@
struct nvme_command *,
struct nvme_completion *);
+static void *aen_thr(void *arg);
+
static __inline void
cpywithpad(char *dst, size_t dst_size, const char *src, char pad)
{
@@ -630,32 +672,42 @@
}
static void
-pci_nvme_aer_init(struct pci_nvme_softc *sc)
+pci_nvme_aer_reset(struct pci_nvme_softc *sc)
{
STAILQ_INIT(&sc->aer_list);
sc->aer_count = 0;
}
+static void
+pci_nvme_aer_init(struct pci_nvme_softc *sc)
+{
+
+ pthread_mutex_init(&sc->aer_mtx, NULL);
+ pci_nvme_aer_reset(sc);
+}
+
static void
pci_nvme_aer_destroy(struct pci_nvme_softc *sc)
{
struct pci_nvme_aer *aer = NULL;
+ pthread_mutex_lock(&sc->aer_mtx);
while (!STAILQ_EMPTY(&sc->aer_list)) {
aer = STAILQ_FIRST(&sc->aer_list);
STAILQ_REMOVE_HEAD(&sc->aer_list, link);
free(aer);
}
+ pthread_mutex_unlock(&sc->aer_mtx);
- pci_nvme_aer_init(sc);
+ pci_nvme_aer_reset(sc);
}
static bool
pci_nvme_aer_available(struct pci_nvme_softc *sc)
{
- return (!STAILQ_EMPTY(&sc->aer_list));
+ return (sc->aer_count != 0);
}
static bool
@@ -687,11 +739,13 @@
if (aer == NULL)
return (-1);
- sc->aer_count++;
-
/* Save the Command ID for use in the completion message */
aer->cid = cid;
+
+ pthread_mutex_lock(&sc->aer_mtx);
+ sc->aer_count++;
STAILQ_INSERT_TAIL(&sc->aer_list, aer, link);
+ pthread_mutex_unlock(&sc->aer_mtx);
return (0);
}
@@ -707,15 +761,196 @@
{
struct pci_nvme_aer *aer = NULL;
+ pthread_mutex_lock(&sc->aer_mtx);
aer = STAILQ_FIRST(&sc->aer_list);
if (aer != NULL) {
STAILQ_REMOVE_HEAD(&sc->aer_list, link);
sc->aer_count--;
}
+ pthread_mutex_unlock(&sc->aer_mtx);
return (aer);
}
+static void
+pci_nvme_aen_reset(struct pci_nvme_softc *sc)
+{
+ uint32_t atype;
+
+ memset(sc->aen, 0, PCI_NVME_AE_TYPE_MAX * sizeof(struct pci_nvme_aen));
+
+ for (atype = 0; atype < PCI_NVME_AE_TYPE_MAX; atype++) {
+ sc->aen[atype].atype = atype;
+ }
+}
+
+static void
+pci_nvme_aen_init(struct pci_nvme_softc *sc)
+{
+ char nstr[80];
+
+ pci_nvme_aen_reset(sc);
+
+ pthread_mutex_init(&sc->aen_mtx, NULL);
+ pthread_create(&sc->aen_tid, NULL, aen_thr, sc);
+ snprintf(nstr, sizeof(nstr), "nvme-aen-%d:%d", sc->nsc_pi->pi_slot,
+ sc->nsc_pi->pi_func);
+ pthread_set_name_np(sc->aen_tid, nstr);
+}
+
+static void
+pci_nvme_aen_destroy(struct pci_nvme_softc *sc)
+{
+
+ pci_nvme_aen_reset(sc);
+}
+
+/*
+ * Post an Asynchronous Event Notification
+ */
+static int32_t
+pci_nvme_aen_post(struct pci_nvme_softc *sc, pci_nvme_async_type atype,
+ uint32_t event_data)
+{
+ struct pci_nvme_aen *aen;
+
+ if (atype >= PCI_NVME_AE_TYPE_MAX) {
+ return(EINVAL);
+ }
+
+ pthread_mutex_lock(&sc->aen_mtx);
+ aen = &sc->aen[atype];
+
+ /* Has the controller already posted an event of this type? */
+ if (aen->posted) {
+ pthread_mutex_unlock(&sc->aen_mtx);
+ return(EALREADY);
+ }
+
+ aen->event_data = event_data;
+ aen->posted = true;
+ pthread_mutex_unlock(&sc->aen_mtx);
+
+ pthread_cond_signal(&sc->aen_cond);
+
+ return(0);
+}
+
+static void
+pci_nvme_aen_process(struct pci_nvme_softc *sc)
+{
+ struct pci_nvme_aer *aer;
+ struct pci_nvme_aen *aen;
+ pci_nvme_async_type atype;
+ uint32_t mask;
+ uint16_t status;
+ uint8_t lid;
+
+ assert(pthread_mutex_isowned_np(&sc->aen_mtx));
+ for (atype = 0; atype < PCI_NVME_AE_TYPE_MAX; atype++) {
+ aen = &sc->aen[atype];
+ /* Previous iterations may have depleted the available AER's */
+ if (!pci_nvme_aer_available(sc)) {
+ break;
+ }
+
+ if (!aen->posted) {
+ continue;
+ }
+
+ status = NVME_SC_SUCCESS;
+
+ /* Is the event masked? */
+ mask =
+ sc->feat[NVME_FEAT_ASYNC_EVENT_CONFIGURATION].cdw11;
+
+ switch (atype) {
+ case PCI_NVME_AE_TYPE_ERROR:
+ lid = NVME_LOG_ERROR;
+ break;
+ case PCI_NVME_AE_TYPE_SMART:
+ mask &= 0xff;
+ if ((mask & aen->event_data) == 0)
+ continue;
+ lid = NVME_LOG_HEALTH_INFORMATION;
+ break;
+ case PCI_NVME_AE_TYPE_NOTICE:
+ if (aen->event_data >= PCI_NVME_AE_INFO_MAX) {
+ EPRINTLN("%s unknown AEN notice type %u",
+ __func__, aen->event_data);
+ status = NVME_SC_INTERNAL_DEVICE_ERROR;
+ break;
+ }
+ mask >>= 8;
+ if (((1 << aen->event_data) & mask) == 0)
+ continue;
+ switch (aen->event_data) {
+ case PCI_NVME_AE_INFO_NS_ATTR_CHANGED:
+ lid = NVME_LOG_CHANGED_NAMESPACE;
+ break;
+ case PCI_NVME_AE_INFO_FW_ACTIVATION:
+ lid = NVME_LOG_FIRMWARE_SLOT;
+ break;
+ case PCI_NVME_AE_INFO_TELEMETRY_CHANGE:
+ lid = NVME_LOG_TELEMETRY_CONTROLLER_INITIATED;
+ break;
+ case PCI_NVME_AE_INFO_ANA_CHANGE:
+ lid = NVME_LOG_ASYMMETRIC_NAMESPAVE_ACCESS; //TODO spelling
+ break;
+ case PCI_NVME_AE_INFO_PREDICT_LATENCY_CHANGE:
+ lid = NVME_LOG_PREDICTABLE_LATENCY_EVENT_AGGREGATE;
+ break;
+ case PCI_NVME_AE_INFO_LBA_STATUS_ALERT:
+ lid = NVME_LOG_LBA_STATUS_INFORMATION;
+ break;
+ case PCI_NVME_AE_INFO_ENDURANCE_GROUP_CHANGE:
+ lid = NVME_LOG_ENDURANCE_GROUP_EVENT_AGGREGATE;
+ break;
+ default:
+ lid = 0;
+ }
+ break;
+ default:
+ /* bad type?!? */
+ EPRINTLN("%s unknown AEN type %u", __func__, atype);
+ status = NVME_SC_INTERNAL_DEVICE_ERROR;
+ break;
+ }
+
+ aer = pci_nvme_aer_get(sc);
+ assert(aer != NULL);
+
+ pci_nvme_cq_update(sc, &sc->compl_queues[0],
+ (lid << 16) | (aen->event_data << 8) | atype, /* cdw0 */
+ aer->cid,
+ 0, /* SQID */
+ status);
+
+ aen->event_data = 0;
+ aen->posted = false;
+
+ pci_generate_msix(sc->nsc_pi, 0);
+ }
+}
+
+static void *
+aen_thr(void *arg)
+{
+ struct pci_nvme_softc *sc;
+
+ sc = arg;
+
+ pthread_mutex_lock(&sc->aen_mtx);
+ for (;;) {
+ pci_nvme_aen_process(sc);
+ pthread_cond_wait(&sc->aen_cond, &sc->aen_mtx);
+ }
+ pthread_mutex_unlock(&sc->aen_mtx);
+
+ pthread_exit(NULL);
+ return (NULL);
+}
+
static void
pci_nvme_reset_locked(struct pci_nvme_softc *sc)
{
@@ -756,6 +991,7 @@
sc->num_q_is_set = false;
pci_nvme_aer_destroy(sc);
+ pci_nvme_aen_destroy(sc);
}
static void
@@ -2025,6 +2261,7 @@
lba = ((uint64_t)cmd->cdw11 << 32) | cmd->cdw10;
nblocks = (cmd->cdw12 & 0xFFFF) + 1;
+
if (pci_nvme_out_of_range(nvstore, lba, nblocks)) {
WPRINTF("%s command would exceed LBA range", __func__);
pci_nvme_status_genc(status, NVME_SC_LBA_OUT_OF_RANGE);
@@ -2789,6 +3026,7 @@
pci_nvme_init_features(sc);
pci_nvme_aer_init(sc);
+ pci_nvme_aen_init(sc);
pci_nvme_reset(sc);

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 22, 1:10 PM (20 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28407936
Default Alt Text
D32952.1776863428.diff (8 KB)

Event Timeline