Branch data 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 : 3137 : 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 : 3137 : struct spdk_nvmf_fabric_prop_set_cmd cmd = {};
29 : :
30 [ + + - + ]: 3137 : assert(size == SPDK_NVMF_PROP_SIZE_4 || size == SPDK_NVMF_PROP_SIZE_8);
31 : :
32 : 3137 : cmd.opcode = SPDK_NVME_OPC_FABRIC;
33 : 3137 : cmd.fctype = SPDK_NVMF_FABRIC_COMMAND_PROPERTY_SET;
34 : 3137 : cmd.ofst = offset;
35 : 3137 : cmd.attrib.size = size;
36 : 3137 : cmd.value.u64 = value;
37 : :
38 : 3137 : 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 : 5 : 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 : 5 : status = calloc(1, sizeof(*status));
50 [ - + ]: 5 : if (!status) {
51 : 0 : SPDK_ERRLOG("Failed to allocate status tracker\n");
52 : 0 : return -ENOMEM;
53 : : }
54 : :
55 : 5 : rc = nvme_fabric_prop_set_cmd(ctrlr, offset, size, value,
56 : : nvme_completion_poll_cb, status);
57 [ - + ]: 5 : if (rc < 0) {
58 : 0 : free(status);
59 : 0 : return rc;
60 : : }
61 : :
62 [ - + ]: 5 : 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 : 5 : free(status);
70 : :
71 : 5 : return 0;
72 : : }
73 : :
74 : : static void
75 : 3132 : nvme_fabric_prop_set_cmd_done(void *ctx, const struct spdk_nvme_cpl *cpl)
76 : : {
77 : 3132 : struct nvme_fabric_prop_ctx *prop_ctx = ctx;
78 : :
79 : 3132 : prop_ctx->cb_fn(prop_ctx->cb_arg, prop_ctx->value, cpl);
80 : 3132 : free(prop_ctx);
81 : 3132 : }
82 : :
83 : : static int
84 : 3132 : 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 : 3132 : ctx = calloc(1, sizeof(*ctx));
92 [ - + ]: 3132 : if (ctx == NULL) {
93 : 0 : SPDK_ERRLOG("Failed to allocate fabrics property context\n");
94 : 0 : return -ENOMEM;
95 : : }
96 : :
97 : 3132 : ctx->value = value;
98 : 3132 : ctx->cb_fn = cb_fn;
99 : 3132 : ctx->cb_arg = cb_arg;
100 : :
101 : 3132 : rc = nvme_fabric_prop_set_cmd(ctrlr, offset, size, value,
102 : : nvme_fabric_prop_set_cmd_done, ctx);
103 [ - + ]: 3132 : if (rc != 0) {
104 : 0 : SPDK_ERRLOG("Failed to send Property Set fabrics command\n");
105 : 0 : free(ctx);
106 : : }
107 : :
108 : 3132 : return rc;
109 : : }
110 : :
111 : : static int
112 : 50378 : 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 : 50378 : struct spdk_nvmf_fabric_prop_set_cmd cmd = {};
116 : :
117 [ + + - + ]: 50378 : assert(size == SPDK_NVMF_PROP_SIZE_4 || size == SPDK_NVMF_PROP_SIZE_8);
118 : :
119 : 50378 : cmd.opcode = SPDK_NVME_OPC_FABRIC;
120 : 50378 : cmd.fctype = SPDK_NVMF_FABRIC_COMMAND_PROPERTY_GET;
121 : 50378 : cmd.ofst = offset;
122 : 50378 : cmd.attrib.size = size;
123 : :
124 : 50378 : 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 : 1805 : 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 : 1805 : status = calloc(1, sizeof(*status));
137 [ - + ]: 1805 : if (!status) {
138 : 0 : SPDK_ERRLOG("Failed to allocate status tracker\n");
139 : 0 : return -ENOMEM;
140 : : }
141 : :
142 : 1805 : rc = nvme_fabric_prop_get_cmd(ctrlr, offset, size, nvme_completion_poll_cb, status);
143 [ - + ]: 1805 : if (rc < 0) {
144 : 0 : free(status);
145 : 0 : return rc;
146 : : }
147 : :
148 [ - + ]: 1805 : 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 : 1805 : response = (struct spdk_nvmf_fabric_prop_get_rsp *)&status->cpl;
157 : :
158 [ + + ]: 1805 : if (size == SPDK_NVMF_PROP_SIZE_4) {
159 : 1800 : *value = response->value.u32.low;
160 : : } else {
161 : 5 : *value = response->value.u64;
162 : : }
163 : :
164 : 1805 : free(status);
165 : :
166 : 1805 : return 0;
167 : : }
168 : :
169 : : static void
170 : 48570 : nvme_fabric_prop_get_cmd_done(void *ctx, const struct spdk_nvme_cpl *cpl)
171 : : {
172 : 48570 : struct nvme_fabric_prop_ctx *prop_ctx = ctx;
173 : : struct spdk_nvmf_fabric_prop_get_rsp *response;
174 : 48570 : uint64_t value = 0;
175 : :
176 [ + - + - ]: 48570 : if (spdk_nvme_cpl_is_success(cpl)) {
177 : 48570 : response = (struct spdk_nvmf_fabric_prop_get_rsp *)cpl;
178 : :
179 [ + + - ]: 48570 : switch (prop_ctx->size) {
180 : 46970 : case SPDK_NVMF_PROP_SIZE_4:
181 : 46970 : value = response->value.u32.low;
182 : 46970 : break;
183 : 1600 : case SPDK_NVMF_PROP_SIZE_8:
184 : 1600 : value = response->value.u64;
185 : 1600 : break;
186 : 0 : default:
187 : 0 : assert(0 && "Should never happen");
188 : : }
189 : : }
190 : :
191 : 48570 : prop_ctx->cb_fn(prop_ctx->cb_arg, value, cpl);
192 : 48570 : free(prop_ctx);
193 : 48570 : }
194 : :
195 : : static int
196 : 48573 : 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 : 48573 : ctx = calloc(1, sizeof(*ctx));
203 [ - + ]: 48573 : if (ctx == NULL) {
204 : 0 : SPDK_ERRLOG("Failed to allocate fabrics property context\n");
205 : 0 : return -ENOMEM;
206 : : }
207 : :
208 : 48573 : ctx->size = size;
209 : 48573 : ctx->cb_fn = cb_fn;
210 : 48573 : ctx->cb_arg = cb_arg;
211 : :
212 : 48573 : rc = nvme_fabric_prop_get_cmd(ctrlr, offset, size, nvme_fabric_prop_get_cmd_done, ctx);
213 [ + + ]: 48573 : if (rc != 0) {
214 : 3 : SPDK_ERRLOG("Failed to send Property Get fabrics command\n");
215 : 3 : free(ctx);
216 : : }
217 : :
218 : 48573 : 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 : 1795 : 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 : 1795 : rc = nvme_fabric_prop_get_cmd_sync(ctrlr, offset, SPDK_NVMF_PROP_SIZE_4, &tmp_value);
239 : :
240 [ + - ]: 1795 : if (!rc) {
241 : 1795 : *value = (uint32_t)tmp_value;
242 : : }
243 : 1795 : 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 : 3132 : 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 : 3132 : 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 : 46973 : 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 : 46973 : return nvme_fabric_prop_get_cmd_async(ctrlr, offset, SPDK_NVMF_PROP_SIZE_4, cb_fn, cb_arg);
273 : : }
274 : :
275 : : int
276 : 1600 : 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 : 1600 : return nvme_fabric_prop_get_cmd_async(ctrlr, offset, SPDK_NVMF_PROP_SIZE_8, cb_fn, cb_arg);
280 : : }
281 : :
282 : : static void
283 : 188 : 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 : 12 : struct spdk_nvme_transport_id trid;
288 : : uint8_t *end;
289 : : size_t len;
290 : :
291 : 188 : memset(&trid, 0, sizeof(trid));
292 : :
293 [ + + ]: 188 : if (entry->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY_CURRENT ||
294 [ - + ]: 102 : entry->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY) {
295 : 86 : SPDK_WARNLOG("Skipping unsupported current discovery service or"
296 : : " discovery service referral\n");
297 : 86 : return;
298 [ - + ]: 102 : } 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 : 102 : trid.trtype = entry->trtype;
304 : 102 : spdk_nvme_transport_id_populate_trstring(&trid, spdk_nvme_transport_id_trtype_str(entry->trtype));
305 [ - + ]: 102 : 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 : 102 : trid.adrfam = entry->adrfam;
312 : :
313 : : /* Ensure that subnqn is null terminated. */
314 [ - + ]: 102 : end = memchr(entry->subnqn, '\0', SPDK_NVMF_NQN_MAX_LEN + 1);
315 [ - + ]: 102 : if (!end) {
316 : 0 : SPDK_ERRLOG("Discovery entry SUBNQN is not null terminated\n");
317 : 0 : return;
318 : : }
319 : 102 : len = end - entry->subnqn;
320 [ - + ]: 102 : memcpy(trid.subnqn, entry->subnqn, len);
321 : 102 : trid.subnqn[len] = '\0';
322 : :
323 : : /* Convert traddr to a null terminated string. */
324 : 102 : len = spdk_strlen_pad(entry->traddr, sizeof(entry->traddr), ' ');
325 [ - + ]: 102 : memcpy(trid.traddr, entry->traddr, len);
326 [ - + ]: 102 : 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 : 102 : len = spdk_strlen_pad(entry->trsvcid, sizeof(entry->trsvcid), ' ');
332 [ - + ]: 102 : memcpy(trid.trsvcid, entry->trsvcid, len);
333 [ - + ]: 102 : if (spdk_str_chomp(trid.trsvcid) != 0) {
334 [ # # # # ]: 0 : SPDK_DEBUGLOG(nvme, "Trailing newlines removed from discovery TRSVCID\n");
335 : : }
336 : :
337 [ - + - + ]: 102 : 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 : 102 : trid.priority = discover_priority;
343 : :
344 : 102 : nvme_ctrlr_probe(&trid, probe_ctx, NULL);
345 : : }
346 : :
347 : : static int
348 : 112 : 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 : 112 : status = calloc(1, sizeof(*status));
355 [ - + ]: 112 : if (!status) {
356 : 0 : SPDK_ERRLOG("Failed to allocate status tracker\n");
357 : 0 : return -ENOMEM;
358 : : }
359 : :
360 : 112 : 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 [ + + ]: 112 : if (rc < 0) {
363 : 10 : free(status);
364 : 10 : return -1;
365 : : }
366 : :
367 [ - + ]: 102 : 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 : 102 : free(status);
374 : :
375 : 102 : return 0;
376 : : }
377 : :
378 : : int
379 : 1537 : nvme_fabric_ctrlr_scan(struct spdk_nvme_probe_ctx *probe_ctx,
380 : : bool direct_connect)
381 : : {
382 : 49 : 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 [ - + + + ]: 1537 : 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 : 1384 : rc = nvme_ctrlr_probe(&probe_ctx->trid, probe_ctx, NULL);
390 : 1384 : return rc;
391 : : }
392 : :
393 : 153 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&discovery_opts, sizeof(discovery_opts));
394 [ + + + - ]: 153 : if (direct_connect && probe_ctx->probe_cb) {
395 : 54 : probe_ctx->probe_cb(probe_ctx->cb_ctx, &probe_ctx->trid, &discovery_opts);
396 : : }
397 : :
398 : 153 : discovery_ctrlr = nvme_transport_ctrlr_construct(&probe_ctx->trid, &discovery_opts, NULL);
399 [ + + ]: 153 : if (discovery_ctrlr == NULL) {
400 : 14 : return -1;
401 : : }
402 : :
403 [ + + ]: 1095543 : while (discovery_ctrlr->state != NVME_CTRLR_STATE_READY) {
404 [ + + ]: 1095405 : if (nvme_ctrlr_process_init(discovery_ctrlr) != 0) {
405 : 1 : nvme_ctrlr_destruct(discovery_ctrlr);
406 : 1 : return -1;
407 : : }
408 : : }
409 : :
410 : 138 : status = calloc(1, sizeof(*status));
411 [ - + ]: 138 : 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 : 138 : rc = nvme_ctrlr_cmd_identify(discovery_ctrlr, SPDK_NVME_IDENTIFY_CTRLR, 0, 0, 0,
419 : 138 : &discovery_ctrlr->cdata, sizeof(discovery_ctrlr->cdata),
420 : : nvme_completion_poll_cb, status);
421 [ - + ]: 138 : 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 [ - + ]: 138 : 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 : 138 : free(status);
438 : :
439 : : /* Direct attach through spdk_nvme_connect() API */
440 [ + + ]: 138 : if (direct_connect == true) {
441 : : /* Set the ready state to skip the normal init process */
442 : 41 : discovery_ctrlr->state = NVME_CTRLR_STATE_READY;
443 : 41 : nvme_ctrlr_connected(probe_ctx, discovery_ctrlr);
444 : 41 : nvme_ctrlr_add_process(discovery_ctrlr, 0);
445 : 41 : return 0;
446 : : }
447 : :
448 : 97 : rc = nvme_fabric_ctrlr_discover(discovery_ctrlr, probe_ctx);
449 : 97 : nvme_ctrlr_destruct(discovery_ctrlr);
450 : 97 : return rc;
451 : : }
452 : :
453 : : int
454 : 97 : 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 : 97 : uint64_t i, numrec, buffer_max_entries_first, buffer_max_entries, log_page_offset = 0;
462 : 97 : uint64_t remaining_num_rec = 0;
463 : : uint16_t recfmt;
464 : :
465 [ - + ]: 97 : memset(buffer, 0x0, 4096);
466 : 97 : 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 : 97 : buffer_max_entries = sizeof(buffer) / sizeof(struct spdk_nvmf_discovery_log_page_entry);
470 : : do {
471 : 97 : rc = nvme_fabric_get_discovery_log_page(ctrlr, buffer, sizeof(buffer), log_page_offset);
472 [ - + ]: 97 : if (rc < 0) {
473 [ # # # # ]: 0 : SPDK_DEBUGLOG(nvme, "Get Log Page - Discovery error\n");
474 : 0 : return rc;
475 : : }
476 : :
477 [ + - ]: 97 : if (!remaining_num_rec) {
478 : 97 : log_page = (struct spdk_nvmf_discovery_log_page *)buffer;
479 : 97 : recfmt = from_le16(&log_page->recfmt);
480 [ - + ]: 97 : if (recfmt != 0) {
481 : 0 : SPDK_ERRLOG("Unrecognized discovery log record format %" PRIu16 "\n", recfmt);
482 : 0 : return -EPROTO;
483 : : }
484 : 97 : remaining_num_rec = log_page->numrec;
485 : 97 : log_page_offset = offsetof(struct spdk_nvmf_discovery_log_page, entries[0]);
486 : 97 : log_page_entry = &log_page->entries[0];
487 : 97 : 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 [ + + ]: 270 : for (i = 0; i < numrec; i++) {
494 : 173 : nvme_fabric_discover_probe(log_page_entry++, probe_ctx, ctrlr->trid.priority);
495 : : }
496 : 97 : remaining_num_rec -= numrec;
497 : 97 : log_page_offset += numrec * sizeof(struct spdk_nvmf_discovery_log_page_entry);
498 [ - + ]: 97 : } while (remaining_num_rec != 0);
499 : :
500 : 97 : return 0;
501 : : }
502 : :
503 : : int
504 : 5297 : nvme_fabric_qpair_connect_async(struct spdk_nvme_qpair *qpair, uint32_t num_entries)
505 : : {
506 : : struct nvme_completion_poll_status *status;
507 : 115 : 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 [ + + - + ]: 5297 : if (num_entries == 0 || num_entries > SPDK_NVME_IO_QUEUE_MAX_ENTRIES) {
514 : 5 : return -EINVAL;
515 : : }
516 : :
517 : 5292 : ctrlr = qpair->ctrlr;
518 [ - + ]: 5292 : if (!ctrlr) {
519 : 0 : return -EINVAL;
520 : : }
521 : :
522 : 5292 : nvmf_data = spdk_zmalloc(sizeof(*nvmf_data), 0, NULL,
523 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
524 [ - + ]: 5292 : if (!nvmf_data) {
525 : 0 : SPDK_ERRLOG("nvmf_data allocation error\n");
526 : 0 : return -ENOMEM;
527 : : }
528 : :
529 : 5292 : status = calloc(1, sizeof(*status));
530 [ - + ]: 5292 : 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 : 5292 : status->dma_data = nvmf_data;
537 : :
538 [ - + ]: 5292 : memset(&cmd, 0, sizeof(cmd));
539 : 5292 : cmd.opcode = SPDK_NVME_OPC_FABRIC;
540 : 5292 : cmd.fctype = SPDK_NVMF_FABRIC_COMMAND_CONNECT;
541 : 5292 : cmd.qid = qpair->id;
542 : 5292 : cmd.sqsize = num_entries - 1;
543 : 5292 : cmd.kato = ctrlr->opts.keep_alive_timeout_ms;
544 : :
545 [ - + ]: 5292 : assert(qpair->reserved_req != NULL);
546 : 5292 : req = qpair->reserved_req;
547 : 5292 : NVME_INIT_REQUEST(req, nvme_completion_poll_cb, status, NVME_PAYLOAD_CONTIG(nvmf_data, NULL),
548 : : sizeof(*nvmf_data), 0);
549 : :
550 : 5292 : memcpy(&req->cmd, &cmd, sizeof(cmd));
551 : :
552 [ + + ]: 5292 : if (nvme_qpair_is_admin_queue(qpair)) {
553 : 1648 : nvmf_data->cntlid = 0xFFFF;
554 : : } else {
555 : 3644 : 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 : 5292 : memcpy(nvmf_data->hostid, ctrlr->opts.extended_host_id, sizeof(nvmf_data->hostid));
561 [ - + ]: 5292 : snprintf(nvmf_data->hostnqn, sizeof(nvmf_data->hostnqn), "%s", ctrlr->opts.hostnqn);
562 [ - + ]: 5292 : snprintf(nvmf_data->subnqn, sizeof(nvmf_data->subnqn), "%s", ctrlr->trid.subnqn);
563 : :
564 : 5292 : rc = nvme_qpair_submit_request(qpair, req);
565 [ - + ]: 5292 : 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 [ - + ]: 5292 : 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 : 5292 : qpair->auth.flags = 0;
579 : 5292 : qpair->connect_state = NVME_QPAIR_CONNECT_STATE_CONNECTING;
580 : 5292 : qpair->poll_status = status;
581 : 5292 : return 0;
582 : : }
583 : :
584 : : static int
585 : 316296 : _nvme_fabric_qpair_connect_poll(struct spdk_nvme_qpair *qpair)
586 : : {
587 : : struct nvme_completion_poll_status *status;
588 : : struct spdk_nvmf_fabric_connect_rsp *rsp;
589 : : struct spdk_nvme_ctrlr *ctrlr;
590 : 316296 : int rc = 0;
591 : :
592 : 316296 : ctrlr = qpair->ctrlr;
593 : 316296 : status = qpair->poll_status;
594 : :
595 [ + + ]: 316296 : if (nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL) == -EAGAIN) {
596 : 311004 : return -EAGAIN;
597 : : }
598 : :
599 [ + + + + : 5292 : if (status->timed_out || spdk_nvme_cpl_is_error(&status->cpl)) {
+ + - + ]
600 [ + + + + ]: 674 : SPDK_ERRLOG("Connect command failed, rc %d, trtype:%s adrfam:%s "
601 : : "traddr:%s trsvcid:%s subnqn:%s\n",
602 : : status->timed_out ? -ECANCELED : -EIO,
603 : : spdk_nvme_transport_id_trtype_str(ctrlr->trid.trtype),
604 : : spdk_nvme_transport_id_adrfam_str(ctrlr->trid.adrfam),
605 : : ctrlr->trid.traddr,
606 : : ctrlr->trid.trsvcid,
607 : : ctrlr->trid.subnqn);
608 [ + + + + ]: 674 : if (status->timed_out) {
609 : 5 : rc = -ECANCELED;
610 : : } else {
611 : 669 : SPDK_ERRLOG("Connect command completed with error: sct %d, sc %d\n",
612 : : status->cpl.status.sct, status->cpl.status.sc);
613 : 669 : rc = -EIO;
614 : : }
615 : :
616 : 674 : goto finish;
617 : : }
618 : :
619 : 4618 : rsp = (struct spdk_nvmf_fabric_connect_rsp *)&status->cpl;
620 [ + + ]: 4618 : if (nvme_qpair_is_admin_queue(qpair)) {
621 : 1641 : ctrlr->cntlid = rsp->status_code_specific.success.cntlid;
622 [ - + + + ]: 1641 : SPDK_DEBUGLOG(nvme, "CNTLID 0x%04" PRIx16 "\n", ctrlr->cntlid);
623 : : }
624 [ + + ]: 4618 : if (rsp->status_code_specific.success.authreq.atr) {
625 : 936 : qpair->auth.flags |= NVME_QPAIR_AUTH_FLAG_ATR;
626 : : }
627 [ + - ]: 4618 : if (rsp->status_code_specific.success.authreq.ascr) {
628 : 0 : qpair->auth.flags |= NVME_QPAIR_AUTH_FLAG_ASCR;
629 : : }
630 : 4618 : finish:
631 : 5292 : qpair->poll_status = NULL;
632 [ + + + + ]: 5292 : if (!status->timed_out) {
633 : 5287 : spdk_free(status->dma_data);
634 : 5287 : free(status);
635 : : }
636 : :
637 : 5292 : return rc;
638 : : }
639 : :
640 : : int
641 : 1405667 : nvme_fabric_qpair_connect_poll(struct spdk_nvme_qpair *qpair)
642 : : {
643 : 1405667 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
644 : : int rc;
645 : :
646 [ + + - ]: 1405667 : switch (qpair->connect_state) {
647 : 316296 : case NVME_QPAIR_CONNECT_STATE_CONNECTING:
648 : 316296 : rc = _nvme_fabric_qpair_connect_poll(qpair);
649 [ + + ]: 316296 : if (rc != 0) {
650 : 311678 : break;
651 : : }
652 [ + + ]: 4618 : if (qpair->auth.flags & (NVME_QPAIR_AUTH_FLAG_ATR | NVME_QPAIR_AUTH_FLAG_ASCR) ||
653 [ + + ]: 3682 : ctrlr->opts.dhchap_ctrlr_key != NULL) {
654 : 940 : rc = nvme_fabric_qpair_authenticate_async(qpair);
655 [ + + ]: 940 : if (rc == 0) {
656 : 932 : qpair->connect_state = NVME_QPAIR_CONNECT_STATE_AUTHENTICATING;
657 : 932 : rc = -EAGAIN;
658 : : }
659 : 940 : break;
660 : : }
661 : 3678 : qpair->connect_state = NVME_QPAIR_CONNECT_STATE_CONNECTED;
662 : 3678 : break;
663 : 1089371 : case NVME_QPAIR_CONNECT_STATE_AUTHENTICATING:
664 : 1089371 : rc = nvme_fabric_qpair_authenticate_poll(qpair);
665 [ + + ]: 1089371 : if (rc == 0) {
666 : 904 : qpair->connect_state = NVME_QPAIR_CONNECT_STATE_CONNECTED;
667 : : }
668 : 1089371 : break;
669 : : /* Once qpair is connected or a failure occurs, users mustn't call this function anymore */
670 : 0 : case NVME_QPAIR_CONNECT_STATE_CONNECTED:
671 : : case NVME_QPAIR_CONNECT_STATE_FAILED:
672 : : default:
673 : 0 : assert(0 && "invalid state");
674 : : rc = -EINVAL;
675 : : break;
676 : : }
677 : :
678 [ + + + + ]: 1405667 : if (rc != 0 && rc != -EAGAIN) {
679 : 710 : qpair->connect_state = NVME_QPAIR_CONNECT_STATE_FAILED;
680 : : }
681 : :
682 : 1405667 : return rc;
683 : : }
684 : :
685 : : int
686 : 20 : nvme_fabric_qpair_connect(struct spdk_nvme_qpair *qpair, uint32_t num_entries)
687 : : {
688 : : int rc;
689 : :
690 : 20 : rc = nvme_fabric_qpair_connect_async(qpair, num_entries);
691 [ + + ]: 20 : if (rc) {
692 : 5 : return rc;
693 : : }
694 : :
695 : : do {
696 : : /* Wait until the command completes or times out */
697 : 15 : rc = nvme_fabric_qpair_connect_poll(qpair);
698 [ - + ]: 15 : } while (rc == -EAGAIN);
699 : :
700 : 15 : return rc;
701 : : }
|