1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 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) { 294 SPDK_WARNLOG("Skipping unsupported discovery service referral\n"); 295 return; 296 } else if (entry->subtype != SPDK_NVMF_SUBTYPE_NVME) { 297 SPDK_WARNLOG("Skipping unknown subtype %u\n", entry->subtype); 298 return; 299 } 300 301 trid.trtype = entry->trtype; 302 spdk_nvme_transport_id_populate_trstring(&trid, spdk_nvme_transport_id_trtype_str(entry->trtype)); 303 if (!spdk_nvme_transport_available_by_name(trid.trstring)) { 304 SPDK_WARNLOG("NVMe transport type %u not available; skipping probe\n", 305 trid.trtype); 306 return; 307 } 308 309 trid.adrfam = entry->adrfam; 310 311 /* Ensure that subnqn is null terminated. */ 312 end = memchr(entry->subnqn, '\0', SPDK_NVMF_NQN_MAX_LEN + 1); 313 if (!end) { 314 SPDK_ERRLOG("Discovery entry SUBNQN is not null terminated\n"); 315 return; 316 } 317 len = end - entry->subnqn; 318 memcpy(trid.subnqn, entry->subnqn, len); 319 trid.subnqn[len] = '\0'; 320 321 /* Convert traddr to a null terminated string. */ 322 len = spdk_strlen_pad(entry->traddr, sizeof(entry->traddr), ' '); 323 memcpy(trid.traddr, entry->traddr, len); 324 if (spdk_str_chomp(trid.traddr) != 0) { 325 SPDK_DEBUGLOG(nvme, "Trailing newlines removed from discovery TRADDR\n"); 326 } 327 328 /* Convert trsvcid to a null terminated string. */ 329 len = spdk_strlen_pad(entry->trsvcid, sizeof(entry->trsvcid), ' '); 330 memcpy(trid.trsvcid, entry->trsvcid, len); 331 if (spdk_str_chomp(trid.trsvcid) != 0) { 332 SPDK_DEBUGLOG(nvme, "Trailing newlines removed from discovery TRSVCID\n"); 333 } 334 335 SPDK_DEBUGLOG(nvme, "subnqn=%s, trtype=%u, traddr=%s, trsvcid=%s\n", 336 trid.subnqn, trid.trtype, 337 trid.traddr, trid.trsvcid); 338 339 /* Copy the priority from the discovery ctrlr */ 340 trid.priority = discover_priority; 341 342 nvme_ctrlr_probe(&trid, probe_ctx, NULL); 343 } 344 345 static int 346 nvme_fabric_get_discovery_log_page(struct spdk_nvme_ctrlr *ctrlr, 347 void *log_page, uint32_t size, uint64_t offset) 348 { 349 struct nvme_completion_poll_status *status; 350 int rc; 351 352 status = calloc(1, sizeof(*status)); 353 if (!status) { 354 SPDK_ERRLOG("Failed to allocate status tracker\n"); 355 return -ENOMEM; 356 } 357 358 rc = spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_LOG_DISCOVERY, 0, log_page, size, offset, 359 nvme_completion_poll_cb, status); 360 if (rc < 0) { 361 free(status); 362 return -1; 363 } 364 365 if (nvme_wait_for_completion(ctrlr->adminq, status)) { 366 if (!status->timed_out) { 367 free(status); 368 } 369 return -1; 370 } 371 free(status); 372 373 return 0; 374 } 375 376 int 377 nvme_fabric_ctrlr_scan(struct spdk_nvme_probe_ctx *probe_ctx, 378 bool direct_connect) 379 { 380 struct spdk_nvme_ctrlr_opts discovery_opts; 381 struct spdk_nvme_ctrlr *discovery_ctrlr; 382 int rc; 383 struct nvme_completion_poll_status *status; 384 385 if (strcmp(probe_ctx->trid.subnqn, SPDK_NVMF_DISCOVERY_NQN) != 0) { 386 /* It is not a discovery_ctrlr info and try to directly connect it */ 387 rc = nvme_ctrlr_probe(&probe_ctx->trid, probe_ctx, NULL); 388 return rc; 389 } 390 391 spdk_nvme_ctrlr_get_default_ctrlr_opts(&discovery_opts, sizeof(discovery_opts)); 392 if (direct_connect && probe_ctx->probe_cb) { 393 probe_ctx->probe_cb(probe_ctx->cb_ctx, &probe_ctx->trid, &discovery_opts); 394 } 395 396 discovery_ctrlr = nvme_transport_ctrlr_construct(&probe_ctx->trid, &discovery_opts, NULL); 397 if (discovery_ctrlr == NULL) { 398 return -1; 399 } 400 401 while (discovery_ctrlr->state != NVME_CTRLR_STATE_READY) { 402 if (nvme_ctrlr_process_init(discovery_ctrlr) != 0) { 403 nvme_ctrlr_destruct(discovery_ctrlr); 404 return -1; 405 } 406 } 407 408 status = calloc(1, sizeof(*status)); 409 if (!status) { 410 SPDK_ERRLOG("Failed to allocate status tracker\n"); 411 nvme_ctrlr_destruct(discovery_ctrlr); 412 return -ENOMEM; 413 } 414 415 /* get the cdata info */ 416 rc = nvme_ctrlr_cmd_identify(discovery_ctrlr, SPDK_NVME_IDENTIFY_CTRLR, 0, 0, 0, 417 &discovery_ctrlr->cdata, sizeof(discovery_ctrlr->cdata), 418 nvme_completion_poll_cb, status); 419 if (rc != 0) { 420 SPDK_ERRLOG("Failed to identify cdata\n"); 421 nvme_ctrlr_destruct(discovery_ctrlr); 422 free(status); 423 return rc; 424 } 425 426 if (nvme_wait_for_completion(discovery_ctrlr->adminq, status)) { 427 SPDK_ERRLOG("nvme_identify_controller failed!\n"); 428 nvme_ctrlr_destruct(discovery_ctrlr); 429 if (!status->timed_out) { 430 free(status); 431 } 432 return -ENXIO; 433 } 434 435 free(status); 436 437 /* Direct attach through spdk_nvme_connect() API */ 438 if (direct_connect == true) { 439 /* Set the ready state to skip the normal init process */ 440 discovery_ctrlr->state = NVME_CTRLR_STATE_READY; 441 nvme_ctrlr_connected(probe_ctx, discovery_ctrlr); 442 nvme_ctrlr_add_process(discovery_ctrlr, 0); 443 return 0; 444 } 445 446 rc = nvme_fabric_ctrlr_discover(discovery_ctrlr, probe_ctx); 447 nvme_ctrlr_destruct(discovery_ctrlr); 448 return rc; 449 } 450 451 int 452 nvme_fabric_ctrlr_discover(struct spdk_nvme_ctrlr *ctrlr, 453 struct spdk_nvme_probe_ctx *probe_ctx) 454 { 455 struct spdk_nvmf_discovery_log_page *log_page; 456 struct spdk_nvmf_discovery_log_page_entry *log_page_entry; 457 char buffer[4096]; 458 int rc; 459 uint64_t i, numrec, buffer_max_entries_first, buffer_max_entries, log_page_offset = 0; 460 uint64_t remaining_num_rec = 0; 461 uint16_t recfmt; 462 463 memset(buffer, 0x0, 4096); 464 buffer_max_entries_first = (sizeof(buffer) - offsetof(struct spdk_nvmf_discovery_log_page, 465 entries[0])) / 466 sizeof(struct spdk_nvmf_discovery_log_page_entry); 467 buffer_max_entries = sizeof(buffer) / sizeof(struct spdk_nvmf_discovery_log_page_entry); 468 do { 469 rc = nvme_fabric_get_discovery_log_page(ctrlr, buffer, sizeof(buffer), log_page_offset); 470 if (rc < 0) { 471 SPDK_DEBUGLOG(nvme, "Get Log Page - Discovery error\n"); 472 return rc; 473 } 474 475 if (!remaining_num_rec) { 476 log_page = (struct spdk_nvmf_discovery_log_page *)buffer; 477 recfmt = from_le16(&log_page->recfmt); 478 if (recfmt != 0) { 479 SPDK_ERRLOG("Unrecognized discovery log record format %" PRIu16 "\n", recfmt); 480 return -EPROTO; 481 } 482 remaining_num_rec = log_page->numrec; 483 log_page_offset = offsetof(struct spdk_nvmf_discovery_log_page, entries[0]); 484 log_page_entry = &log_page->entries[0]; 485 numrec = spdk_min(remaining_num_rec, buffer_max_entries_first); 486 } else { 487 numrec = spdk_min(remaining_num_rec, buffer_max_entries); 488 log_page_entry = (struct spdk_nvmf_discovery_log_page_entry *)buffer; 489 } 490 491 for (i = 0; i < numrec; i++) { 492 nvme_fabric_discover_probe(log_page_entry++, probe_ctx, ctrlr->trid.priority); 493 } 494 remaining_num_rec -= numrec; 495 log_page_offset += numrec * sizeof(struct spdk_nvmf_discovery_log_page_entry); 496 } while (remaining_num_rec != 0); 497 498 return 0; 499 } 500 501 int 502 nvme_fabric_qpair_connect_async(struct spdk_nvme_qpair *qpair, uint32_t num_entries) 503 { 504 struct nvme_completion_poll_status *status; 505 struct spdk_nvmf_fabric_connect_cmd cmd; 506 struct spdk_nvmf_fabric_connect_data *nvmf_data; 507 struct spdk_nvme_ctrlr *ctrlr; 508 struct nvme_request *req; 509 int rc; 510 511 if (num_entries == 0 || num_entries > SPDK_NVME_IO_QUEUE_MAX_ENTRIES) { 512 return -EINVAL; 513 } 514 515 ctrlr = qpair->ctrlr; 516 if (!ctrlr) { 517 return -EINVAL; 518 } 519 520 nvmf_data = spdk_zmalloc(sizeof(*nvmf_data), 0, NULL, 521 SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 522 if (!nvmf_data) { 523 SPDK_ERRLOG("nvmf_data allocation error\n"); 524 return -ENOMEM; 525 } 526 527 status = calloc(1, sizeof(*status)); 528 if (!status) { 529 SPDK_ERRLOG("Failed to allocate status tracker\n"); 530 spdk_free(nvmf_data); 531 return -ENOMEM; 532 } 533 534 status->dma_data = nvmf_data; 535 536 memset(&cmd, 0, sizeof(cmd)); 537 cmd.opcode = SPDK_NVME_OPC_FABRIC; 538 cmd.fctype = SPDK_NVMF_FABRIC_COMMAND_CONNECT; 539 cmd.qid = qpair->id; 540 cmd.sqsize = num_entries - 1; 541 cmd.kato = ctrlr->opts.keep_alive_timeout_ms; 542 543 assert(qpair->reserved_req != NULL); 544 req = qpair->reserved_req; 545 memcpy(&req->cmd, &cmd, sizeof(cmd)); 546 547 if (nvme_qpair_is_admin_queue(qpair)) { 548 nvmf_data->cntlid = 0xFFFF; 549 } else { 550 nvmf_data->cntlid = ctrlr->cntlid; 551 } 552 553 SPDK_STATIC_ASSERT(sizeof(nvmf_data->hostid) == sizeof(ctrlr->opts.extended_host_id), 554 "host ID size mismatch"); 555 memcpy(nvmf_data->hostid, ctrlr->opts.extended_host_id, sizeof(nvmf_data->hostid)); 556 snprintf(nvmf_data->hostnqn, sizeof(nvmf_data->hostnqn), "%s", ctrlr->opts.hostnqn); 557 snprintf(nvmf_data->subnqn, sizeof(nvmf_data->subnqn), "%s", ctrlr->trid.subnqn); 558 559 NVME_INIT_REQUEST(req, nvme_completion_poll_cb, status, NVME_PAYLOAD_CONTIG(nvmf_data, NULL), 560 sizeof(*nvmf_data), 0); 561 562 rc = nvme_qpair_submit_request(qpair, req); 563 if (rc < 0) { 564 SPDK_ERRLOG("Failed to allocate/submit FABRIC_CONNECT command, rc %d\n", rc); 565 spdk_free(status->dma_data); 566 free(status); 567 return rc; 568 } 569 570 /* If we time out, the qpair will abort the request upon destruction. */ 571 if (ctrlr->opts.fabrics_connect_timeout_us > 0) { 572 status->timeout_tsc = spdk_get_ticks() + ctrlr->opts.fabrics_connect_timeout_us * 573 spdk_get_ticks_hz() / SPDK_SEC_TO_USEC; 574 } 575 576 qpair->poll_status = status; 577 return 0; 578 } 579 580 int 581 nvme_fabric_qpair_connect_poll(struct spdk_nvme_qpair *qpair) 582 { 583 struct nvme_completion_poll_status *status; 584 struct spdk_nvmf_fabric_connect_rsp *rsp; 585 struct spdk_nvme_ctrlr *ctrlr; 586 int rc = 0; 587 588 ctrlr = qpair->ctrlr; 589 status = qpair->poll_status; 590 591 if (nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL) == -EAGAIN) { 592 return -EAGAIN; 593 } 594 595 if (status->timed_out || spdk_nvme_cpl_is_error(&status->cpl)) { 596 SPDK_ERRLOG("Connect command failed, rc %d, trtype:%s adrfam:%s " 597 "traddr:%s trsvcid:%s subnqn:%s\n", 598 status->timed_out ? -ECANCELED : -EIO, 599 spdk_nvme_transport_id_trtype_str(ctrlr->trid.trtype), 600 spdk_nvme_transport_id_adrfam_str(ctrlr->trid.adrfam), 601 ctrlr->trid.traddr, 602 ctrlr->trid.trsvcid, 603 ctrlr->trid.subnqn); 604 if (status->timed_out) { 605 rc = -ECANCELED; 606 } else { 607 SPDK_ERRLOG("Connect command completed with error: sct %d, sc %d\n", 608 status->cpl.status.sct, status->cpl.status.sc); 609 rc = -EIO; 610 } 611 612 goto finish; 613 } 614 615 if (nvme_qpair_is_admin_queue(qpair)) { 616 rsp = (struct spdk_nvmf_fabric_connect_rsp *)&status->cpl; 617 ctrlr->cntlid = rsp->status_code_specific.success.cntlid; 618 SPDK_DEBUGLOG(nvme, "CNTLID 0x%04" PRIx16 "\n", ctrlr->cntlid); 619 } 620 finish: 621 qpair->poll_status = NULL; 622 if (!status->timed_out) { 623 spdk_free(status->dma_data); 624 free(status); 625 } 626 627 return rc; 628 } 629 630 int 631 nvme_fabric_qpair_connect(struct spdk_nvme_qpair *qpair, uint32_t num_entries) 632 { 633 int rc; 634 635 rc = nvme_fabric_qpair_connect_async(qpair, num_entries); 636 if (rc) { 637 return rc; 638 } 639 640 do { 641 /* Wait until the command completes or times out */ 642 rc = nvme_fabric_qpair_connect_poll(qpair); 643 } while (rc == -EAGAIN); 644 645 return rc; 646 } 647