diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index b68062917..e74ab1bc1 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -371,6 +371,35 @@ int spdk_nvme_probe(const struct spdk_nvme_transport_id *trid, spdk_nvme_attach_cb attach_cb, spdk_nvme_remove_cb remove_cb); +/** + * \brief Connect the NVMe driver to the device located at the given transport ID. + * + * \param trid The transport ID indicating which device to connect. If the trtype is PCIe, this will + * connect the local PCIe bus. If the trtype is RDMA, the traddr and trsvcid must point at the + * location of an NVMe-oF service. + * \param opts NVMe controller initialization options. Default values will be used if the user does + * not specify the options. The controller may not support all requested parameters. + * \param opts_size Must be set to sizeof(struct spdk_nvme_ctrlr_opts), or 0 if opts is NULL. + * + * \return pointer to the connected NVMe controller or NULL if there is any failure. + * + * This function is not thread safe and should only be called from one thread at a time while no + * other threads are actively using this NVMe device. + * + * If called from a secondary process, only the device that has been attached to the userspace driver + * in the primary process will be connected. + * + * If connecting to multiple controllers, it is suggested to use spdk_nvme_probe() and filter the + * requested controllers with the probe callback. For PCIe controllers, spdk_nvme_probe() will be + * more efficient since the controller resets will happen in parallel. + * + * To stop using the the controller and release its associated resources, + * call \ref spdk_nvme_detach with the spdk_nvme_ctrlr instance returned by this function. + */ +struct spdk_nvme_ctrlr *spdk_nvme_connect(const struct spdk_nvme_transport_id *trid, + const struct spdk_nvme_ctrlr_opts *opts, + size_t opts_size); + /** * \brief Detaches specified device returned by \ref spdk_nvme_probe()'s attach_cb from the NVMe driver. * diff --git a/lib/nvme/nvme.c b/lib/nvme/nvme.c index c6e2d3b53..af449e470 100644 --- a/lib/nvme/nvme.c +++ b/lib/nvme/nvme.c @@ -322,7 +322,7 @@ nvme_ctrlr_probe(const struct spdk_nvme_transport_id *trid, void *devhandle, spdk_nvme_ctrlr_get_default_ctrlr_opts(&opts, sizeof(opts)); - if (probe_cb(cb_ctx, trid, &opts)) { + if (!probe_cb || probe_cb(cb_ctx, trid, &opts)) { ctrlr = nvme_transport_ctrlr_construct(trid, &opts, devhandle); if (ctrlr == NULL) { SPDK_ERRLOG("Failed to construct NVMe controller\n"); @@ -386,9 +386,11 @@ nvme_init_controllers(void *cb_ctx, spdk_nvme_attach_cb attach_cb) * Unlock while calling attach_cb() so the user can call other functions * that may take the driver lock, like nvme_detach(). */ - nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock); - attach_cb(cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts); - nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock); + if (attach_cb) { + nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock); + attach_cb(cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts); + nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock); + } break; } @@ -401,25 +403,36 @@ nvme_init_controllers(void *cb_ctx, spdk_nvme_attach_cb attach_cb) return rc; } -int -spdk_nvme_probe(const struct spdk_nvme_transport_id *trid, void *cb_ctx, - spdk_nvme_probe_cb probe_cb, spdk_nvme_attach_cb attach_cb, - spdk_nvme_remove_cb remove_cb) +/* This function must not be called while holding g_spdk_nvme_driver->lock */ +static struct spdk_nvme_ctrlr * +spdk_nvme_get_ctrlr_by_trid(const struct spdk_nvme_transport_id *trid) +{ + struct spdk_nvme_ctrlr *ctrlr = NULL; + bool found = false; + + nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock); + + TAILQ_FOREACH(ctrlr, &g_spdk_nvme_driver->attached_ctrlrs, tailq) { + if (spdk_nvme_transport_id_compare(&ctrlr->trid, trid) == 0) { + found = true; + break; + } + } + + nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock); + + return (found == true) ? ctrlr : NULL; +} + +/* This function must only be called while holding g_spdk_nvme_driver->lock */ +static int +spdk_nvme_probe_internal(const struct spdk_nvme_transport_id *trid, void *cb_ctx, + spdk_nvme_probe_cb probe_cb, spdk_nvme_attach_cb attach_cb, + spdk_nvme_remove_cb remove_cb, struct spdk_nvme_ctrlr **connected_ctrlr) { int rc; struct spdk_nvme_ctrlr *ctrlr; - struct spdk_nvme_transport_id trid_pcie; - - rc = nvme_driver_init(); - if (rc != 0) { - return rc; - } - - if (trid == NULL) { - memset(&trid_pcie, 0, sizeof(trid_pcie)); - trid_pcie.trtype = SPDK_NVME_TRANSPORT_PCIE; - trid = &trid_pcie; - } + bool direct_connect = (connected_ctrlr != NULL); if (!spdk_nvme_transport_available(trid->trtype)) { SPDK_ERRLOG("NVMe trtype %u not available\n", trid->trtype); @@ -428,7 +441,7 @@ spdk_nvme_probe(const struct spdk_nvme_transport_id *trid, void *cb_ctx, nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock); - nvme_transport_ctrlr_scan(trid, cb_ctx, probe_cb, remove_cb); + nvme_transport_ctrlr_scan(trid, cb_ctx, probe_cb, remove_cb, direct_connect); /* * The RDMA trtype will always construct the ctrlr and go through the @@ -448,13 +461,18 @@ spdk_nvme_probe(const struct spdk_nvme_transport_id *trid, void *cb_ctx, * Unlock while calling attach_cb() so the user can call other functions * that may take the driver lock, like nvme_detach(). */ - nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock); - attach_cb(cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts); - nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock); + if (attach_cb) { + nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock); + attach_cb(cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts); + nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock); + } } nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock); - return 0; + + rc = 0; + + goto exit; } nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock); @@ -465,9 +483,83 @@ spdk_nvme_probe(const struct spdk_nvme_transport_id *trid, void *cb_ctx, rc = nvme_init_controllers(cb_ctx, attach_cb); +exit: + if (connected_ctrlr) { + *connected_ctrlr = spdk_nvme_get_ctrlr_by_trid(trid); + } + return rc; } +int +spdk_nvme_probe(const struct spdk_nvme_transport_id *trid, void *cb_ctx, + spdk_nvme_probe_cb probe_cb, spdk_nvme_attach_cb attach_cb, + spdk_nvme_remove_cb remove_cb) +{ + int rc; + struct spdk_nvme_transport_id trid_pcie; + + rc = nvme_driver_init(); + if (rc != 0) { + return rc; + } + + if (trid == NULL) { + memset(&trid_pcie, 0, sizeof(trid_pcie)); + trid_pcie.trtype = SPDK_NVME_TRANSPORT_PCIE; + trid = &trid_pcie; + } + + return spdk_nvme_probe_internal(trid, cb_ctx, probe_cb, attach_cb, remove_cb, NULL); +} + +static bool +spdk_nvme_connect_probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid, + struct spdk_nvme_ctrlr_opts *opts) +{ + struct spdk_nvme_ctrlr_connect_opts *requested_opts = cb_ctx; + + assert(requested_opts->opts); + + assert(requested_opts->opts_size != 0); + + memcpy(opts, requested_opts->opts, spdk_min(sizeof(*opts), requested_opts->opts_size)); + + return true; +} + +struct spdk_nvme_ctrlr * +spdk_nvme_connect(const struct spdk_nvme_transport_id *trid, + const struct spdk_nvme_ctrlr_opts *opts, size_t opts_size) +{ + int rc; + struct spdk_nvme_ctrlr_connect_opts connect_opts = {}; + struct spdk_nvme_ctrlr_connect_opts *user_connect_opts = NULL; + struct spdk_nvme_ctrlr *ctrlr = NULL; + spdk_nvme_probe_cb probe_cb = NULL; + + if (trid == NULL) { + SPDK_ERRLOG("No transport ID specified\n"); + return NULL; + } + + rc = nvme_driver_init(); + if (rc != 0) { + return NULL; + } + + if (opts && opts_size > 0) { + connect_opts.opts = opts; + connect_opts.opts_size = opts_size; + user_connect_opts = &connect_opts; + probe_cb = spdk_nvme_connect_probe_cb; + } + + spdk_nvme_probe_internal(trid, user_connect_opts, probe_cb, NULL, NULL, &ctrlr); + + return ctrlr; +} + int spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str) { diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c index 311860a62..e2e5cd494 100644 --- a/lib/nvme/nvme_ctrlr.c +++ b/lib/nvme/nvme_ctrlr.c @@ -1459,6 +1459,10 @@ nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr) } break; + case NVME_CTRLR_STATE_READY: + SPDK_DEBUGLOG(SPDK_TRACE_NVME, "Ctrlr already in ready state\n"); + return 0; + default: assert(0); nvme_ctrlr_fail(ctrlr, false); diff --git a/lib/nvme/nvme_internal.h b/lib/nvme/nvme_internal.h index d778a5355..e36c0bc92 100644 --- a/lib/nvme/nvme_internal.h +++ b/lib/nvme/nvme_internal.h @@ -473,6 +473,14 @@ struct nvme_driver { extern struct nvme_driver *g_spdk_nvme_driver; +/* + * Used for the spdk_nvme_connect() public API to save user specified opts. + */ +struct spdk_nvme_ctrlr_connect_opts { + const struct spdk_nvme_ctrlr_opts *opts; + size_t opts_size; +}; + #define nvme_delay usleep static inline bool @@ -599,7 +607,7 @@ void nvme_qpair_print_completion(struct spdk_nvme_qpair *qpair, struct spdk_nvme struct spdk_nvme_ctrlr *nvme_ ## name ## _ctrlr_construct(const struct spdk_nvme_transport_id *trid, const struct spdk_nvme_ctrlr_opts *opts, \ void *devhandle); \ int nvme_ ## name ## _ctrlr_destruct(struct spdk_nvme_ctrlr *ctrlr); \ - int nvme_ ## name ## _ctrlr_scan(const struct spdk_nvme_transport_id *trid, void *cb_ctx, spdk_nvme_probe_cb probe_cb, spdk_nvme_remove_cb remove_cb); \ + int nvme_ ## name ## _ctrlr_scan(const struct spdk_nvme_transport_id *trid, void *cb_ctx, spdk_nvme_probe_cb probe_cb, spdk_nvme_remove_cb remove_cb, bool direct_connect); \ int nvme_ ## name ## _ctrlr_enable(struct spdk_nvme_ctrlr *ctrlr); \ int nvme_ ## name ## _ctrlr_set_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t value); \ int nvme_ ## name ## _ctrlr_set_reg_8(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint64_t value); \ diff --git a/lib/nvme/nvme_pcie.c b/lib/nvme/nvme_pcie.c index c23af6035..a0b053872 100644 --- a/lib/nvme/nvme_pcie.c +++ b/lib/nvme/nvme_pcie.c @@ -610,7 +610,8 @@ int nvme_pcie_ctrlr_scan(const struct spdk_nvme_transport_id *trid, void *cb_ctx, spdk_nvme_probe_cb probe_cb, - spdk_nvme_remove_cb remove_cb) + spdk_nvme_remove_cb remove_cb, + bool direct_connect) { struct nvme_pcie_enum_ctx enum_ctx = {}; diff --git a/lib/nvme/nvme_rdma.c b/lib/nvme/nvme_rdma.c index 590e5d35f..d3dae5c86 100644 --- a/lib/nvme/nvme_rdma.c +++ b/lib/nvme/nvme_rdma.c @@ -1172,7 +1172,8 @@ int nvme_rdma_ctrlr_scan(const struct spdk_nvme_transport_id *discovery_trid, void *cb_ctx, spdk_nvme_probe_cb probe_cb, - spdk_nvme_remove_cb remove_cb) + spdk_nvme_remove_cb remove_cb, + bool direct_connect) { struct spdk_nvme_ctrlr_opts discovery_opts; struct spdk_nvme_ctrlr *discovery_ctrlr; @@ -1232,6 +1233,15 @@ nvme_rdma_ctrlr_scan(const struct spdk_nvme_transport_id *discovery_trid, return -ENXIO; } + /* Direct attach through spdk_nvme_connect() API */ + if (direct_connect == true) { + /* Set the ready state to skip the normal init process */ + discovery_ctrlr->state = NVME_CTRLR_STATE_READY; + TAILQ_INSERT_TAIL(&g_spdk_nvme_driver->init_ctrlrs, discovery_ctrlr, tailq); + nvme_ctrlr_add_process(discovery_ctrlr, 0); + return 0; + } + buffer_max_entries_first = (sizeof(buffer) - offsetof(struct spdk_nvmf_discovery_log_page, entries[0])) / sizeof(struct spdk_nvmf_discovery_log_page_entry); diff --git a/lib/nvme/nvme_transport.c b/lib/nvme/nvme_transport.c index 406905b54..9eb3f54fa 100644 --- a/lib/nvme/nvme_transport.c +++ b/lib/nvme/nvme_transport.c @@ -92,9 +92,10 @@ int nvme_transport_ctrlr_scan(const struct spdk_nvme_transport_id *trid, void *cb_ctx, spdk_nvme_probe_cb probe_cb, - spdk_nvme_remove_cb remove_cb) + spdk_nvme_remove_cb remove_cb, + bool direct_connect) { - NVME_TRANSPORT_CALL(trid->trtype, ctrlr_scan, (trid, cb_ctx, probe_cb, remove_cb)); + NVME_TRANSPORT_CALL(trid->trtype, ctrlr_scan, (trid, cb_ctx, probe_cb, remove_cb, direct_connect)); } int diff --git a/test/unit/lib/nvme/nvme.c/nvme_ut.c b/test/unit/lib/nvme/nvme.c/nvme_ut.c index 3fce1c3a6..d7f80fce7 100644 --- a/test/unit/lib/nvme/nvme.c/nvme_ut.c +++ b/test/unit/lib/nvme/nvme.c/nvme_ut.c @@ -112,7 +112,8 @@ int nvme_transport_ctrlr_scan(const struct spdk_nvme_transport_id *trid, void *cb_ctx, spdk_nvme_probe_cb probe_cb, - spdk_nvme_remove_cb remove_cb) + spdk_nvme_remove_cb remove_cb, + bool direct_connect) { if (ut_check_trtype == true) { CU_ASSERT(trid->trtype == SPDK_NVME_TRANSPORT_PCIE); diff --git a/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c b/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c index c47206f84..dc97c2151 100644 --- a/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c +++ b/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c @@ -182,7 +182,8 @@ int nvme_transport_ctrlr_scan(const struct spdk_nvme_transport_id *trid, void *cb_ctx, spdk_nvme_probe_cb probe_cb, - spdk_nvme_remove_cb remove_cb) + spdk_nvme_remove_cb remove_cb, + bool direct_connect) { return 0; }