nvme: add new spdk_nvme_connect() API to directly attach the ctrlr

With this new API, callers can attach one specific ctrlr identified by
the transport ID directly along with optional ctrlr opts. If connecting
to multiple controllers, it is still suggested to use spdk_nvme_probe()
and filter the requested controllers with the probe callback.

Two primary use cases:
1) connecting to the NVMe-oF discovery controller
2) more straightforward way to connect a specific controller (avoiding
the probe callback)

A typical usage of this API with specific ctrlr_opts:
1. struct spdk_nvme_ctrlr_opts user_opts = {}
2. Call spdk_nvme_ctrlr_get_default_ctrlr_opts(&user_opts, sizeof(user_opts))
3. Modify the content of the initialized user_opts with user required value like
   user_opts.num_io_queues = 8
4. Call spdk_nvme_connect(&trid, &user_opts, sizeof(user_opts))

Change-Id: Idf67ee5966f6753918c12604342c892d2f3bbe3a
Signed-off-by: GangCao <gang.cao@intel.com>
Reviewed-on: https://review.gerrithub.io/370634
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
GangCao 2017-07-20 23:01:03 -04:00 committed by Daniel Verkamp
parent dc2fb2ed39
commit 6368d6c0f5
9 changed files with 179 additions and 32 deletions

View File

@ -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.
*

View File

@ -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)
{

View File

@ -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);

View File

@ -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); \

View File

@ -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 = {};

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;
}