diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index dcfe8d98c..a6881dedd 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -2895,6 +2895,25 @@ struct spdk_nvme_transport_ops { void (*admin_qpair_abort_aers)(struct spdk_nvme_qpair *qpair); }; +/** + * Register the operations for a given transport type. + * + * This function should be invoked by referencing the macro + * SPDK_NVME_TRANSPORT_REGISTER macro in the transport's .c file. + * + * \param ops The operations associated with an NVMe-oF transport. + */ +void spdk_nvme_transport_register(const struct spdk_nvme_transport_ops *ops); + +/* + * Macro used to register new transports. + */ +#define SPDK_NVME_TRANSPORT_REGISTER(name, transport_ops) \ +static void __attribute__((constructor)) spdk_nvme_transport_register_##name(void) \ +{ \ + spdk_nvme_transport_register(transport_ops); \ +}\ + #ifdef __cplusplus } #endif diff --git a/lib/nvme/nvme_transport.c b/lib/nvme/nvme_transport.c index 18c146c94..161fd04a4 100644 --- a/lib/nvme/nvme_transport.c +++ b/lib/nvme/nvme_transport.c @@ -36,6 +36,7 @@ */ #include "nvme_internal.h" +#include "spdk/queue.h" #ifdef DEBUG static __attribute__((noreturn)) void @@ -76,6 +77,9 @@ nvme_transport_unknown(enum spdk_nvme_transport_type trtype) SPDK_UNREACHABLE(); \ } while (0) +TAILQ_HEAD(nvme_transport_list, nvme_transport) g_spdk_nvme_transports = + TAILQ_HEAD_INITIALIZER(g_spdk_nvme_transports); + bool spdk_nvme_transport_available(enum spdk_nvme_transport_type trtype) { @@ -105,6 +109,30 @@ spdk_nvme_transport_available_by_name(const char *transport_name) return spdk_nvme_transport_available(trtype); } +void +spdk_nvme_transport_register(const struct spdk_nvme_transport_ops *ops) +{ + struct nvme_transport *registered_transport, *new_transport; + + TAILQ_FOREACH(registered_transport, &g_spdk_nvme_transports, link) { + if (strcasecmp(ops->name, registered_transport->ops.name) == 0) { + SPDK_ERRLOG("Double registering NVMe transport %s is prohibited.\n", ops->name); + assert(false); + return; + } + } + + new_transport = calloc(1, sizeof(*new_transport)); + if (new_transport == NULL) { + SPDK_ERRLOG("Unable to allocate memory to register new NVMe transport.\n"); + assert(false); + return; + } + + new_transport->ops = *ops; + TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, new_transport, link); +} + struct spdk_nvme_ctrlr *nvme_transport_ctrlr_construct(const struct spdk_nvme_transport_id *trid, const struct spdk_nvme_ctrlr_opts *opts, void *devhandle)