LCOV - code coverage report
Current view: top level - lib/nvme - nvme.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 651 801 81.3 %
Date: 2024-11-05 10:06:02 Functions: 48 55 87.3 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2015 Intel Corporation. All rights reserved.
       3             :  *   Copyright (c) 2020 Mellanox Technologies LTD. All rights reserved.
       4             :  */
       5             : 
       6             : #include "spdk/config.h"
       7             : #include "spdk/nvmf_spec.h"
       8             : #include "spdk/string.h"
       9             : #include "spdk/env.h"
      10             : #include "nvme_internal.h"
      11             : #include "nvme_io_msg.h"
      12             : 
      13             : #define SPDK_NVME_DRIVER_NAME "spdk_nvme_driver"
      14             : 
      15             : struct nvme_driver      *g_spdk_nvme_driver;
      16             : pid_t                   g_spdk_nvme_pid;
      17             : 
      18             : /* gross timeout of 180 seconds in milliseconds */
      19             : static int g_nvme_driver_timeout_ms = 3 * 60 * 1000;
      20             : 
      21             : /* Per-process attached controller list */
      22             : static TAILQ_HEAD(, spdk_nvme_ctrlr) g_nvme_attached_ctrlrs =
      23             :         TAILQ_HEAD_INITIALIZER(g_nvme_attached_ctrlrs);
      24             : 
      25             : /* Returns true if ctrlr should be stored on the multi-process shared_attached_ctrlrs list */
      26             : static bool
      27          12 : nvme_ctrlr_shared(const struct spdk_nvme_ctrlr *ctrlr)
      28             : {
      29          12 :         return ctrlr->trid.trtype == SPDK_NVME_TRANSPORT_PCIE;
      30             : }
      31             : 
      32             : void
      33           0 : nvme_ctrlr_connected(struct spdk_nvme_probe_ctx *probe_ctx,
      34             :                      struct spdk_nvme_ctrlr *ctrlr)
      35             : {
      36           0 :         TAILQ_INSERT_TAIL(&probe_ctx->init_ctrlrs, ctrlr, tailq);
      37           0 : }
      38             : 
      39             : static void
      40          10 : nvme_ctrlr_detach_async_finish(struct spdk_nvme_ctrlr *ctrlr)
      41             : {
      42          10 :         nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
      43          10 :         if (nvme_ctrlr_shared(ctrlr)) {
      44           8 :                 TAILQ_REMOVE(&g_spdk_nvme_driver->shared_attached_ctrlrs, ctrlr, tailq);
      45             :         } else {
      46           2 :                 TAILQ_REMOVE(&g_nvme_attached_ctrlrs, ctrlr, tailq);
      47             :         }
      48          10 :         nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
      49          10 : }
      50             : 
      51             : static int
      52          11 : nvme_ctrlr_detach_async(struct spdk_nvme_ctrlr *ctrlr,
      53             :                         struct nvme_ctrlr_detach_ctx **_ctx)
      54             : {
      55             :         struct nvme_ctrlr_detach_ctx *ctx;
      56             :         int ref_count;
      57             : 
      58          11 :         nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
      59             : 
      60          11 :         ref_count = nvme_ctrlr_get_ref_count(ctrlr);
      61          11 :         assert(ref_count > 0);
      62             : 
      63          11 :         if (ref_count == 1) {
      64             :                 /* This is the last reference to the controller, so we need to
      65             :                  * allocate a context to destruct it.
      66             :                  */
      67          10 :                 ctx = calloc(1, sizeof(*ctx));
      68          10 :                 if (ctx == NULL) {
      69           0 :                         nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
      70             : 
      71           0 :                         return -ENOMEM;
      72             :                 }
      73          10 :                 ctx->ctrlr = ctrlr;
      74          10 :                 ctx->cb_fn = nvme_ctrlr_detach_async_finish;
      75             : 
      76          10 :                 nvme_ctrlr_proc_put_ref(ctrlr);
      77             : 
      78          10 :                 nvme_io_msg_ctrlr_detach(ctrlr);
      79             : 
      80          10 :                 nvme_ctrlr_destruct_async(ctrlr, ctx);
      81             : 
      82          10 :                 *_ctx = ctx;
      83             :         } else {
      84           1 :                 nvme_ctrlr_proc_put_ref(ctrlr);
      85             :         }
      86             : 
      87          11 :         nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
      88             : 
      89          11 :         return 0;
      90             : }
      91             : 
      92             : static int
      93          11 : nvme_ctrlr_detach_poll_async(struct nvme_ctrlr_detach_ctx *ctx)
      94             : {
      95             :         int rc;
      96             : 
      97          11 :         rc = nvme_ctrlr_destruct_poll_async(ctx->ctrlr, ctx);
      98          11 :         if (rc == -EAGAIN) {
      99           1 :                 return -EAGAIN;
     100             :         }
     101             : 
     102          10 :         free(ctx);
     103             : 
     104          10 :         return rc;
     105             : }
     106             : 
     107             : int
     108           5 : spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr)
     109             : {
     110           5 :         struct nvme_ctrlr_detach_ctx *ctx = NULL;
     111             :         int rc;
     112             : 
     113           5 :         rc = nvme_ctrlr_detach_async(ctrlr, &ctx);
     114           5 :         if (rc != 0) {
     115           0 :                 return rc;
     116           5 :         } else if (ctx == NULL) {
     117             :                 /* ctrlr was detached from the caller process but any other process
     118             :                  * still attaches it.
     119             :                  */
     120           1 :                 return 0;
     121             :         }
     122             : 
     123             :         while (1) {
     124           4 :                 rc = nvme_ctrlr_detach_poll_async(ctx);
     125           4 :                 if (rc != -EAGAIN) {
     126           4 :                         break;
     127             :                 }
     128           0 :                 nvme_delay(1000);
     129             :         }
     130             : 
     131           4 :         return 0;
     132             : }
     133             : 
     134             : int
     135           6 : spdk_nvme_detach_async(struct spdk_nvme_ctrlr *ctrlr,
     136             :                        struct spdk_nvme_detach_ctx **_detach_ctx)
     137             : {
     138             :         struct spdk_nvme_detach_ctx *detach_ctx;
     139           6 :         struct nvme_ctrlr_detach_ctx *ctx = NULL;
     140             :         int rc;
     141             : 
     142           6 :         if (ctrlr == NULL || _detach_ctx == NULL) {
     143           0 :                 return -EINVAL;
     144             :         }
     145             : 
     146             :         /* Use a context header to poll detachment for multiple controllers.
     147             :          * Allocate an new one if not allocated yet, or use the passed one otherwise.
     148             :          */
     149           6 :         detach_ctx = *_detach_ctx;
     150           6 :         if (detach_ctx == NULL) {
     151           3 :                 detach_ctx = calloc(1, sizeof(*detach_ctx));
     152           3 :                 if (detach_ctx == NULL) {
     153           0 :                         return -ENOMEM;
     154             :                 }
     155           3 :                 TAILQ_INIT(&detach_ctx->head);
     156             :         }
     157             : 
     158           6 :         rc = nvme_ctrlr_detach_async(ctrlr, &ctx);
     159           6 :         if (rc != 0 || ctx == NULL) {
     160             :                 /* If this detach failed and the context header is empty, it means we just
     161             :                  * allocated the header and need to free it before returning.
     162             :                  */
     163           0 :                 if (TAILQ_EMPTY(&detach_ctx->head)) {
     164           0 :                         free(detach_ctx);
     165             :                 }
     166           0 :                 return rc;
     167             :         }
     168             : 
     169             :         /* Append a context for this detachment to the context header. */
     170           6 :         TAILQ_INSERT_TAIL(&detach_ctx->head, ctx, link);
     171             : 
     172           6 :         *_detach_ctx = detach_ctx;
     173             : 
     174           6 :         return 0;
     175             : }
     176             : 
     177             : int
     178           4 : spdk_nvme_detach_poll_async(struct spdk_nvme_detach_ctx *detach_ctx)
     179             : {
     180             :         struct nvme_ctrlr_detach_ctx *ctx, *tmp_ctx;
     181             :         int rc;
     182             : 
     183           4 :         if (detach_ctx == NULL) {
     184           0 :                 return -EINVAL;
     185             :         }
     186             : 
     187          11 :         TAILQ_FOREACH_SAFE(ctx, &detach_ctx->head, link, tmp_ctx) {
     188           7 :                 TAILQ_REMOVE(&detach_ctx->head, ctx, link);
     189             : 
     190           7 :                 rc = nvme_ctrlr_detach_poll_async(ctx);
     191           7 :                 if (rc == -EAGAIN) {
     192             :                         /* If not -EAGAIN, ctx was freed by nvme_ctrlr_detach_poll_async(). */
     193           1 :                         TAILQ_INSERT_HEAD(&detach_ctx->head, ctx, link);
     194             :                 }
     195             :         }
     196             : 
     197           4 :         if (!TAILQ_EMPTY(&detach_ctx->head)) {
     198           1 :                 return -EAGAIN;
     199             :         }
     200             : 
     201           3 :         free(detach_ctx);
     202           3 :         return 0;
     203             : }
     204             : 
     205             : void
     206           0 : spdk_nvme_detach_poll(struct spdk_nvme_detach_ctx *detach_ctx)
     207             : {
     208           0 :         while (detach_ctx && spdk_nvme_detach_poll_async(detach_ctx) == -EAGAIN) {
     209             :                 ;
     210             :         }
     211           0 : }
     212             : 
     213             : void
     214           1 : nvme_completion_poll_cb(void *arg, const struct spdk_nvme_cpl *cpl)
     215             : {
     216           1 :         struct nvme_completion_poll_status      *status = arg;
     217             : 
     218           1 :         if (status->timed_out) {
     219             :                 /* There is no routine waiting for the completion of this request, free allocated memory */
     220           0 :                 spdk_free(status->dma_data);
     221           0 :                 free(status);
     222           0 :                 return;
     223             :         }
     224             : 
     225             :         /*
     226             :          * Copy status into the argument passed by the caller, so that
     227             :          *  the caller can check the status to determine if the
     228             :          *  the request passed or failed.
     229             :          */
     230           1 :         memcpy(&status->cpl, cpl, sizeof(*cpl));
     231           1 :         status->done = true;
     232             : }
     233             : 
     234             : static void
     235           0 : dummy_disconnected_qpair_cb(struct spdk_nvme_qpair *qpair, void *poll_group_ctx)
     236             : {
     237           0 : }
     238             : 
     239             : int
     240          10 : nvme_wait_for_completion_robust_lock_timeout_poll(struct spdk_nvme_qpair *qpair,
     241             :                 struct nvme_completion_poll_status *status,
     242             :                 pthread_mutex_t *robust_mutex)
     243             : {
     244             :         int rc;
     245             : 
     246          10 :         if (robust_mutex) {
     247           5 :                 nvme_robust_mutex_lock(robust_mutex);
     248             :         }
     249             : 
     250          10 :         if (qpair->poll_group) {
     251           0 :                 rc = (int)spdk_nvme_poll_group_process_completions(qpair->poll_group->group, 0,
     252             :                                 dummy_disconnected_qpair_cb);
     253             :         } else {
     254          10 :                 rc = spdk_nvme_qpair_process_completions(qpair, 0);
     255             :         }
     256             : 
     257          10 :         if (robust_mutex) {
     258           5 :                 nvme_robust_mutex_unlock(robust_mutex);
     259             :         }
     260             : 
     261          10 :         if (rc < 0) {
     262           4 :                 status->cpl.status.sct = SPDK_NVME_SCT_GENERIC;
     263           4 :                 status->cpl.status.sc = SPDK_NVME_SC_ABORTED_SQ_DELETION;
     264           4 :                 goto error;
     265             :         }
     266             : 
     267           6 :         if (!status->done && status->timeout_tsc && spdk_get_ticks() > status->timeout_tsc) {
     268           2 :                 goto error;
     269             :         }
     270             : 
     271           4 :         if (qpair->ctrlr->trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
     272           4 :                 union spdk_nvme_csts_register csts = spdk_nvme_ctrlr_get_regs_csts(qpair->ctrlr);
     273           4 :                 if (csts.raw == SPDK_NVME_INVALID_REGISTER_VALUE) {
     274           0 :                         status->cpl.status.sct = SPDK_NVME_SCT_GENERIC;
     275           0 :                         status->cpl.status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
     276           0 :                         goto error;
     277             :                 }
     278             :         }
     279             : 
     280           4 :         if (!status->done) {
     281           0 :                 return -EAGAIN;
     282           4 :         } else if (spdk_nvme_cpl_is_error(&status->cpl)) {
     283           0 :                 return -EIO;
     284             :         } else {
     285           4 :                 return 0;
     286             :         }
     287           6 : error:
     288             :         /* Either transport error occurred or we've timed out.  Either way, if the response hasn't
     289             :          * been received yet, mark the command as timed out, so the status gets freed when the
     290             :          * command is completed or aborted.
     291             :          */
     292           6 :         if (!status->done) {
     293           6 :                 status->timed_out = true;
     294             :         }
     295             : 
     296           6 :         return -ECANCELED;
     297             : }
     298             : 
     299             : /**
     300             :  * Poll qpair for completions until a command completes.
     301             :  *
     302             :  * \param qpair queue to poll
     303             :  * \param status completion status. The user must fill this structure with zeroes before calling
     304             :  * this function
     305             :  * \param robust_mutex optional robust mutex to lock while polling qpair
     306             :  * \param timeout_in_usecs optional timeout
     307             :  *
     308             :  * \return 0 if command completed without error,
     309             :  * -EIO if command completed with error,
     310             :  * -ECANCELED if command is not completed due to transport/device error or time expired
     311             :  *
     312             :  *  The command to wait upon must be submitted with nvme_completion_poll_cb as the callback
     313             :  *  and status as the callback argument.
     314             :  */
     315             : int
     316          10 : nvme_wait_for_completion_robust_lock_timeout(
     317             :         struct spdk_nvme_qpair *qpair,
     318             :         struct nvme_completion_poll_status *status,
     319             :         pthread_mutex_t *robust_mutex,
     320             :         uint64_t timeout_in_usecs)
     321             : {
     322             :         int rc;
     323             : 
     324          10 :         if (timeout_in_usecs) {
     325          12 :                 status->timeout_tsc = spdk_get_ticks() + timeout_in_usecs *
     326           6 :                                       spdk_get_ticks_hz() / SPDK_SEC_TO_USEC;
     327             :         } else {
     328           4 :                 status->timeout_tsc = 0;
     329             :         }
     330             : 
     331          10 :         status->cpl.status_raw = 0;
     332             :         do {
     333          10 :                 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, robust_mutex);
     334          10 :         } while (rc == -EAGAIN);
     335             : 
     336          10 :         return rc;
     337             : }
     338             : 
     339             : /**
     340             :  * Poll qpair for completions until a command completes.
     341             :  *
     342             :  * \param qpair queue to poll
     343             :  * \param status completion status. The user must fill this structure with zeroes before calling
     344             :  * this function
     345             :  * \param robust_mutex optional robust mutex to lock while polling qpair
     346             :  *
     347             :  * \return 0 if command completed without error,
     348             :  * -EIO if command completed with error,
     349             :  * -ECANCELED if command is not completed due to transport/device error
     350             :  *
     351             :  * The command to wait upon must be submitted with nvme_completion_poll_cb as the callback
     352             :  * and status as the callback argument.
     353             :  */
     354             : int
     355           2 : nvme_wait_for_completion_robust_lock(
     356             :         struct spdk_nvme_qpair *qpair,
     357             :         struct nvme_completion_poll_status *status,
     358             :         pthread_mutex_t *robust_mutex)
     359             : {
     360           2 :         return nvme_wait_for_completion_robust_lock_timeout(qpair, status, robust_mutex, 0);
     361             : }
     362             : 
     363             : int
     364           2 : nvme_wait_for_completion(struct spdk_nvme_qpair *qpair,
     365             :                          struct nvme_completion_poll_status *status)
     366             : {
     367           2 :         return nvme_wait_for_completion_robust_lock_timeout(qpair, status, NULL, 0);
     368             : }
     369             : 
     370             : /**
     371             :  * Poll qpair for completions until a command completes.
     372             :  *
     373             :  * \param qpair queue to poll
     374             :  * \param status completion status. The user must fill this structure with zeroes before calling
     375             :  * this function
     376             :  * \param timeout_in_usecs optional timeout
     377             :  *
     378             :  * \return 0 if command completed without error,
     379             :  * -EIO if command completed with error,
     380             :  * -ECANCELED if command is not completed due to transport/device error or time expired
     381             :  *
     382             :  * The command to wait upon must be submitted with nvme_completion_poll_cb as the callback
     383             :  * and status as the callback argument.
     384             :  */
     385             : int
     386           3 : nvme_wait_for_completion_timeout(struct spdk_nvme_qpair *qpair,
     387             :                                  struct nvme_completion_poll_status *status,
     388             :                                  uint64_t timeout_in_usecs)
     389             : {
     390           3 :         return nvme_wait_for_completion_robust_lock_timeout(qpair, status, NULL, timeout_in_usecs);
     391             : }
     392             : 
     393             : static void
     394           3 : nvme_user_copy_cmd_complete(void *arg, const struct spdk_nvme_cpl *cpl)
     395             : {
     396           3 :         struct nvme_request *req = arg;
     397             :         spdk_nvme_cmd_cb user_cb_fn;
     398             :         void *user_cb_arg;
     399             :         enum spdk_nvme_data_transfer xfer;
     400             : 
     401           3 :         if (req->user_buffer && req->payload_size) {
     402             :                 /* Copy back to the user buffer */
     403           2 :                 assert(nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_CONTIG);
     404           2 :                 xfer = spdk_nvme_opc_get_data_transfer(req->cmd.opc);
     405           2 :                 if (xfer == SPDK_NVME_DATA_CONTROLLER_TO_HOST ||
     406             :                     xfer == SPDK_NVME_DATA_BIDIRECTIONAL) {
     407           1 :                         assert(req->pid == getpid());
     408           1 :                         memcpy(req->user_buffer, req->payload.contig_or_cb_arg, req->payload_size);
     409             :                 }
     410             :         }
     411             : 
     412           3 :         user_cb_fn = req->user_cb_fn;
     413           3 :         user_cb_arg = req->user_cb_arg;
     414           3 :         nvme_cleanup_user_req(req);
     415             : 
     416             :         /* Call the user's original callback now that the buffer has been copied */
     417           3 :         user_cb_fn(user_cb_arg, cpl);
     418             : 
     419           3 : }
     420             : 
     421             : /**
     422             :  * Allocate a request as well as a DMA-capable buffer to copy to/from the user's buffer.
     423             :  *
     424             :  * This is intended for use in non-fast-path functions (admin commands, reservations, etc.)
     425             :  * where the overhead of a copy is not a problem.
     426             :  */
     427             : struct nvme_request *
     428          14 : nvme_allocate_request_user_copy(struct spdk_nvme_qpair *qpair,
     429             :                                 void *buffer, uint32_t payload_size, spdk_nvme_cmd_cb cb_fn,
     430             :                                 void *cb_arg, bool host_to_controller)
     431             : {
     432             :         struct nvme_request *req;
     433          14 :         void *dma_buffer = NULL;
     434             : 
     435          14 :         if (buffer && payload_size) {
     436          13 :                 dma_buffer = spdk_zmalloc(payload_size, 4096, NULL,
     437             :                                           SPDK_ENV_NUMA_ID_ANY, SPDK_MALLOC_DMA);
     438          13 :                 if (!dma_buffer) {
     439           1 :                         return NULL;
     440             :                 }
     441             : 
     442          12 :                 if (host_to_controller) {
     443           8 :                         memcpy(dma_buffer, buffer, payload_size);
     444             :                 }
     445             :         }
     446             : 
     447          13 :         req = nvme_allocate_request_contig(qpair, dma_buffer, payload_size, nvme_user_copy_cmd_complete,
     448             :                                            NULL);
     449          13 :         if (!req) {
     450           1 :                 spdk_free(dma_buffer);
     451           1 :                 return NULL;
     452             :         }
     453             : 
     454          12 :         req->user_cb_fn = cb_fn;
     455          12 :         req->user_cb_arg = cb_arg;
     456          12 :         req->user_buffer = buffer;
     457          12 :         req->cb_arg = req;
     458             : 
     459          12 :         return req;
     460             : }
     461             : 
     462             : /**
     463             :  * Check if a request has exceeded the controller timeout.
     464             :  *
     465             :  * \param req request to check for timeout.
     466             :  * \param cid command ID for command submitted by req (will be passed to timeout_cb_fn)
     467             :  * \param active_proc per-process data for the controller associated with req
     468             :  * \param now_tick current time from spdk_get_ticks()
     469             :  * \return 0 if requests submitted more recently than req should still be checked for timeouts, or
     470             :  * 1 if requests newer than req need not be checked.
     471             :  *
     472             :  * The request's timeout callback will be called if needed; the caller is only responsible for
     473             :  * calling this function on each outstanding request.
     474             :  */
     475             : int
     476           6 : nvme_request_check_timeout(struct nvme_request *req, uint16_t cid,
     477             :                            struct spdk_nvme_ctrlr_process *active_proc,
     478             :                            uint64_t now_tick)
     479             : {
     480           6 :         struct spdk_nvme_qpair *qpair = req->qpair;
     481           6 :         struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
     482           6 :         uint64_t timeout_ticks = nvme_qpair_is_admin_queue(qpair) ?
     483           6 :                                  active_proc->timeout_admin_ticks : active_proc->timeout_io_ticks;
     484             : 
     485           6 :         assert(active_proc->timeout_cb_fn != NULL);
     486             : 
     487           6 :         if (req->timed_out || req->submit_tick == 0) {
     488           2 :                 return 0;
     489             :         }
     490             : 
     491           4 :         if (req->pid != g_spdk_nvme_pid) {
     492           1 :                 return 0;
     493             :         }
     494             : 
     495           3 :         if (nvme_qpair_is_admin_queue(qpair) &&
     496           1 :             req->cmd.opc == SPDK_NVME_OPC_ASYNC_EVENT_REQUEST) {
     497           1 :                 return 0;
     498             :         }
     499             : 
     500           2 :         if (req->submit_tick + timeout_ticks > now_tick) {
     501           1 :                 return 1;
     502             :         }
     503             : 
     504           1 :         req->timed_out = true;
     505             : 
     506             :         /*
     507             :          * We don't want to expose the admin queue to the user,
     508             :          * so when we're timing out admin commands set the
     509             :          * qpair to NULL.
     510             :          */
     511           2 :         active_proc->timeout_cb_fn(active_proc->timeout_cb_arg, ctrlr,
     512           1 :                                    nvme_qpair_is_admin_queue(qpair) ? NULL : qpair,
     513             :                                    cid);
     514           1 :         return 0;
     515             : }
     516             : 
     517             : int
     518           7 : nvme_robust_mutex_init_shared(pthread_mutex_t *mtx)
     519             : {
     520           7 :         int rc = 0;
     521             : 
     522             : #ifdef __FreeBSD__
     523             :         pthread_mutex_init(mtx, NULL);
     524             : #else
     525           7 :         pthread_mutexattr_t attr;
     526             : 
     527           7 :         if (pthread_mutexattr_init(&attr)) {
     528           2 :                 return -1;
     529             :         }
     530          10 :         if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) ||
     531          10 :             pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST) ||
     532           5 :             pthread_mutex_init(mtx, &attr)) {
     533           1 :                 rc = -1;
     534             :         }
     535           5 :         pthread_mutexattr_destroy(&attr);
     536             : #endif
     537             : 
     538           5 :         return rc;
     539             : }
     540             : 
     541             : int
     542          32 : nvme_driver_init(void)
     543             : {
     544             :         static pthread_mutex_t g_init_mutex = PTHREAD_MUTEX_INITIALIZER;
     545          32 :         int ret = 0;
     546             : 
     547             :         /* Use a special process-private mutex to ensure the global
     548             :          * nvme driver object (g_spdk_nvme_driver) gets initialized by
     549             :          * only one thread.  Once that object is established and its
     550             :          * mutex is initialized, we can unlock this mutex and use that
     551             :          * one instead.
     552             :          */
     553          32 :         pthread_mutex_lock(&g_init_mutex);
     554             : 
     555             :         /* Each process needs its own pid. */
     556          32 :         g_spdk_nvme_pid = getpid();
     557             : 
     558             :         /*
     559             :          * Only one thread from one process will do this driver init work.
     560             :          * The primary process will reserve the shared memory and do the
     561             :          *  initialization.
     562             :          * The secondary process will lookup the existing reserved memory.
     563             :          */
     564          32 :         if (spdk_process_is_primary()) {
     565             :                 /* The unique named memzone already reserved. */
     566          14 :                 if (g_spdk_nvme_driver != NULL) {
     567           9 :                         pthread_mutex_unlock(&g_init_mutex);
     568           9 :                         return 0;
     569             :                 } else {
     570           5 :                         g_spdk_nvme_driver = spdk_memzone_reserve(SPDK_NVME_DRIVER_NAME,
     571             :                                              sizeof(struct nvme_driver), SPDK_ENV_NUMA_ID_ANY,
     572             :                                              SPDK_MEMZONE_NO_IOVA_CONTIG);
     573             :                 }
     574             : 
     575           5 :                 if (g_spdk_nvme_driver == NULL) {
     576           1 :                         SPDK_ERRLOG("primary process failed to reserve memory\n");
     577           1 :                         pthread_mutex_unlock(&g_init_mutex);
     578           1 :                         return -1;
     579             :                 }
     580             :         } else {
     581          18 :                 g_spdk_nvme_driver = spdk_memzone_lookup(SPDK_NVME_DRIVER_NAME);
     582             : 
     583             :                 /* The unique named memzone already reserved by the primary process. */
     584          18 :                 if (g_spdk_nvme_driver != NULL) {
     585          15 :                         int ms_waited = 0;
     586             : 
     587             :                         /* Wait the nvme driver to get initialized. */
     588         115 :                         while ((g_spdk_nvme_driver->initialized == false) &&
     589         101 :                                (ms_waited < g_nvme_driver_timeout_ms)) {
     590         100 :                                 ms_waited++;
     591         100 :                                 nvme_delay(1000); /* delay 1ms */
     592             :                         }
     593          15 :                         if (g_spdk_nvme_driver->initialized == false) {
     594           1 :                                 SPDK_ERRLOG("timeout waiting for primary process to init\n");
     595           1 :                                 pthread_mutex_unlock(&g_init_mutex);
     596           1 :                                 return -1;
     597             :                         }
     598             :                 } else {
     599           3 :                         SPDK_ERRLOG("primary process is not started yet\n");
     600           3 :                         pthread_mutex_unlock(&g_init_mutex);
     601           3 :                         return -1;
     602             :                 }
     603             : 
     604          14 :                 pthread_mutex_unlock(&g_init_mutex);
     605          14 :                 return 0;
     606             :         }
     607             : 
     608             :         /*
     609             :          * At this moment, only one thread from the primary process will do
     610             :          * the g_spdk_nvme_driver initialization
     611             :          */
     612           4 :         assert(spdk_process_is_primary());
     613             : 
     614           4 :         ret = nvme_robust_mutex_init_shared(&g_spdk_nvme_driver->lock);
     615           4 :         if (ret != 0) {
     616           1 :                 SPDK_ERRLOG("failed to initialize mutex\n");
     617           1 :                 spdk_memzone_free(SPDK_NVME_DRIVER_NAME);
     618           1 :                 pthread_mutex_unlock(&g_init_mutex);
     619           1 :                 return ret;
     620             :         }
     621             : 
     622             :         /* The lock in the shared g_spdk_nvme_driver object is now ready to
     623             :          * be used - so we can unlock the g_init_mutex here.
     624             :          */
     625           3 :         pthread_mutex_unlock(&g_init_mutex);
     626           3 :         nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
     627             : 
     628           3 :         g_spdk_nvme_driver->initialized = false;
     629           3 :         g_spdk_nvme_driver->hotplug_fd = spdk_pci_event_listen();
     630           3 :         if (g_spdk_nvme_driver->hotplug_fd < 0) {
     631           0 :                 SPDK_DEBUGLOG(nvme, "Failed to open uevent netlink socket\n");
     632             :         }
     633             : 
     634           3 :         TAILQ_INIT(&g_spdk_nvme_driver->shared_attached_ctrlrs);
     635             : 
     636           3 :         spdk_uuid_generate(&g_spdk_nvme_driver->default_extended_host_id);
     637             : 
     638           3 :         nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
     639             : 
     640           3 :         return ret;
     641             : }
     642             : 
     643             : /* This function must only be called while holding g_spdk_nvme_driver->lock */
     644             : int
     645           6 : nvme_ctrlr_probe(const struct spdk_nvme_transport_id *trid,
     646             :                  struct spdk_nvme_probe_ctx *probe_ctx, void *devhandle)
     647             : {
     648             :         struct spdk_nvme_ctrlr *ctrlr;
     649           6 :         struct spdk_nvme_ctrlr_opts opts;
     650             : 
     651           6 :         assert(trid != NULL);
     652             : 
     653           6 :         spdk_nvme_ctrlr_get_default_ctrlr_opts(&opts, sizeof(opts));
     654             : 
     655           6 :         if (!probe_ctx->probe_cb || probe_ctx->probe_cb(probe_ctx->cb_ctx, trid, &opts)) {
     656           5 :                 ctrlr = nvme_get_ctrlr_by_trid_unsafe(trid, opts.hostnqn);
     657           5 :                 if (ctrlr) {
     658             :                         /* This ctrlr already exists. */
     659             : 
     660           1 :                         if (ctrlr->is_destructed) {
     661             :                                 /* This ctrlr is being destructed asynchronously. */
     662           1 :                                 SPDK_ERRLOG("NVMe controller for SSD: %s is being destructed\n",
     663             :                                             trid->traddr);
     664           1 :                                 probe_ctx->attach_fail_cb(probe_ctx->cb_ctx, trid, -EBUSY);
     665           1 :                                 return -EBUSY;
     666             :                         }
     667             : 
     668             :                         /* Increase the ref count before calling attach_cb() as the user may
     669             :                         * call nvme_detach() immediately. */
     670           0 :                         nvme_ctrlr_proc_get_ref(ctrlr);
     671             : 
     672           0 :                         if (probe_ctx->attach_cb) {
     673           0 :                                 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
     674           0 :                                 probe_ctx->attach_cb(probe_ctx->cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts);
     675           0 :                                 nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
     676             :                         }
     677           0 :                         return 0;
     678             :                 }
     679             : 
     680           4 :                 ctrlr = nvme_transport_ctrlr_construct(trid, &opts, devhandle);
     681           4 :                 if (ctrlr == NULL) {
     682           2 :                         SPDK_ERRLOG("Failed to construct NVMe controller for SSD: %s\n", trid->traddr);
     683           2 :                         probe_ctx->attach_fail_cb(probe_ctx->cb_ctx, trid, -ENODEV);
     684           2 :                         return -1;
     685             :                 }
     686           2 :                 ctrlr->remove_cb = probe_ctx->remove_cb;
     687           2 :                 ctrlr->cb_ctx = probe_ctx->cb_ctx;
     688             : 
     689           2 :                 nvme_qpair_set_state(ctrlr->adminq, NVME_QPAIR_ENABLED);
     690           2 :                 TAILQ_INSERT_TAIL(&probe_ctx->init_ctrlrs, ctrlr, tailq);
     691           2 :                 return 0;
     692             :         }
     693             : 
     694           1 :         return 1;
     695             : }
     696             : 
     697             : static void
     698           3 : nvme_ctrlr_poll_internal(struct spdk_nvme_ctrlr *ctrlr,
     699             :                          struct spdk_nvme_probe_ctx *probe_ctx)
     700             : {
     701           3 :         int rc = 0;
     702             : 
     703           3 :         rc = nvme_ctrlr_process_init(ctrlr);
     704             : 
     705           3 :         if (rc) {
     706             :                 /* Controller failed to initialize. */
     707           1 :                 TAILQ_REMOVE(&probe_ctx->init_ctrlrs, ctrlr, tailq);
     708           1 :                 SPDK_ERRLOG("Failed to initialize SSD: %s\n", ctrlr->trid.traddr);
     709           1 :                 probe_ctx->attach_fail_cb(probe_ctx->cb_ctx, &ctrlr->trid, rc);
     710           1 :                 nvme_ctrlr_lock(ctrlr);
     711           1 :                 nvme_ctrlr_fail(ctrlr, false);
     712           1 :                 nvme_ctrlr_unlock(ctrlr);
     713           1 :                 nvme_ctrlr_destruct(ctrlr);
     714           1 :                 return;
     715             :         }
     716             : 
     717           2 :         if (ctrlr->state != NVME_CTRLR_STATE_READY) {
     718           0 :                 return;
     719             :         }
     720             : 
     721           2 :         STAILQ_INIT(&ctrlr->io_producers);
     722             : 
     723             :         /*
     724             :          * Controller has been initialized.
     725             :          *  Move it to the attached_ctrlrs list.
     726             :          */
     727           2 :         TAILQ_REMOVE(&probe_ctx->init_ctrlrs, ctrlr, tailq);
     728             : 
     729           2 :         nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
     730           2 :         if (nvme_ctrlr_shared(ctrlr)) {
     731           1 :                 TAILQ_INSERT_TAIL(&g_spdk_nvme_driver->shared_attached_ctrlrs, ctrlr, tailq);
     732             :         } else {
     733           1 :                 TAILQ_INSERT_TAIL(&g_nvme_attached_ctrlrs, ctrlr, tailq);
     734             :         }
     735             : 
     736             :         /*
     737             :          * Increase the ref count before calling attach_cb() as the user may
     738             :          * call nvme_detach() immediately.
     739             :          */
     740           2 :         nvme_ctrlr_proc_get_ref(ctrlr);
     741           2 :         nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
     742             : 
     743           2 :         if (probe_ctx->attach_cb) {
     744           0 :                 probe_ctx->attach_cb(probe_ctx->cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts);
     745             :         }
     746             : }
     747             : 
     748             : static int
     749          14 : nvme_init_controllers(struct spdk_nvme_probe_ctx *probe_ctx)
     750             : {
     751          14 :         int rc = 0;
     752             : 
     753             :         while (true) {
     754          14 :                 rc = spdk_nvme_probe_poll_async(probe_ctx);
     755          14 :                 if (rc != -EAGAIN) {
     756          14 :                         return rc;
     757             :                 }
     758             :         }
     759             : 
     760             :         return rc;
     761             : }
     762             : 
     763             : /* This function must not be called while holding g_spdk_nvme_driver->lock */
     764             : static struct spdk_nvme_ctrlr *
     765          13 : nvme_get_ctrlr_by_trid(const struct spdk_nvme_transport_id *trid, const char *hostnqn)
     766             : {
     767             :         struct spdk_nvme_ctrlr *ctrlr;
     768             : 
     769          13 :         nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
     770          13 :         ctrlr = nvme_get_ctrlr_by_trid_unsafe(trid, hostnqn);
     771          13 :         nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
     772             : 
     773          13 :         return ctrlr;
     774             : }
     775             : 
     776             : /* This function must be called while holding g_spdk_nvme_driver->lock */
     777             : struct spdk_nvme_ctrlr *
     778          18 : nvme_get_ctrlr_by_trid_unsafe(const struct spdk_nvme_transport_id *trid, const char *hostnqn)
     779             : {
     780             :         struct spdk_nvme_ctrlr *ctrlr;
     781             : 
     782             :         /* Search per-process list */
     783          18 :         TAILQ_FOREACH(ctrlr, &g_nvme_attached_ctrlrs, tailq) {
     784           1 :                 if (spdk_nvme_transport_id_compare(&ctrlr->trid, trid) != 0) {
     785           0 :                         continue;
     786             :                 }
     787           1 :                 if (hostnqn && strcmp(ctrlr->opts.hostnqn, hostnqn) != 0) {
     788           0 :                         continue;
     789             :                 }
     790           1 :                 return ctrlr;
     791             :         }
     792             : 
     793             :         /* Search multi-process shared list */
     794          17 :         TAILQ_FOREACH(ctrlr, &g_spdk_nvme_driver->shared_attached_ctrlrs, tailq) {
     795          12 :                 if (spdk_nvme_transport_id_compare(&ctrlr->trid, trid) != 0) {
     796           0 :                         continue;
     797             :                 }
     798          12 :                 if (hostnqn && strcmp(ctrlr->opts.hostnqn, hostnqn) != 0) {
     799           0 :                         continue;
     800             :                 }
     801          12 :                 return ctrlr;
     802             :         }
     803             : 
     804           5 :         return NULL;
     805             : }
     806             : 
     807             : /* This function must only be called while holding g_spdk_nvme_driver->lock */
     808             : static int
     809          13 : nvme_probe_internal(struct spdk_nvme_probe_ctx *probe_ctx,
     810             :                     bool direct_connect)
     811             : {
     812             :         int rc;
     813             :         struct spdk_nvme_ctrlr *ctrlr, *ctrlr_tmp;
     814          13 :         const struct spdk_nvme_ctrlr_opts *opts = probe_ctx->opts;
     815             : 
     816          13 :         if (strlen(probe_ctx->trid.trstring) == 0) {
     817             :                 /* If user didn't provide trstring, derive it from trtype */
     818          10 :                 spdk_nvme_trid_populate_transport(&probe_ctx->trid, probe_ctx->trid.trtype);
     819             :         }
     820             : 
     821          13 :         if (!spdk_nvme_transport_available_by_name(probe_ctx->trid.trstring)) {
     822           1 :                 SPDK_ERRLOG("NVMe trtype %u (%s) not available\n",
     823             :                             probe_ctx->trid.trtype, probe_ctx->trid.trstring);
     824           1 :                 return -1;
     825             :         }
     826             : 
     827          12 :         nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
     828             : 
     829          12 :         rc = nvme_transport_ctrlr_scan(probe_ctx, direct_connect);
     830          12 :         if (rc != 0) {
     831           1 :                 SPDK_ERRLOG("NVMe ctrlr scan failed\n");
     832           2 :                 TAILQ_FOREACH_SAFE(ctrlr, &probe_ctx->init_ctrlrs, tailq, ctrlr_tmp) {
     833           1 :                         TAILQ_REMOVE(&probe_ctx->init_ctrlrs, ctrlr, tailq);
     834           1 :                         probe_ctx->attach_fail_cb(probe_ctx->cb_ctx, &ctrlr->trid, -EFAULT);
     835           1 :                         nvme_transport_ctrlr_destruct(ctrlr);
     836             :                 }
     837           1 :                 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
     838           1 :                 return -1;
     839             :         }
     840             : 
     841             :         /*
     842             :          * Probe controllers on the shared_attached_ctrlrs list
     843             :          */
     844          11 :         if (!spdk_process_is_primary() && (probe_ctx->trid.trtype == SPDK_NVME_TRANSPORT_PCIE)) {
     845          13 :                 TAILQ_FOREACH(ctrlr, &g_spdk_nvme_driver->shared_attached_ctrlrs, tailq) {
     846             :                         /* Do not attach other ctrlrs if user specify a valid trid */
     847          11 :                         if ((strlen(probe_ctx->trid.traddr) != 0) &&
     848           5 :                             (spdk_nvme_transport_id_compare(&probe_ctx->trid, &ctrlr->trid))) {
     849           0 :                                 continue;
     850             :                         }
     851             : 
     852           6 :                         if (opts && strcmp(opts->hostnqn, ctrlr->opts.hostnqn) != 0) {
     853           0 :                                 continue;
     854             :                         }
     855             : 
     856             :                         /* Do not attach if we failed to initialize it in this process */
     857           6 :                         if (nvme_ctrlr_get_current_process(ctrlr) == NULL) {
     858           0 :                                 continue;
     859             :                         }
     860             : 
     861           6 :                         nvme_ctrlr_proc_get_ref(ctrlr);
     862             : 
     863             :                         /*
     864             :                          * Unlock while calling attach_cb() so the user can call other functions
     865             :                          *  that may take the driver lock, like nvme_detach().
     866             :                          */
     867           6 :                         if (probe_ctx->attach_cb) {
     868           1 :                                 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
     869           1 :                                 probe_ctx->attach_cb(probe_ctx->cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts);
     870           1 :                                 nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
     871             :                         }
     872             :                 }
     873             :         }
     874             : 
     875          11 :         nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
     876             : 
     877          11 :         return 0;
     878             : }
     879             : 
     880             : static void
     881           0 : nvme_dummy_attach_fail_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
     882             :                           int rc)
     883             : {
     884           0 :         SPDK_ERRLOG("Failed to attach nvme ctrlr: trtype=%s adrfam=%s traddr=%s trsvcid=%s "
     885             :                     "subnqn=%s, %s\n", spdk_nvme_transport_id_trtype_str(trid->trtype),
     886             :                     spdk_nvme_transport_id_adrfam_str(trid->adrfam), trid->traddr, trid->trsvcid,
     887             :                     trid->subnqn, spdk_strerror(-rc));
     888           0 : }
     889             : 
     890             : static void
     891          17 : nvme_probe_ctx_init(struct spdk_nvme_probe_ctx *probe_ctx,
     892             :                     const struct spdk_nvme_transport_id *trid,
     893             :                     const struct spdk_nvme_ctrlr_opts *opts,
     894             :                     void *cb_ctx,
     895             :                     spdk_nvme_probe_cb probe_cb,
     896             :                     spdk_nvme_attach_cb attach_cb,
     897             :                     spdk_nvme_attach_fail_cb attach_fail_cb,
     898             :                     spdk_nvme_remove_cb remove_cb)
     899             : {
     900          17 :         probe_ctx->trid = *trid;
     901          17 :         probe_ctx->opts = opts;
     902          17 :         probe_ctx->cb_ctx = cb_ctx;
     903          17 :         probe_ctx->probe_cb = probe_cb;
     904          17 :         probe_ctx->attach_cb = attach_cb;
     905          17 :         if (attach_fail_cb != NULL) {
     906           6 :                 probe_ctx->attach_fail_cb = attach_fail_cb;
     907             :         } else {
     908          11 :                 probe_ctx->attach_fail_cb = nvme_dummy_attach_fail_cb;
     909             :         }
     910          17 :         probe_ctx->remove_cb = remove_cb;
     911          17 :         TAILQ_INIT(&probe_ctx->init_ctrlrs);
     912          17 : }
     913             : 
     914             : int
     915           0 : spdk_nvme_probe(const struct spdk_nvme_transport_id *trid, void *cb_ctx,
     916             :                 spdk_nvme_probe_cb probe_cb, spdk_nvme_attach_cb attach_cb,
     917             :                 spdk_nvme_remove_cb remove_cb)
     918             : {
     919           0 :         return spdk_nvme_probe_ext(trid, cb_ctx, probe_cb, attach_cb, NULL, remove_cb);
     920             : }
     921             : 
     922             : int
     923           4 : spdk_nvme_probe_ext(const struct spdk_nvme_transport_id *trid, void *cb_ctx,
     924             :                     spdk_nvme_probe_cb probe_cb, spdk_nvme_attach_cb attach_cb,
     925             :                     spdk_nvme_attach_fail_cb attach_fail_cb, spdk_nvme_remove_cb remove_cb)
     926             : {
     927           4 :         struct spdk_nvme_transport_id trid_pcie;
     928             :         struct spdk_nvme_probe_ctx *probe_ctx;
     929             : 
     930           4 :         if (trid == NULL) {
     931           4 :                 memset(&trid_pcie, 0, sizeof(trid_pcie));
     932           4 :                 spdk_nvme_trid_populate_transport(&trid_pcie, SPDK_NVME_TRANSPORT_PCIE);
     933           4 :                 trid = &trid_pcie;
     934             :         }
     935             : 
     936           4 :         probe_ctx = spdk_nvme_probe_async_ext(trid, cb_ctx, probe_cb,
     937             :                                               attach_cb, attach_fail_cb, remove_cb);
     938           4 :         if (!probe_ctx) {
     939           2 :                 SPDK_ERRLOG("Create probe context failed\n");
     940           2 :                 return -1;
     941             :         }
     942             : 
     943             :         /*
     944             :          * Keep going even if one or more nvme_attach() calls failed,
     945             :          *  but maintain the value of rc to signal errors when we return.
     946             :          */
     947           2 :         return nvme_init_controllers(probe_ctx);
     948             : }
     949             : 
     950             : static bool
     951           4 : nvme_connect_probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
     952             :                       struct spdk_nvme_ctrlr_opts *opts)
     953             : {
     954           4 :         struct spdk_nvme_ctrlr_opts *requested_opts = cb_ctx;
     955             : 
     956           4 :         assert(requested_opts);
     957           4 :         memcpy(opts, requested_opts, sizeof(*opts));
     958             : 
     959           4 :         return true;
     960             : }
     961             : 
     962             : static void
     963           4 : nvme_ctrlr_opts_init(struct spdk_nvme_ctrlr_opts *opts,
     964             :                      const struct spdk_nvme_ctrlr_opts *opts_user,
     965             :                      size_t opts_size_user)
     966             : {
     967           4 :         assert(opts);
     968           4 :         assert(opts_user);
     969             : 
     970           4 :         spdk_nvme_ctrlr_get_default_ctrlr_opts(opts, opts_size_user);
     971             : 
     972             : #define FIELD_OK(field) \
     973             :         offsetof(struct spdk_nvme_ctrlr_opts, field) + sizeof(opts->field) <= (opts->opts_size)
     974             : 
     975             : #define SET_FIELD(field) \
     976             :         if (FIELD_OK(field)) { \
     977             :                         opts->field = opts_user->field; \
     978             :         }
     979             : 
     980             : #define SET_FIELD_ARRAY(field) \
     981             :         if (FIELD_OK(field)) { \
     982             :                 memcpy(opts->field, opts_user->field, sizeof(opts_user->field)); \
     983             :         }
     984             : 
     985           4 :         SET_FIELD(num_io_queues);
     986           4 :         SET_FIELD(use_cmb_sqs);
     987           4 :         SET_FIELD(no_shn_notification);
     988           4 :         SET_FIELD(enable_interrupts);
     989           4 :         SET_FIELD(arb_mechanism);
     990           4 :         SET_FIELD(arbitration_burst);
     991           4 :         SET_FIELD(low_priority_weight);
     992           4 :         SET_FIELD(medium_priority_weight);
     993           4 :         SET_FIELD(high_priority_weight);
     994           4 :         SET_FIELD(keep_alive_timeout_ms);
     995           4 :         SET_FIELD(transport_retry_count);
     996           4 :         SET_FIELD(io_queue_size);
     997           4 :         SET_FIELD_ARRAY(hostnqn);
     998           4 :         SET_FIELD(io_queue_requests);
     999           4 :         SET_FIELD_ARRAY(src_addr);
    1000           4 :         SET_FIELD_ARRAY(src_svcid);
    1001           4 :         SET_FIELD_ARRAY(host_id);
    1002           4 :         SET_FIELD_ARRAY(extended_host_id);
    1003           4 :         SET_FIELD(command_set);
    1004           4 :         SET_FIELD(admin_timeout_ms);
    1005           4 :         SET_FIELD(header_digest);
    1006           4 :         SET_FIELD(data_digest);
    1007           4 :         SET_FIELD(disable_error_logging);
    1008           4 :         SET_FIELD(transport_ack_timeout);
    1009           4 :         SET_FIELD(admin_queue_size);
    1010           4 :         SET_FIELD(fabrics_connect_timeout_us);
    1011           4 :         SET_FIELD(disable_read_ana_log_page);
    1012           4 :         SET_FIELD(disable_read_changed_ns_list_log_page);
    1013           4 :         SET_FIELD(tls_psk);
    1014           4 :         SET_FIELD(dhchap_key);
    1015           4 :         SET_FIELD(dhchap_ctrlr_key);
    1016           4 :         SET_FIELD(dhchap_digests);
    1017           4 :         SET_FIELD(dhchap_dhgroups);
    1018             : 
    1019             : #undef FIELD_OK
    1020             : #undef SET_FIELD
    1021             : #undef SET_FIELD_ARRAY
    1022           4 : }
    1023             : 
    1024             : struct spdk_nvme_ctrlr *
    1025          11 : spdk_nvme_connect(const struct spdk_nvme_transport_id *trid,
    1026             :                   const struct spdk_nvme_ctrlr_opts *opts, size_t opts_size)
    1027             : {
    1028             :         int rc;
    1029          11 :         struct spdk_nvme_ctrlr *ctrlr = NULL;
    1030             :         struct spdk_nvme_probe_ctx *probe_ctx;
    1031          11 :         struct spdk_nvme_ctrlr_opts *opts_local_p = NULL;
    1032          11 :         struct spdk_nvme_ctrlr_opts opts_local;
    1033          11 :         char hostnqn[SPDK_NVMF_NQN_MAX_LEN + 1];
    1034             : 
    1035          11 :         if (trid == NULL) {
    1036           1 :                 SPDK_ERRLOG("No transport ID specified\n");
    1037           1 :                 return NULL;
    1038             :         }
    1039             : 
    1040          10 :         rc = nvme_driver_init();
    1041          10 :         if (rc != 0) {
    1042           1 :                 return NULL;
    1043             :         }
    1044             : 
    1045           9 :         nvme_get_default_hostnqn(hostnqn, sizeof(hostnqn));
    1046           9 :         if (opts) {
    1047           4 :                 opts_local_p = &opts_local;
    1048           4 :                 nvme_ctrlr_opts_init(opts_local_p, opts, opts_size);
    1049           4 :                 memcpy(hostnqn, opts_local.hostnqn, sizeof(hostnqn));
    1050             :         }
    1051             : 
    1052           9 :         probe_ctx = spdk_nvme_connect_async(trid, opts_local_p, NULL);
    1053           9 :         if (!probe_ctx) {
    1054           0 :                 SPDK_ERRLOG("Create probe context failed\n");
    1055           0 :                 return NULL;
    1056             :         }
    1057             : 
    1058           9 :         rc = nvme_init_controllers(probe_ctx);
    1059           9 :         if (rc != 0) {
    1060           0 :                 return NULL;
    1061             :         }
    1062             : 
    1063           9 :         ctrlr = nvme_get_ctrlr_by_trid(trid, hostnqn);
    1064             : 
    1065           9 :         return ctrlr;
    1066             : }
    1067             : 
    1068             : void
    1069          14 : spdk_nvme_trid_populate_transport(struct spdk_nvme_transport_id *trid,
    1070             :                                   enum spdk_nvme_transport_type trtype)
    1071             : {
    1072             :         const char *trstring;
    1073             : 
    1074          14 :         trid->trtype = trtype;
    1075          14 :         switch (trtype) {
    1076           0 :         case SPDK_NVME_TRANSPORT_FC:
    1077           0 :                 trstring = SPDK_NVME_TRANSPORT_NAME_FC;
    1078           0 :                 break;
    1079          14 :         case SPDK_NVME_TRANSPORT_PCIE:
    1080          14 :                 trstring = SPDK_NVME_TRANSPORT_NAME_PCIE;
    1081          14 :                 break;
    1082           0 :         case SPDK_NVME_TRANSPORT_RDMA:
    1083           0 :                 trstring = SPDK_NVME_TRANSPORT_NAME_RDMA;
    1084           0 :                 break;
    1085           0 :         case SPDK_NVME_TRANSPORT_TCP:
    1086           0 :                 trstring = SPDK_NVME_TRANSPORT_NAME_TCP;
    1087           0 :                 break;
    1088           0 :         case SPDK_NVME_TRANSPORT_VFIOUSER:
    1089           0 :                 trstring = SPDK_NVME_TRANSPORT_NAME_VFIOUSER;
    1090           0 :                 break;
    1091           0 :         case SPDK_NVME_TRANSPORT_CUSTOM:
    1092           0 :                 trstring = SPDK_NVME_TRANSPORT_NAME_CUSTOM;
    1093           0 :                 break;
    1094           0 :         default:
    1095           0 :                 SPDK_ERRLOG("no available transports\n");
    1096           0 :                 assert(0);
    1097             :                 return;
    1098             :         }
    1099          14 :         snprintf(trid->trstring, SPDK_NVMF_TRSTRING_MAX_LEN, "%s", trstring);
    1100             : }
    1101             : 
    1102             : int
    1103          11 : spdk_nvme_transport_id_populate_trstring(struct spdk_nvme_transport_id *trid, const char *trstring)
    1104             : {
    1105          11 :         int i = 0;
    1106             : 
    1107          11 :         if (trid == NULL || trstring == NULL) {
    1108           0 :                 return -EINVAL;
    1109             :         }
    1110             : 
    1111             :         /* Note: gcc-11 has some false positive -Wstringop-overread warnings with LTO builds if we
    1112             :          * use strnlen here.  So do the trstring copy manually instead.  See GitHub issue #2391.
    1113             :          */
    1114             : 
    1115             :         /* cast official trstring to uppercase version of input. */
    1116          54 :         while (i < SPDK_NVMF_TRSTRING_MAX_LEN && trstring[i] != 0) {
    1117          43 :                 trid->trstring[i] = toupper(trstring[i]);
    1118          43 :                 i++;
    1119             :         }
    1120             : 
    1121          11 :         if (trstring[i] != 0) {
    1122           0 :                 return -EINVAL;
    1123             :         } else {
    1124          11 :                 trid->trstring[i] = 0;
    1125          11 :                 return 0;
    1126             :         }
    1127             : }
    1128             : 
    1129             : int
    1130          22 : spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str)
    1131             : {
    1132          22 :         if (trtype == NULL || str == NULL) {
    1133           2 :                 return -EINVAL;
    1134             :         }
    1135             : 
    1136          20 :         if (strcasecmp(str, "PCIe") == 0) {
    1137          11 :                 *trtype = SPDK_NVME_TRANSPORT_PCIE;
    1138           9 :         } else if (strcasecmp(str, "RDMA") == 0) {
    1139           3 :                 *trtype = SPDK_NVME_TRANSPORT_RDMA;
    1140           6 :         } else if (strcasecmp(str, "FC") == 0) {
    1141           2 :                 *trtype = SPDK_NVME_TRANSPORT_FC;
    1142           4 :         } else if (strcasecmp(str, "TCP") == 0) {
    1143           3 :                 *trtype = SPDK_NVME_TRANSPORT_TCP;
    1144           1 :         } else if (strcasecmp(str, "VFIOUSER") == 0) {
    1145           0 :                 *trtype = SPDK_NVME_TRANSPORT_VFIOUSER;
    1146             :         } else {
    1147           1 :                 *trtype = SPDK_NVME_TRANSPORT_CUSTOM;
    1148             :         }
    1149          20 :         return 0;
    1150             : }
    1151             : 
    1152             : const char *
    1153           5 : spdk_nvme_transport_id_trtype_str(enum spdk_nvme_transport_type trtype)
    1154             : {
    1155           5 :         switch (trtype) {
    1156           1 :         case SPDK_NVME_TRANSPORT_PCIE:
    1157           1 :                 return "PCIe";
    1158           1 :         case SPDK_NVME_TRANSPORT_RDMA:
    1159           1 :                 return "RDMA";
    1160           1 :         case SPDK_NVME_TRANSPORT_FC:
    1161           1 :                 return "FC";
    1162           1 :         case SPDK_NVME_TRANSPORT_TCP:
    1163           1 :                 return "TCP";
    1164           0 :         case SPDK_NVME_TRANSPORT_VFIOUSER:
    1165           0 :                 return "VFIOUSER";
    1166           0 :         case SPDK_NVME_TRANSPORT_CUSTOM:
    1167           0 :                 return "CUSTOM";
    1168           1 :         default:
    1169           1 :                 return NULL;
    1170             :         }
    1171             : }
    1172             : 
    1173             : int
    1174          13 : spdk_nvme_transport_id_parse_adrfam(enum spdk_nvmf_adrfam *adrfam, const char *str)
    1175             : {
    1176          13 :         if (adrfam == NULL || str == NULL) {
    1177           2 :                 return -EINVAL;
    1178             :         }
    1179             : 
    1180          11 :         if (strcasecmp(str, "IPv4") == 0) {
    1181           4 :                 *adrfam = SPDK_NVMF_ADRFAM_IPV4;
    1182           7 :         } else if (strcasecmp(str, "IPv6") == 0) {
    1183           2 :                 *adrfam = SPDK_NVMF_ADRFAM_IPV6;
    1184           5 :         } else if (strcasecmp(str, "IB") == 0) {
    1185           2 :                 *adrfam = SPDK_NVMF_ADRFAM_IB;
    1186           3 :         } else if (strcasecmp(str, "FC") == 0) {
    1187           2 :                 *adrfam = SPDK_NVMF_ADRFAM_FC;
    1188             :         } else {
    1189           1 :                 return -ENOENT;
    1190             :         }
    1191          10 :         return 0;
    1192             : }
    1193             : 
    1194             : const char *
    1195           5 : spdk_nvme_transport_id_adrfam_str(enum spdk_nvmf_adrfam adrfam)
    1196             : {
    1197           5 :         switch (adrfam) {
    1198           1 :         case SPDK_NVMF_ADRFAM_IPV4:
    1199           1 :                 return "IPv4";
    1200           1 :         case SPDK_NVMF_ADRFAM_IPV6:
    1201           1 :                 return "IPv6";
    1202           1 :         case SPDK_NVMF_ADRFAM_IB:
    1203           1 :                 return "IB";
    1204           1 :         case SPDK_NVMF_ADRFAM_FC:
    1205           1 :                 return "FC";
    1206           1 :         default:
    1207           1 :                 return NULL;
    1208             :         }
    1209             : }
    1210             : 
    1211             : static size_t
    1212          38 : parse_next_key(const char **str, char *key, char *val, size_t key_buf_size, size_t val_buf_size)
    1213             : {
    1214             : 
    1215             :         const char *sep, *sep1;
    1216          38 :         const char *whitespace = " \t\n";
    1217             :         size_t key_len, val_len;
    1218             : 
    1219          38 :         *str += strspn(*str, whitespace);
    1220             : 
    1221          38 :         sep = strchr(*str, ':');
    1222          38 :         if (!sep) {
    1223           1 :                 sep = strchr(*str, '=');
    1224           1 :                 if (!sep) {
    1225           1 :                         SPDK_ERRLOG("Key without ':' or '=' separator\n");
    1226           1 :                         return 0;
    1227             :                 }
    1228             :         } else {
    1229          37 :                 sep1 = strchr(*str, '=');
    1230          37 :                 if ((sep1 != NULL) && (sep1 < sep)) {
    1231           4 :                         sep = sep1;
    1232             :                 }
    1233             :         }
    1234             : 
    1235          37 :         key_len = sep - *str;
    1236          37 :         if (key_len >= key_buf_size) {
    1237           1 :                 SPDK_ERRLOG("Key length %zu greater than maximum allowed %zu\n",
    1238             :                             key_len, key_buf_size - 1);
    1239           1 :                 return 0;
    1240             :         }
    1241             : 
    1242          36 :         memcpy(key, *str, key_len);
    1243          36 :         key[key_len] = '\0';
    1244             : 
    1245          36 :         *str += key_len + 1; /* Skip key: */
    1246          36 :         val_len = strcspn(*str, whitespace);
    1247          36 :         if (val_len == 0) {
    1248           1 :                 SPDK_ERRLOG("Key without value\n");
    1249           1 :                 return 0;
    1250             :         }
    1251             : 
    1252          35 :         if (val_len >= val_buf_size) {
    1253           0 :                 SPDK_ERRLOG("Value length %zu greater than maximum allowed %zu\n",
    1254             :                             val_len, val_buf_size - 1);
    1255           0 :                 return 0;
    1256             :         }
    1257             : 
    1258          35 :         memcpy(val, *str, val_len);
    1259          35 :         val[val_len] = '\0';
    1260             : 
    1261          35 :         *str += val_len;
    1262             : 
    1263          35 :         return val_len;
    1264             : }
    1265             : 
    1266             : int
    1267          17 : spdk_nvme_transport_id_parse(struct spdk_nvme_transport_id *trid, const char *str)
    1268             : {
    1269             :         size_t val_len;
    1270          17 :         char key[32];
    1271          17 :         char val[1024];
    1272             : 
    1273          17 :         if (trid == NULL || str == NULL) {
    1274           3 :                 return -EINVAL;
    1275             :         }
    1276             : 
    1277          43 :         while (*str != '\0') {
    1278             : 
    1279          32 :                 val_len = parse_next_key(&str, key, val, sizeof(key), sizeof(val));
    1280             : 
    1281          32 :                 if (val_len == 0) {
    1282           3 :                         SPDK_ERRLOG("Failed to parse transport ID\n");
    1283           3 :                         return -EINVAL;
    1284             :                 }
    1285             : 
    1286          29 :                 if (strcasecmp(key, "trtype") == 0) {
    1287          11 :                         if (spdk_nvme_transport_id_populate_trstring(trid, val) != 0) {
    1288           0 :                                 SPDK_ERRLOG("invalid transport '%s'\n", val);
    1289           0 :                                 return -EINVAL;
    1290             :                         }
    1291          11 :                         if (spdk_nvme_transport_id_parse_trtype(&trid->trtype, val) != 0) {
    1292           0 :                                 SPDK_ERRLOG("Unknown trtype '%s'\n", val);
    1293           0 :                                 return -EINVAL;
    1294             :                         }
    1295          18 :                 } else if (strcasecmp(key, "adrfam") == 0) {
    1296           2 :                         if (spdk_nvme_transport_id_parse_adrfam(&trid->adrfam, val) != 0) {
    1297           0 :                                 SPDK_ERRLOG("Unknown adrfam '%s'\n", val);
    1298           0 :                                 return -EINVAL;
    1299             :                         }
    1300          16 :                 } else if (strcasecmp(key, "traddr") == 0) {
    1301          11 :                         if (val_len > SPDK_NVMF_TRADDR_MAX_LEN) {
    1302           0 :                                 SPDK_ERRLOG("traddr length %zu greater than maximum allowed %u\n",
    1303             :                                             val_len, SPDK_NVMF_TRADDR_MAX_LEN);
    1304           0 :                                 return -EINVAL;
    1305             :                         }
    1306          11 :                         memcpy(trid->traddr, val, val_len + 1);
    1307           5 :                 } else if (strcasecmp(key, "trsvcid") == 0) {
    1308           2 :                         if (val_len > SPDK_NVMF_TRSVCID_MAX_LEN) {
    1309           0 :                                 SPDK_ERRLOG("trsvcid length %zu greater than maximum allowed %u\n",
    1310             :                                             val_len, SPDK_NVMF_TRSVCID_MAX_LEN);
    1311           0 :                                 return -EINVAL;
    1312             :                         }
    1313           2 :                         memcpy(trid->trsvcid, val, val_len + 1);
    1314           3 :                 } else if (strcasecmp(key, "priority") == 0) {
    1315           1 :                         if (val_len > SPDK_NVMF_PRIORITY_MAX_LEN) {
    1316           0 :                                 SPDK_ERRLOG("priority length %zu greater than maximum allowed %u\n",
    1317             :                                             val_len, SPDK_NVMF_PRIORITY_MAX_LEN);
    1318           0 :                                 return -EINVAL;
    1319             :                         }
    1320           1 :                         trid->priority = spdk_strtol(val, 10);
    1321           2 :                 } else if (strcasecmp(key, "subnqn") == 0) {
    1322           2 :                         if (val_len > SPDK_NVMF_NQN_MAX_LEN) {
    1323           0 :                                 SPDK_ERRLOG("subnqn length %zu greater than maximum allowed %u\n",
    1324             :                                             val_len, SPDK_NVMF_NQN_MAX_LEN);
    1325           0 :                                 return -EINVAL;
    1326             :                         }
    1327           2 :                         memcpy(trid->subnqn, val, val_len + 1);
    1328           0 :                 } else if (strcasecmp(key, "hostaddr") == 0) {
    1329           0 :                         continue;
    1330           0 :                 } else if (strcasecmp(key, "hostsvcid") == 0) {
    1331           0 :                         continue;
    1332           0 :                 } else if (strcasecmp(key, "hostnqn") == 0) {
    1333           0 :                         continue;
    1334           0 :                 } else if (strcasecmp(key, "ns") == 0) {
    1335             :                         /*
    1336             :                          * Special case.  The namespace id parameter may
    1337             :                          * optionally be passed in the transport id string
    1338             :                          * for an SPDK application (e.g. spdk_nvme_perf)
    1339             :                          * and additionally parsed therein to limit
    1340             :                          * targeting a specific namespace.  For this
    1341             :                          * scenario, just silently ignore this key
    1342             :                          * rather than letting it default to logging
    1343             :                          * it as an invalid key.
    1344             :                          */
    1345           0 :                         continue;
    1346           0 :                 } else if (strcasecmp(key, "alt_traddr") == 0) {
    1347             :                         /*
    1348             :                          * Used by applications for enabling transport ID failover.
    1349             :                          * Please see the case above for more information on custom parameters.
    1350             :                          */
    1351           0 :                         continue;
    1352             :                 } else {
    1353           0 :                         SPDK_ERRLOG("Unknown transport ID key '%s'\n", key);
    1354             :                 }
    1355             :         }
    1356             : 
    1357          11 :         return 0;
    1358             : }
    1359             : 
    1360             : int
    1361           3 : spdk_nvme_host_id_parse(struct spdk_nvme_host_id *hostid, const char *str)
    1362           3 : {
    1363             : 
    1364           3 :         size_t key_size = 32;
    1365           3 :         size_t val_size = 1024;
    1366             :         size_t val_len;
    1367           3 :         char key[key_size];
    1368           3 :         char val[val_size];
    1369             : 
    1370           3 :         if (hostid == NULL || str == NULL) {
    1371           0 :                 return -EINVAL;
    1372             :         }
    1373             : 
    1374           6 :         while (*str != '\0') {
    1375             : 
    1376           3 :                 val_len = parse_next_key(&str, key, val, key_size, val_size);
    1377             : 
    1378           3 :                 if (val_len == 0) {
    1379           0 :                         SPDK_ERRLOG("Failed to parse host ID\n");
    1380           0 :                         return val_len;
    1381             :                 }
    1382             : 
    1383             :                 /* Ignore the rest of the options from the transport ID. */
    1384           3 :                 if (strcasecmp(key, "trtype") == 0) {
    1385           1 :                         continue;
    1386           2 :                 } else if (strcasecmp(key, "adrfam") == 0) {
    1387           0 :                         continue;
    1388           2 :                 } else if (strcasecmp(key, "traddr") == 0) {
    1389           0 :                         continue;
    1390           2 :                 } else if (strcasecmp(key, "trsvcid") == 0) {
    1391           0 :                         continue;
    1392           2 :                 } else if (strcasecmp(key, "subnqn") == 0) {
    1393           0 :                         continue;
    1394           2 :                 } else if (strcasecmp(key, "priority") == 0) {
    1395           0 :                         continue;
    1396           2 :                 } else if (strcasecmp(key, "ns") == 0) {
    1397           0 :                         continue;
    1398           2 :                 } else if (strcasecmp(key, "hostaddr") == 0) {
    1399           1 :                         if (val_len > SPDK_NVMF_TRADDR_MAX_LEN) {
    1400           0 :                                 SPDK_ERRLOG("hostaddr length %zu greater than maximum allowed %u\n",
    1401             :                                             val_len, SPDK_NVMF_TRADDR_MAX_LEN);
    1402           0 :                                 return -EINVAL;
    1403             :                         }
    1404           1 :                         memcpy(hostid->hostaddr, val, val_len + 1);
    1405             : 
    1406           1 :                 } else if (strcasecmp(key, "hostsvcid") == 0) {
    1407           1 :                         if (val_len > SPDK_NVMF_TRSVCID_MAX_LEN) {
    1408           0 :                                 SPDK_ERRLOG("trsvcid length %zu greater than maximum allowed %u\n",
    1409             :                                             val_len, SPDK_NVMF_TRSVCID_MAX_LEN);
    1410           0 :                                 return -EINVAL;
    1411             :                         }
    1412           1 :                         memcpy(hostid->hostsvcid, val, val_len + 1);
    1413             :                 } else {
    1414           0 :                         SPDK_ERRLOG("Unknown transport ID key '%s'\n", key);
    1415             :                 }
    1416             :         }
    1417             : 
    1418           3 :         return 0;
    1419             : }
    1420             : 
    1421             : static int
    1422          37 : cmp_int(int a, int b)
    1423             : {
    1424          37 :         return a - b;
    1425             : }
    1426             : 
    1427             : int
    1428          30 : spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1,
    1429             :                                const struct spdk_nvme_transport_id *trid2)
    1430             : {
    1431             :         int cmp;
    1432             : 
    1433          30 :         if (trid1->trtype == SPDK_NVME_TRANSPORT_CUSTOM) {
    1434           0 :                 cmp = strcasecmp(trid1->trstring, trid2->trstring);
    1435             :         } else {
    1436          30 :                 cmp = cmp_int(trid1->trtype, trid2->trtype);
    1437             :         }
    1438             : 
    1439          30 :         if (cmp) {
    1440           1 :                 return cmp;
    1441             :         }
    1442             : 
    1443          29 :         if (trid1->trtype == SPDK_NVME_TRANSPORT_PCIE) {
    1444          21 :                 struct spdk_pci_addr pci_addr1 = {};
    1445          21 :                 struct spdk_pci_addr pci_addr2 = {};
    1446             : 
    1447             :                 /* Normalize PCI addresses before comparing */
    1448          42 :                 if (spdk_pci_addr_parse(&pci_addr1, trid1->traddr) < 0 ||
    1449          21 :                     spdk_pci_addr_parse(&pci_addr2, trid2->traddr) < 0) {
    1450           0 :                         return -1;
    1451             :                 }
    1452             : 
    1453             :                 /* PCIe transport ID only uses trtype and traddr */
    1454          21 :                 return spdk_pci_addr_compare(&pci_addr1, &pci_addr2);
    1455             :         }
    1456             : 
    1457           8 :         cmp = strcasecmp(trid1->traddr, trid2->traddr);
    1458           8 :         if (cmp) {
    1459           1 :                 return cmp;
    1460             :         }
    1461             : 
    1462           7 :         cmp = cmp_int(trid1->adrfam, trid2->adrfam);
    1463           7 :         if (cmp) {
    1464           1 :                 return cmp;
    1465             :         }
    1466             : 
    1467           6 :         cmp = strcasecmp(trid1->trsvcid, trid2->trsvcid);
    1468           6 :         if (cmp) {
    1469           1 :                 return cmp;
    1470             :         }
    1471             : 
    1472           5 :         cmp = strcmp(trid1->subnqn, trid2->subnqn);
    1473           5 :         if (cmp) {
    1474           2 :                 return cmp;
    1475             :         }
    1476             : 
    1477           3 :         return 0;
    1478             : }
    1479             : 
    1480             : int
    1481           4 : spdk_nvme_prchk_flags_parse(uint32_t *prchk_flags, const char *str)
    1482             : {
    1483             :         size_t val_len;
    1484           4 :         char key[32];
    1485           4 :         char val[1024];
    1486             : 
    1487           4 :         if (prchk_flags == NULL || str == NULL) {
    1488           1 :                 return -EINVAL;
    1489             :         }
    1490             : 
    1491           9 :         while (*str != '\0') {
    1492           3 :                 val_len = parse_next_key(&str, key, val, sizeof(key), sizeof(val));
    1493             : 
    1494           3 :                 if (val_len == 0) {
    1495           0 :                         SPDK_ERRLOG("Failed to parse prchk\n");
    1496           0 :                         return -EINVAL;
    1497             :                 }
    1498             : 
    1499           3 :                 if (strcasecmp(key, "prchk") == 0) {
    1500           3 :                         if (strcasestr(val, "reftag") != NULL) {
    1501           2 :                                 *prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_REFTAG;
    1502             :                         }
    1503           3 :                         if (strcasestr(val, "guard") != NULL) {
    1504           2 :                                 *prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_GUARD;
    1505             :                         }
    1506             :                 } else {
    1507           0 :                         SPDK_ERRLOG("Unknown key '%s'\n", key);
    1508           0 :                         return -EINVAL;
    1509             :                 }
    1510             :         }
    1511             : 
    1512           3 :         return 0;
    1513             : }
    1514             : 
    1515             : const char *
    1516           3 : spdk_nvme_prchk_flags_str(uint32_t prchk_flags)
    1517             : {
    1518           3 :         if (prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_REFTAG) {
    1519           2 :                 if (prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_GUARD) {
    1520           1 :                         return "prchk:reftag|guard";
    1521             :                 } else {
    1522           1 :                         return "prchk:reftag";
    1523             :                 }
    1524             :         } else {
    1525           1 :                 if (prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_GUARD) {
    1526           1 :                         return "prchk:guard";
    1527             :                 } else {
    1528           0 :                         return NULL;
    1529             :                 }
    1530             :         }
    1531             : }
    1532             : 
    1533             : int
    1534           0 : spdk_nvme_scan_attached(const struct spdk_nvme_transport_id *trid)
    1535             : {
    1536             :         int rc;
    1537             :         struct spdk_nvme_probe_ctx *probe_ctx;
    1538             : 
    1539           0 :         rc = nvme_driver_init();
    1540           0 :         if (rc != 0) {
    1541           0 :                 return rc;
    1542             :         }
    1543             : 
    1544           0 :         probe_ctx = calloc(1, sizeof(*probe_ctx));
    1545           0 :         if (!probe_ctx) {
    1546           0 :                 return -ENOMEM;
    1547             :         }
    1548             : 
    1549           0 :         nvme_probe_ctx_init(probe_ctx, trid, NULL, NULL, NULL, NULL, NULL, NULL);
    1550             : 
    1551           0 :         nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
    1552           0 :         rc = nvme_transport_ctrlr_scan_attached(probe_ctx);
    1553           0 :         nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
    1554           0 :         free(probe_ctx);
    1555             : 
    1556           0 :         return rc < 0 ? rc : 0;
    1557             : }
    1558             : 
    1559             : struct spdk_nvme_probe_ctx *
    1560           0 : spdk_nvme_probe_async(const struct spdk_nvme_transport_id *trid,
    1561             :                       void *cb_ctx,
    1562             :                       spdk_nvme_probe_cb probe_cb,
    1563             :                       spdk_nvme_attach_cb attach_cb,
    1564             :                       spdk_nvme_remove_cb remove_cb)
    1565             : {
    1566           0 :         return spdk_nvme_probe_async_ext(trid, cb_ctx, probe_cb, attach_cb, NULL, remove_cb);
    1567             : }
    1568             : 
    1569             : struct spdk_nvme_probe_ctx *
    1570           4 : spdk_nvme_probe_async_ext(const struct spdk_nvme_transport_id *trid,
    1571             :                           void *cb_ctx,
    1572             :                           spdk_nvme_probe_cb probe_cb,
    1573             :                           spdk_nvme_attach_cb attach_cb,
    1574             :                           spdk_nvme_attach_fail_cb attach_fail_cb,
    1575             :                           spdk_nvme_remove_cb remove_cb)
    1576             : {
    1577             :         int rc;
    1578             :         struct spdk_nvme_probe_ctx *probe_ctx;
    1579             : 
    1580           4 :         rc = nvme_driver_init();
    1581           4 :         if (rc != 0) {
    1582           1 :                 return NULL;
    1583             :         }
    1584             : 
    1585           3 :         probe_ctx = calloc(1, sizeof(*probe_ctx));
    1586           3 :         if (!probe_ctx) {
    1587           0 :                 return NULL;
    1588             :         }
    1589             : 
    1590           3 :         nvme_probe_ctx_init(probe_ctx, trid, NULL, cb_ctx, probe_cb, attach_cb, attach_fail_cb,
    1591             :                             remove_cb);
    1592           3 :         rc = nvme_probe_internal(probe_ctx, false);
    1593           3 :         if (rc != 0) {
    1594           1 :                 free(probe_ctx);
    1595           1 :                 return NULL;
    1596             :         }
    1597             : 
    1598           2 :         return probe_ctx;
    1599             : }
    1600             : 
    1601             : int
    1602          14 : spdk_nvme_probe_poll_async(struct spdk_nvme_probe_ctx *probe_ctx)
    1603             : {
    1604             :         struct spdk_nvme_ctrlr *ctrlr, *ctrlr_tmp;
    1605             : 
    1606          14 :         if (!spdk_process_is_primary() && probe_ctx->trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
    1607           7 :                 free(probe_ctx);
    1608           7 :                 return 0;
    1609             :         }
    1610             : 
    1611          10 :         TAILQ_FOREACH_SAFE(ctrlr, &probe_ctx->init_ctrlrs, tailq, ctrlr_tmp) {
    1612           3 :                 nvme_ctrlr_poll_internal(ctrlr, probe_ctx);
    1613             :         }
    1614             : 
    1615           7 :         if (TAILQ_EMPTY(&probe_ctx->init_ctrlrs)) {
    1616           7 :                 nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
    1617           7 :                 g_spdk_nvme_driver->initialized = true;
    1618           7 :                 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
    1619           7 :                 free(probe_ctx);
    1620           7 :                 return 0;
    1621             :         }
    1622             : 
    1623           0 :         return -EAGAIN;
    1624             : }
    1625             : 
    1626             : struct spdk_nvme_probe_ctx *
    1627           9 : spdk_nvme_connect_async(const struct spdk_nvme_transport_id *trid,
    1628             :                         const struct spdk_nvme_ctrlr_opts *opts,
    1629             :                         spdk_nvme_attach_cb attach_cb)
    1630             : {
    1631             :         int rc;
    1632           9 :         spdk_nvme_probe_cb probe_cb = NULL;
    1633             :         struct spdk_nvme_probe_ctx *probe_ctx;
    1634             : 
    1635           9 :         rc = nvme_driver_init();
    1636           9 :         if (rc != 0) {
    1637           0 :                 return NULL;
    1638             :         }
    1639             : 
    1640           9 :         probe_ctx = calloc(1, sizeof(*probe_ctx));
    1641           9 :         if (!probe_ctx) {
    1642           0 :                 return NULL;
    1643             :         }
    1644             : 
    1645           9 :         if (opts) {
    1646           4 :                 probe_cb = nvme_connect_probe_cb;
    1647             :         }
    1648             : 
    1649           9 :         nvme_probe_ctx_init(probe_ctx, trid, opts, (void *)opts, probe_cb, attach_cb, NULL, NULL);
    1650           9 :         rc = nvme_probe_internal(probe_ctx, true);
    1651           9 :         if (rc != 0) {
    1652           0 :                 free(probe_ctx);
    1653           0 :                 return NULL;
    1654             :         }
    1655             : 
    1656           9 :         return probe_ctx;
    1657             : }
    1658             : 
    1659             : int
    1660           2 : nvme_parse_addr(struct sockaddr_storage *sa, int family, const char *addr, const char *service,
    1661             :                 long int *port)
    1662             : {
    1663           2 :         struct addrinfo *res;
    1664           2 :         struct addrinfo hints;
    1665             :         int ret;
    1666             : 
    1667           2 :         memset(&hints, 0, sizeof(hints));
    1668           2 :         hints.ai_family = family;
    1669           2 :         hints.ai_socktype = SOCK_STREAM;
    1670           2 :         hints.ai_protocol = 0;
    1671             : 
    1672           2 :         if (service != NULL) {
    1673           1 :                 *port = spdk_strtol(service, 10);
    1674           1 :                 if (*port <= 0 || *port >= 65536) {
    1675           0 :                         SPDK_ERRLOG("Invalid port: %s\n", service);
    1676           0 :                         return -EINVAL;
    1677             :                 }
    1678             :         }
    1679             : 
    1680           2 :         ret = getaddrinfo(addr, service, &hints, &res);
    1681           2 :         if (ret) {
    1682           1 :                 SPDK_ERRLOG("getaddrinfo failed: %s (%d)\n", gai_strerror(ret), ret);
    1683           1 :                 return -(abs(ret));
    1684             :         }
    1685             : 
    1686           1 :         if (res->ai_addrlen > sizeof(*sa)) {
    1687           0 :                 SPDK_ERRLOG("getaddrinfo() ai_addrlen %zu too large\n", (size_t)res->ai_addrlen);
    1688           0 :                 ret = -EINVAL;
    1689             :         } else {
    1690           1 :                 memcpy(sa, res->ai_addr, res->ai_addrlen);
    1691             :         }
    1692             : 
    1693           1 :         freeaddrinfo(res);
    1694           1 :         return ret;
    1695             : }
    1696             : 
    1697             : int
    1698          23 : nvme_get_default_hostnqn(char *buf, int len)
    1699             : {
    1700          23 :         char uuid[SPDK_UUID_STRING_LEN];
    1701             :         int rc;
    1702             : 
    1703          23 :         spdk_uuid_fmt_lower(uuid, sizeof(uuid), &g_spdk_nvme_driver->default_extended_host_id);
    1704          23 :         rc = snprintf(buf, len, "nqn.2014-08.org.nvmexpress:uuid:%s", uuid);
    1705          23 :         if (rc < 0 || rc >= len) {
    1706           0 :                 return -EINVAL;
    1707             :         }
    1708             : 
    1709          23 :         return 0;
    1710             : }
    1711             : 
    1712           3 : SPDK_LOG_REGISTER_COMPONENT(nvme)

Generated by: LCOV version 1.15