LCOV - code coverage report
Current view: top level - lib/nvme - nvme_fabric.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 135 324 41.7 %
Date: 2024-12-06 01:28:43 Functions: 9 24 37.5 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2018 Intel Corporation. All rights reserved.
       3             :  *   Copyright (c) 2020 Mellanox Technologies LTD. All rights reserved.
       4             :  *   Copyright (c) 2021, 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
       5             :  */
       6             : 
       7             : /*
       8             :  * NVMe over Fabrics transport-independent functions
       9             :  */
      10             : 
      11             : #include "nvme_internal.h"
      12             : 
      13             : #include "spdk/endian.h"
      14             : #include "spdk/string.h"
      15             : 
      16             : struct nvme_fabric_prop_ctx {
      17             :         uint64_t                value;
      18             :         int                     size;
      19             :         spdk_nvme_reg_cb        cb_fn;
      20             :         void                    *cb_arg;
      21             : };
      22             : 
      23             : static int
      24           1 : nvme_fabric_prop_set_cmd(struct spdk_nvme_ctrlr *ctrlr,
      25             :                          uint32_t offset, uint8_t size, uint64_t value,
      26             :                          spdk_nvme_cmd_cb cb_fn, void *cb_arg)
      27             : {
      28           1 :         struct spdk_nvmf_fabric_prop_set_cmd cmd = {};
      29             : 
      30           1 :         assert(size == SPDK_NVMF_PROP_SIZE_4 || size == SPDK_NVMF_PROP_SIZE_8);
      31             : 
      32           1 :         cmd.opcode = SPDK_NVME_OPC_FABRIC;
      33           1 :         cmd.fctype = SPDK_NVMF_FABRIC_COMMAND_PROPERTY_SET;
      34           1 :         cmd.ofst = offset;
      35           1 :         cmd.attrib.size = size;
      36           1 :         cmd.value.u64 = value;
      37             : 
      38           1 :         return spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, (struct spdk_nvme_cmd *)&cmd,
      39             :                                              NULL, 0, cb_fn, cb_arg);
      40             : }
      41             : 
      42             : static int
      43           1 : nvme_fabric_prop_set_cmd_sync(struct spdk_nvme_ctrlr *ctrlr,
      44             :                               uint32_t offset, uint8_t size, uint64_t value)
      45             : {
      46             :         struct nvme_completion_poll_status *status;
      47             :         int rc;
      48             : 
      49           1 :         status = calloc(1, sizeof(*status));
      50           1 :         if (!status) {
      51           0 :                 SPDK_ERRLOG("Failed to allocate status tracker\n");
      52           0 :                 return -ENOMEM;
      53             :         }
      54             : 
      55           1 :         rc = nvme_fabric_prop_set_cmd(ctrlr, offset, size, value,
      56             :                                       nvme_completion_poll_cb, status);
      57           1 :         if (rc < 0) {
      58           0 :                 free(status);
      59           0 :                 return rc;
      60             :         }
      61             : 
      62           1 :         if (nvme_wait_for_completion_robust_lock(ctrlr->adminq, status, &ctrlr->ctrlr_lock)) {
      63           0 :                 if (!status->timed_out) {
      64           0 :                         free(status);
      65             :                 }
      66           0 :                 SPDK_ERRLOG("Property Set failed\n");
      67           0 :                 return -1;
      68             :         }
      69           1 :         free(status);
      70             : 
      71           1 :         return 0;
      72             : }
      73             : 
      74             : static void
      75           0 : nvme_fabric_prop_set_cmd_done(void *ctx, const struct spdk_nvme_cpl *cpl)
      76             : {
      77           0 :         struct nvme_fabric_prop_ctx *prop_ctx = ctx;
      78             : 
      79           0 :         prop_ctx->cb_fn(prop_ctx->cb_arg, prop_ctx->value, cpl);
      80           0 :         free(prop_ctx);
      81           0 : }
      82             : 
      83             : static int
      84           0 : nvme_fabric_prop_set_cmd_async(struct spdk_nvme_ctrlr *ctrlr,
      85             :                                uint32_t offset, uint8_t size, uint64_t value,
      86             :                                spdk_nvme_reg_cb cb_fn, void *cb_arg)
      87             : {
      88             :         struct nvme_fabric_prop_ctx *ctx;
      89             :         int rc;
      90             : 
      91           0 :         ctx = calloc(1, sizeof(*ctx));
      92           0 :         if (ctx == NULL) {
      93           0 :                 SPDK_ERRLOG("Failed to allocate fabrics property context\n");
      94           0 :                 return -ENOMEM;
      95             :         }
      96             : 
      97           0 :         ctx->value = value;
      98           0 :         ctx->cb_fn = cb_fn;
      99           0 :         ctx->cb_arg = cb_arg;
     100             : 
     101           0 :         rc = nvme_fabric_prop_set_cmd(ctrlr, offset, size, value,
     102             :                                       nvme_fabric_prop_set_cmd_done, ctx);
     103           0 :         if (rc != 0) {
     104           0 :                 SPDK_ERRLOG("Failed to send Property Set fabrics command\n");
     105           0 :                 free(ctx);
     106             :         }
     107             : 
     108           0 :         return rc;
     109             : }
     110             : 
     111             : static int
     112           2 : nvme_fabric_prop_get_cmd(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint8_t size,
     113             :                          spdk_nvme_cmd_cb cb_fn, void *cb_arg)
     114             : {
     115           2 :         struct spdk_nvmf_fabric_prop_set_cmd cmd = {};
     116             : 
     117           2 :         assert(size == SPDK_NVMF_PROP_SIZE_4 || size == SPDK_NVMF_PROP_SIZE_8);
     118             : 
     119           2 :         cmd.opcode = SPDK_NVME_OPC_FABRIC;
     120           2 :         cmd.fctype = SPDK_NVMF_FABRIC_COMMAND_PROPERTY_GET;
     121           2 :         cmd.ofst = offset;
     122           2 :         cmd.attrib.size = size;
     123             : 
     124           2 :         return spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, (struct spdk_nvme_cmd *)&cmd,
     125             :                                              NULL, 0, cb_fn, cb_arg);
     126             : }
     127             : 
     128             : static int
     129           2 : nvme_fabric_prop_get_cmd_sync(struct spdk_nvme_ctrlr *ctrlr,
     130             :                               uint32_t offset, uint8_t size, uint64_t *value)
     131             : {
     132             :         struct nvme_completion_poll_status *status;
     133             :         struct spdk_nvmf_fabric_prop_get_rsp *response;
     134             :         int rc;
     135             : 
     136           2 :         status = calloc(1, sizeof(*status));
     137           2 :         if (!status) {
     138           0 :                 SPDK_ERRLOG("Failed to allocate status tracker\n");
     139           0 :                 return -ENOMEM;
     140             :         }
     141             : 
     142           2 :         rc = nvme_fabric_prop_get_cmd(ctrlr, offset, size, nvme_completion_poll_cb, status);
     143           2 :         if (rc < 0) {
     144           0 :                 free(status);
     145           0 :                 return rc;
     146             :         }
     147             : 
     148           2 :         if (nvme_wait_for_completion_robust_lock(ctrlr->adminq, status, &ctrlr->ctrlr_lock)) {
     149           0 :                 if (!status->timed_out) {
     150           0 :                         free(status);
     151             :                 }
     152           0 :                 SPDK_ERRLOG("Property Get failed, offset %x, size %u\n", offset, size);
     153           0 :                 return -1;
     154             :         }
     155             : 
     156           2 :         response = (struct spdk_nvmf_fabric_prop_get_rsp *)&status->cpl;
     157             : 
     158           2 :         if (size == SPDK_NVMF_PROP_SIZE_4) {
     159           1 :                 *value = response->value.u32.low;
     160             :         } else {
     161           1 :                 *value = response->value.u64;
     162             :         }
     163             : 
     164           2 :         free(status);
     165             : 
     166           2 :         return 0;
     167             : }
     168             : 
     169             : static void
     170           0 : nvme_fabric_prop_get_cmd_done(void *ctx, const struct spdk_nvme_cpl *cpl)
     171             : {
     172           0 :         struct nvme_fabric_prop_ctx *prop_ctx = ctx;
     173             :         struct spdk_nvmf_fabric_prop_get_rsp *response;
     174           0 :         uint64_t value = 0;
     175             : 
     176           0 :         if (spdk_nvme_cpl_is_success(cpl)) {
     177           0 :                 response = (struct spdk_nvmf_fabric_prop_get_rsp *)cpl;
     178             : 
     179           0 :                 switch (prop_ctx->size) {
     180           0 :                 case SPDK_NVMF_PROP_SIZE_4:
     181           0 :                         value = response->value.u32.low;
     182           0 :                         break;
     183           0 :                 case SPDK_NVMF_PROP_SIZE_8:
     184           0 :                         value = response->value.u64;
     185           0 :                         break;
     186           0 :                 default:
     187           0 :                         assert(0 && "Should never happen");
     188             :                 }
     189             :         }
     190             : 
     191           0 :         prop_ctx->cb_fn(prop_ctx->cb_arg, value, cpl);
     192           0 :         free(prop_ctx);
     193           0 : }
     194             : 
     195             : static int
     196           0 : nvme_fabric_prop_get_cmd_async(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint8_t size,
     197             :                                spdk_nvme_reg_cb cb_fn, void *cb_arg)
     198             : {
     199             :         struct nvme_fabric_prop_ctx *ctx;
     200             :         int rc;
     201             : 
     202           0 :         ctx = calloc(1, sizeof(*ctx));
     203           0 :         if (ctx == NULL) {
     204           0 :                 SPDK_ERRLOG("Failed to allocate fabrics property context\n");
     205           0 :                 return -ENOMEM;
     206             :         }
     207             : 
     208           0 :         ctx->size = size;
     209           0 :         ctx->cb_fn = cb_fn;
     210           0 :         ctx->cb_arg = cb_arg;
     211             : 
     212           0 :         rc = nvme_fabric_prop_get_cmd(ctrlr, offset, size, nvme_fabric_prop_get_cmd_done, ctx);
     213           0 :         if (rc != 0) {
     214           0 :                 SPDK_ERRLOG("Failed to send Property Get fabrics command\n");
     215           0 :                 free(ctx);
     216             :         }
     217             : 
     218           0 :         return rc;
     219             : }
     220             : 
     221             : int
     222           0 : nvme_fabric_ctrlr_set_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t value)
     223             : {
     224           0 :         return nvme_fabric_prop_set_cmd_sync(ctrlr, offset, SPDK_NVMF_PROP_SIZE_4, value);
     225             : }
     226             : 
     227             : int
     228           0 : nvme_fabric_ctrlr_set_reg_8(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint64_t value)
     229             : {
     230           0 :         return nvme_fabric_prop_set_cmd_sync(ctrlr, offset, SPDK_NVMF_PROP_SIZE_8, value);
     231             : }
     232             : 
     233             : int
     234           0 : nvme_fabric_ctrlr_get_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t *value)
     235             : {
     236           0 :         uint64_t tmp_value;
     237             :         int rc;
     238           0 :         rc = nvme_fabric_prop_get_cmd_sync(ctrlr, offset, SPDK_NVMF_PROP_SIZE_4, &tmp_value);
     239             : 
     240           0 :         if (!rc) {
     241           0 :                 *value = (uint32_t)tmp_value;
     242             :         }
     243           0 :         return rc;
     244             : }
     245             : 
     246             : int
     247           0 : nvme_fabric_ctrlr_get_reg_8(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint64_t *value)
     248             : {
     249           0 :         return nvme_fabric_prop_get_cmd_sync(ctrlr, offset, SPDK_NVMF_PROP_SIZE_8, value);
     250             : }
     251             : 
     252             : int
     253           0 : nvme_fabric_ctrlr_set_reg_4_async(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset,
     254             :                                   uint32_t value, spdk_nvme_reg_cb cb_fn, void *cb_arg)
     255             : {
     256           0 :         return nvme_fabric_prop_set_cmd_async(ctrlr, offset, SPDK_NVMF_PROP_SIZE_4, value,
     257             :                                               cb_fn, cb_arg);
     258             : }
     259             : 
     260             : int
     261           0 : nvme_fabric_ctrlr_set_reg_8_async(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset,
     262             :                                   uint64_t value, spdk_nvme_reg_cb cb_fn, void *cb_arg)
     263             : {
     264           0 :         return nvme_fabric_prop_set_cmd_async(ctrlr, offset, SPDK_NVMF_PROP_SIZE_8, value,
     265             :                                               cb_fn, cb_arg);
     266             : }
     267             : 
     268             : int
     269           0 : nvme_fabric_ctrlr_get_reg_4_async(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset,
     270             :                                   spdk_nvme_reg_cb cb_fn, void *cb_arg)
     271             : {
     272           0 :         return nvme_fabric_prop_get_cmd_async(ctrlr, offset, SPDK_NVMF_PROP_SIZE_4, cb_fn, cb_arg);
     273             : }
     274             : 
     275             : int
     276           0 : nvme_fabric_ctrlr_get_reg_8_async(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset,
     277             :                                   spdk_nvme_reg_cb cb_fn, void *cb_arg)
     278             : {
     279           0 :         return nvme_fabric_prop_get_cmd_async(ctrlr, offset, SPDK_NVMF_PROP_SIZE_8, cb_fn, cb_arg);
     280             : }
     281             : 
     282             : static void
     283           3 : nvme_fabric_discover_probe(struct spdk_nvmf_discovery_log_page_entry *entry,
     284             :                            struct spdk_nvme_probe_ctx *probe_ctx,
     285             :                            int discover_priority)
     286             : {
     287           3 :         struct spdk_nvme_transport_id trid;
     288             :         uint8_t *end;
     289             :         size_t len;
     290             : 
     291           3 :         memset(&trid, 0, sizeof(trid));
     292             : 
     293           3 :         if (entry->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY_CURRENT ||
     294           1 :             entry->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY) {
     295           2 :                 SPDK_WARNLOG("Skipping unsupported current discovery service or"
     296             :                              " discovery service referral\n");
     297           2 :                 return;
     298           1 :         } else if (entry->subtype != SPDK_NVMF_SUBTYPE_NVME) {
     299           0 :                 SPDK_WARNLOG("Skipping unknown subtype %u\n", entry->subtype);
     300           0 :                 return;
     301             :         }
     302             : 
     303           1 :         trid.trtype = entry->trtype;
     304           1 :         spdk_nvme_transport_id_populate_trstring(&trid, spdk_nvme_transport_id_trtype_str(entry->trtype));
     305           1 :         if (!spdk_nvme_transport_available_by_name(trid.trstring)) {
     306           0 :                 SPDK_WARNLOG("NVMe transport type %u not available; skipping probe\n",
     307             :                              trid.trtype);
     308           0 :                 return;
     309             :         }
     310             : 
     311           1 :         trid.adrfam = entry->adrfam;
     312             : 
     313             :         /* Ensure that subnqn is null terminated. */
     314           1 :         end = memchr(entry->subnqn, '\0', SPDK_NVMF_NQN_MAX_LEN + 1);
     315           1 :         if (!end) {
     316           0 :                 SPDK_ERRLOG("Discovery entry SUBNQN is not null terminated\n");
     317           0 :                 return;
     318             :         }
     319           1 :         len = end - entry->subnqn;
     320           1 :         memcpy(trid.subnqn, entry->subnqn, len);
     321           1 :         trid.subnqn[len] = '\0';
     322             : 
     323             :         /* Convert traddr to a null terminated string. */
     324           1 :         len = spdk_strlen_pad(entry->traddr, sizeof(entry->traddr), ' ');
     325           1 :         memcpy(trid.traddr, entry->traddr, len);
     326           1 :         if (spdk_str_chomp(trid.traddr) != 0) {
     327           0 :                 SPDK_DEBUGLOG(nvme, "Trailing newlines removed from discovery TRADDR\n");
     328             :         }
     329             : 
     330             :         /* Convert trsvcid to a null terminated string. */
     331           1 :         len = spdk_strlen_pad(entry->trsvcid, sizeof(entry->trsvcid), ' ');
     332           1 :         memcpy(trid.trsvcid, entry->trsvcid, len);
     333           1 :         if (spdk_str_chomp(trid.trsvcid) != 0) {
     334           0 :                 SPDK_DEBUGLOG(nvme, "Trailing newlines removed from discovery TRSVCID\n");
     335             :         }
     336             : 
     337           1 :         SPDK_DEBUGLOG(nvme, "subnqn=%s, trtype=%u, traddr=%s, trsvcid=%s\n",
     338             :                       trid.subnqn, trid.trtype,
     339             :                       trid.traddr, trid.trsvcid);
     340             : 
     341             :         /* Copy the priority from the discovery ctrlr */
     342           1 :         trid.priority = discover_priority;
     343             : 
     344           1 :         nvme_ctrlr_probe(&trid, probe_ctx, NULL);
     345             : }
     346             : 
     347             : static int
     348           3 : nvme_fabric_get_discovery_log_page(struct spdk_nvme_ctrlr *ctrlr,
     349             :                                    void *log_page, uint32_t size, uint64_t offset)
     350             : {
     351             :         struct nvme_completion_poll_status *status;
     352             :         int rc;
     353             : 
     354           3 :         status = calloc(1, sizeof(*status));
     355           3 :         if (!status) {
     356           0 :                 SPDK_ERRLOG("Failed to allocate status tracker\n");
     357           0 :                 return -ENOMEM;
     358             :         }
     359             : 
     360           3 :         rc = spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_LOG_DISCOVERY, 0, log_page, size, offset,
     361             :                                               nvme_completion_poll_cb, status);
     362           3 :         if (rc < 0) {
     363           2 :                 free(status);
     364           2 :                 return -1;
     365             :         }
     366             : 
     367           1 :         if (nvme_wait_for_completion(ctrlr->adminq, status)) {
     368           0 :                 if (!status->timed_out) {
     369           0 :                         free(status);
     370             :                 }
     371           0 :                 return -1;
     372             :         }
     373           1 :         free(status);
     374             : 
     375           1 :         return 0;
     376             : }
     377             : 
     378             : int
     379           0 : nvme_fabric_ctrlr_scan(struct spdk_nvme_probe_ctx *probe_ctx,
     380             :                        bool direct_connect)
     381             : {
     382           0 :         struct spdk_nvme_ctrlr_opts discovery_opts;
     383             :         struct spdk_nvme_ctrlr *discovery_ctrlr;
     384             :         int rc;
     385             :         struct nvme_completion_poll_status *status;
     386             : 
     387           0 :         if (strcmp(probe_ctx->trid.subnqn, SPDK_NVMF_DISCOVERY_NQN) != 0) {
     388             :                 /* It is not a discovery_ctrlr info and try to directly connect it */
     389           0 :                 rc = nvme_ctrlr_probe(&probe_ctx->trid, probe_ctx, NULL);
     390           0 :                 return rc;
     391             :         }
     392             : 
     393           0 :         spdk_nvme_ctrlr_get_default_ctrlr_opts(&discovery_opts, sizeof(discovery_opts));
     394           0 :         if (direct_connect && probe_ctx->probe_cb) {
     395           0 :                 probe_ctx->probe_cb(probe_ctx->cb_ctx, &probe_ctx->trid, &discovery_opts);
     396             :         }
     397             : 
     398           0 :         discovery_ctrlr = nvme_transport_ctrlr_construct(&probe_ctx->trid, &discovery_opts, NULL);
     399           0 :         if (discovery_ctrlr == NULL) {
     400           0 :                 return -1;
     401             :         }
     402             : 
     403           0 :         while (discovery_ctrlr->state != NVME_CTRLR_STATE_READY) {
     404           0 :                 if (nvme_ctrlr_process_init(discovery_ctrlr) != 0) {
     405           0 :                         nvme_ctrlr_destruct(discovery_ctrlr);
     406           0 :                         return -1;
     407             :                 }
     408             :         }
     409             : 
     410           0 :         status = calloc(1, sizeof(*status));
     411           0 :         if (!status) {
     412           0 :                 SPDK_ERRLOG("Failed to allocate status tracker\n");
     413           0 :                 nvme_ctrlr_destruct(discovery_ctrlr);
     414           0 :                 return -ENOMEM;
     415             :         }
     416             : 
     417             :         /* get the cdata info */
     418           0 :         rc = nvme_ctrlr_cmd_identify(discovery_ctrlr, SPDK_NVME_IDENTIFY_CTRLR, 0, 0, 0,
     419           0 :                                      &discovery_ctrlr->cdata, sizeof(discovery_ctrlr->cdata),
     420             :                                      nvme_completion_poll_cb, status);
     421           0 :         if (rc != 0) {
     422           0 :                 SPDK_ERRLOG("Failed to identify cdata\n");
     423           0 :                 nvme_ctrlr_destruct(discovery_ctrlr);
     424           0 :                 free(status);
     425           0 :                 return rc;
     426             :         }
     427             : 
     428           0 :         if (nvme_wait_for_completion(discovery_ctrlr->adminq, status)) {
     429           0 :                 SPDK_ERRLOG("nvme_identify_controller failed!\n");
     430           0 :                 nvme_ctrlr_destruct(discovery_ctrlr);
     431           0 :                 if (!status->timed_out) {
     432           0 :                         free(status);
     433             :                 }
     434           0 :                 return -ENXIO;
     435             :         }
     436             : 
     437           0 :         free(status);
     438             : 
     439             :         /* Direct attach through spdk_nvme_connect() API */
     440           0 :         if (direct_connect == true) {
     441             :                 /* Set the ready state to skip the normal init process */
     442           0 :                 discovery_ctrlr->state = NVME_CTRLR_STATE_READY;
     443           0 :                 nvme_ctrlr_connected(probe_ctx, discovery_ctrlr);
     444           0 :                 nvme_ctrlr_add_process(discovery_ctrlr, 0);
     445           0 :                 return 0;
     446             :         }
     447             : 
     448           0 :         rc = nvme_fabric_ctrlr_discover(discovery_ctrlr, probe_ctx);
     449           0 :         nvme_ctrlr_destruct(discovery_ctrlr);
     450           0 :         return rc;
     451             : }
     452             : 
     453             : int
     454           0 : nvme_fabric_ctrlr_discover(struct spdk_nvme_ctrlr *ctrlr,
     455             :                            struct spdk_nvme_probe_ctx *probe_ctx)
     456             : {
     457             :         struct spdk_nvmf_discovery_log_page *log_page;
     458             :         struct spdk_nvmf_discovery_log_page_entry *log_page_entry;
     459           0 :         char buffer[4096];
     460             :         int rc;
     461           0 :         uint64_t i, numrec, buffer_max_entries_first, buffer_max_entries, log_page_offset = 0;
     462           0 :         uint64_t remaining_num_rec = 0;
     463             :         uint16_t recfmt;
     464             : 
     465           0 :         memset(buffer, 0x0, 4096);
     466           0 :         buffer_max_entries_first = (sizeof(buffer) - offsetof(struct spdk_nvmf_discovery_log_page,
     467             :                                     entries[0])) /
     468             :                                    sizeof(struct spdk_nvmf_discovery_log_page_entry);
     469           0 :         buffer_max_entries = sizeof(buffer) / sizeof(struct spdk_nvmf_discovery_log_page_entry);
     470             :         do {
     471           0 :                 rc = nvme_fabric_get_discovery_log_page(ctrlr, buffer, sizeof(buffer), log_page_offset);
     472           0 :                 if (rc < 0) {
     473           0 :                         SPDK_DEBUGLOG(nvme, "Get Log Page - Discovery error\n");
     474           0 :                         return rc;
     475             :                 }
     476             : 
     477           0 :                 if (!remaining_num_rec) {
     478           0 :                         log_page = (struct spdk_nvmf_discovery_log_page *)buffer;
     479           0 :                         recfmt = from_le16(&log_page->recfmt);
     480           0 :                         if (recfmt != 0) {
     481           0 :                                 SPDK_ERRLOG("Unrecognized discovery log record format %" PRIu16 "\n", recfmt);
     482           0 :                                 return -EPROTO;
     483             :                         }
     484           0 :                         remaining_num_rec = log_page->numrec;
     485           0 :                         log_page_offset = offsetof(struct spdk_nvmf_discovery_log_page, entries[0]);
     486           0 :                         log_page_entry = &log_page->entries[0];
     487           0 :                         numrec = spdk_min(remaining_num_rec, buffer_max_entries_first);
     488             :                 } else {
     489           0 :                         numrec = spdk_min(remaining_num_rec, buffer_max_entries);
     490           0 :                         log_page_entry = (struct spdk_nvmf_discovery_log_page_entry *)buffer;
     491             :                 }
     492             : 
     493           0 :                 for (i = 0; i < numrec; i++) {
     494           0 :                         nvme_fabric_discover_probe(log_page_entry++, probe_ctx, ctrlr->trid.priority);
     495             :                 }
     496           0 :                 remaining_num_rec -= numrec;
     497           0 :                 log_page_offset += numrec * sizeof(struct spdk_nvmf_discovery_log_page_entry);
     498           0 :         } while (remaining_num_rec != 0);
     499             : 
     500           0 :         return 0;
     501             : }
     502             : 
     503             : int
     504           4 : nvme_fabric_qpair_connect_async(struct spdk_nvme_qpair *qpair, uint32_t num_entries)
     505             : {
     506             :         struct nvme_completion_poll_status *status;
     507           4 :         struct spdk_nvmf_fabric_connect_cmd cmd;
     508             :         struct spdk_nvmf_fabric_connect_data *nvmf_data;
     509             :         struct spdk_nvme_ctrlr *ctrlr;
     510             :         struct nvme_request *req;
     511             :         int rc;
     512             : 
     513           4 :         if (num_entries == 0 || num_entries > SPDK_NVME_IO_QUEUE_MAX_ENTRIES) {
     514           1 :                 return -EINVAL;
     515             :         }
     516             : 
     517           3 :         ctrlr = qpair->ctrlr;
     518           3 :         if (!ctrlr) {
     519           0 :                 return -EINVAL;
     520             :         }
     521             : 
     522           3 :         nvmf_data = spdk_zmalloc(sizeof(*nvmf_data), 0, NULL,
     523             :                                  SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
     524           3 :         if (!nvmf_data) {
     525           0 :                 SPDK_ERRLOG("nvmf_data allocation error\n");
     526           0 :                 return -ENOMEM;
     527             :         }
     528             : 
     529           3 :         status = calloc(1, sizeof(*status));
     530           3 :         if (!status) {
     531           0 :                 SPDK_ERRLOG("Failed to allocate status tracker\n");
     532           0 :                 spdk_free(nvmf_data);
     533           0 :                 return -ENOMEM;
     534             :         }
     535             : 
     536           3 :         status->dma_data = nvmf_data;
     537             : 
     538           3 :         memset(&cmd, 0, sizeof(cmd));
     539           3 :         cmd.opcode = SPDK_NVME_OPC_FABRIC;
     540           3 :         cmd.fctype = SPDK_NVMF_FABRIC_COMMAND_CONNECT;
     541           3 :         cmd.qid = qpair->id;
     542           3 :         cmd.sqsize = num_entries - 1;
     543           3 :         cmd.kato = ctrlr->opts.keep_alive_timeout_ms;
     544             : 
     545           3 :         assert(qpair->reserved_req != NULL);
     546           3 :         req = qpair->reserved_req;
     547           3 :         NVME_INIT_REQUEST(req, nvme_completion_poll_cb, status, NVME_PAYLOAD_CONTIG(nvmf_data, NULL),
     548             :                           sizeof(*nvmf_data), 0);
     549             : 
     550           3 :         memcpy(&req->cmd, &cmd, sizeof(cmd));
     551             : 
     552           3 :         if (nvme_qpair_is_admin_queue(qpair)) {
     553           2 :                 nvmf_data->cntlid = 0xFFFF;
     554             :         } else {
     555           1 :                 nvmf_data->cntlid = ctrlr->cntlid;
     556             :         }
     557             : 
     558             :         SPDK_STATIC_ASSERT(sizeof(nvmf_data->hostid) == sizeof(ctrlr->opts.extended_host_id),
     559             :                            "host ID size mismatch");
     560           3 :         memcpy(nvmf_data->hostid, ctrlr->opts.extended_host_id, sizeof(nvmf_data->hostid));
     561           3 :         snprintf(nvmf_data->hostnqn, sizeof(nvmf_data->hostnqn), "%s", ctrlr->opts.hostnqn);
     562           3 :         snprintf(nvmf_data->subnqn, sizeof(nvmf_data->subnqn), "%s", ctrlr->trid.subnqn);
     563             : 
     564           3 :         rc = nvme_qpair_submit_request(qpair, req);
     565           3 :         if (rc < 0) {
     566           0 :                 SPDK_ERRLOG("Failed to allocate/submit FABRIC_CONNECT command, rc %d\n", rc);
     567           0 :                 spdk_free(status->dma_data);
     568           0 :                 free(status);
     569           0 :                 return rc;
     570             :         }
     571             : 
     572             :         /* If we time out, the qpair will abort the request upon destruction. */
     573           3 :         if (ctrlr->opts.fabrics_connect_timeout_us > 0) {
     574           0 :                 status->timeout_tsc = spdk_get_ticks() + ctrlr->opts.fabrics_connect_timeout_us *
     575           0 :                                       spdk_get_ticks_hz() / SPDK_SEC_TO_USEC;
     576             :         }
     577             : 
     578           3 :         qpair->auth.flags = 0;
     579           3 :         qpair->poll_status = status;
     580           3 :         return 0;
     581             : }
     582             : 
     583             : int
     584           3 : nvme_fabric_qpair_connect_poll(struct spdk_nvme_qpair *qpair)
     585             : {
     586             :         struct nvme_completion_poll_status *status;
     587             :         struct spdk_nvmf_fabric_connect_rsp *rsp;
     588             :         struct spdk_nvme_ctrlr *ctrlr;
     589           3 :         int rc = 0;
     590             : 
     591           3 :         ctrlr = qpair->ctrlr;
     592           3 :         status = qpair->poll_status;
     593             : 
     594           3 :         if (nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL) == -EAGAIN) {
     595           0 :                 return -EAGAIN;
     596             :         }
     597             : 
     598           3 :         if (status->timed_out || spdk_nvme_cpl_is_error(&status->cpl)) {
     599           1 :                 SPDK_ERRLOG("Connect command failed, rc %d, trtype:%s adrfam:%s "
     600             :                             "traddr:%s trsvcid:%s subnqn:%s\n",
     601             :                             status->timed_out ? -ECANCELED : -EIO,
     602             :                             spdk_nvme_transport_id_trtype_str(ctrlr->trid.trtype),
     603             :                             spdk_nvme_transport_id_adrfam_str(ctrlr->trid.adrfam),
     604             :                             ctrlr->trid.traddr,
     605             :                             ctrlr->trid.trsvcid,
     606             :                             ctrlr->trid.subnqn);
     607           1 :                 if (status->timed_out) {
     608           1 :                         rc = -ECANCELED;
     609             :                 } else {
     610           0 :                         SPDK_ERRLOG("Connect command completed with error: sct %d, sc %d\n",
     611             :                                     status->cpl.status.sct, status->cpl.status.sc);
     612           0 :                         rc = -EIO;
     613             :                 }
     614             : 
     615           1 :                 goto finish;
     616             :         }
     617             : 
     618           2 :         rsp = (struct spdk_nvmf_fabric_connect_rsp *)&status->cpl;
     619           2 :         if (nvme_qpair_is_admin_queue(qpair)) {
     620           1 :                 ctrlr->cntlid = rsp->status_code_specific.success.cntlid;
     621           1 :                 SPDK_DEBUGLOG(nvme, "CNTLID 0x%04" PRIx16 "\n", ctrlr->cntlid);
     622             :         }
     623           2 :         if (rsp->status_code_specific.success.authreq.atr) {
     624           0 :                 qpair->auth.flags |= NVME_QPAIR_AUTH_FLAG_ATR;
     625             :         }
     626           2 :         if (rsp->status_code_specific.success.authreq.ascr) {
     627           0 :                 qpair->auth.flags |= NVME_QPAIR_AUTH_FLAG_ASCR;
     628             :         }
     629           2 : finish:
     630           3 :         qpair->poll_status = NULL;
     631           3 :         if (!status->timed_out) {
     632           2 :                 spdk_free(status->dma_data);
     633           2 :                 free(status);
     634             :         }
     635             : 
     636           3 :         return rc;
     637             : }
     638             : 
     639             : bool
     640           0 : nvme_fabric_qpair_auth_required(struct spdk_nvme_qpair *qpair)
     641             : {
     642           0 :         struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
     643             : 
     644           0 :         return qpair->auth.flags & (NVME_QPAIR_AUTH_FLAG_ATR | NVME_QPAIR_AUTH_FLAG_ASCR) ||
     645           0 :                ctrlr->opts.dhchap_ctrlr_key != NULL || qpair->auth.cb_fn != NULL;
     646             : }
     647             : 
     648             : int
     649           4 : nvme_fabric_qpair_connect(struct spdk_nvme_qpair *qpair, uint32_t num_entries)
     650             : {
     651             :         int rc;
     652             : 
     653           4 :         rc = nvme_fabric_qpair_connect_async(qpair, num_entries);
     654           4 :         if (rc) {
     655           1 :                 return rc;
     656             :         }
     657             : 
     658             :         do {
     659             :                 /* Wait until the command completes or times out */
     660           3 :                 rc = nvme_fabric_qpair_connect_poll(qpair);
     661           3 :         } while (rc == -EAGAIN);
     662             : 
     663           3 :         return rc;
     664             : }

Generated by: LCOV version 1.15