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