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