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 2 : return spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, (struct spdk_nvme_cmd *)&cmd,
39 1 : 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 2 : rc = nvme_fabric_prop_set_cmd(ctrlr, offset, size, value,
56 1 : 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 0 : }
66 0 : SPDK_ERRLOG("Property Set failed\n");
67 0 : return -1;
68 : }
69 1 : free(status);
70 :
71 1 : return 0;
72 1 : }
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 0 : 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 0 : }
107 :
108 0 : return rc;
109 0 : }
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 4 : return spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, (struct spdk_nvme_cmd *)&cmd,
125 2 : 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 0 : }
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 1 : } else {
161 1 : *value = response->value.u64;
162 : }
163 :
164 2 : free(status);
165 :
166 2 : return 0;
167 2 : }
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 : case SPDK_NVMF_PROP_SIZE_4:
181 0 : value = response->value.u32.low;
182 0 : break;
183 : case SPDK_NVMF_PROP_SIZE_8:
184 0 : value = response->value.u64;
185 0 : break;
186 : default:
187 0 : assert(0 && "Should never happen");
188 : }
189 0 : }
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 0 : }
217 :
218 0 : return rc;
219 0 : }
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 : 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 0 : }
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 0 : 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 0 : 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 : 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 0 : }
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 0 : }
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 3 : }
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 6 : rc = spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_LOG_DISCOVERY, 0, log_page, size, offset,
361 3 : 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 0 : }
371 0 : return -1;
372 : }
373 1 : free(status);
374 :
375 1 : return 0;
376 3 : }
377 :
378 : int
379 0 : 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 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 0 : }
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 0 : 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 0 : }
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 0 : }
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 : 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 0 : 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 0 : } 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 0 : }
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 0 : }
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 : 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 2 : } 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 0 : }
577 :
578 3 : qpair->auth.flags = 0;
579 3 : qpair->poll_status = status;
580 3 : return 0;
581 4 : }
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 1 : } 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 1 : }
623 2 : if (rsp->status_code_specific.success.authreq.atr) {
624 0 : qpair->auth.flags |= NVME_QPAIR_AUTH_FLAG_ATR;
625 0 : }
626 2 : if (rsp->status_code_specific.success.authreq.ascr) {
627 0 : qpair->auth.flags |= NVME_QPAIR_AUTH_FLAG_ASCR;
628 0 : }
629 : 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 2 : }
635 :
636 3 : return rc;
637 3 : }
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 3 : 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 4 : }
|