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 : 1778 : 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 : 1778 : struct spdk_nvmf_fabric_prop_set_cmd cmd = {};
29 : :
30 [ + + - + ]: 1778 : assert(size == SPDK_NVMF_PROP_SIZE_4 || size == SPDK_NVMF_PROP_SIZE_8);
31 : :
32 : 1778 : cmd.opcode = SPDK_NVME_OPC_FABRIC;
33 : 1778 : cmd.fctype = SPDK_NVMF_FABRIC_COMMAND_PROPERTY_SET;
34 : 1778 : cmd.ofst = offset;
35 : 1778 : cmd.attrib.size = size;
36 : 1778 : cmd.value.u64 = value;
37 : :
38 : 1778 : 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 : 6 : 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 : 6 : status = calloc(1, sizeof(*status));
50 [ - + ]: 6 : if (!status) {
51 : 0 : SPDK_ERRLOG("Failed to allocate status tracker\n");
52 : 0 : return -ENOMEM;
53 : : }
54 : :
55 : 6 : rc = nvme_fabric_prop_set_cmd(ctrlr, offset, size, value,
56 : : nvme_completion_poll_cb, status);
57 [ - + ]: 6 : if (rc < 0) {
58 : 0 : free(status);
59 : 0 : return rc;
60 : : }
61 : :
62 [ - + ]: 6 : 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 : 6 : free(status);
70 : :
71 : 6 : return 0;
72 : : }
73 : :
74 : : static void
75 : 1772 : nvme_fabric_prop_set_cmd_done(void *ctx, const struct spdk_nvme_cpl *cpl)
76 : : {
77 : 1772 : struct nvme_fabric_prop_ctx *prop_ctx = ctx;
78 : :
79 : 1772 : prop_ctx->cb_fn(prop_ctx->cb_arg, prop_ctx->value, cpl);
80 : 1772 : free(prop_ctx);
81 : 1772 : }
82 : :
83 : : static int
84 : 1772 : 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 : 1772 : ctx = calloc(1, sizeof(*ctx));
92 [ - + ]: 1772 : if (ctx == NULL) {
93 : 0 : SPDK_ERRLOG("Failed to allocate fabrics property context\n");
94 : 0 : return -ENOMEM;
95 : : }
96 : :
97 : 1772 : ctx->value = value;
98 : 1772 : ctx->cb_fn = cb_fn;
99 : 1772 : ctx->cb_arg = cb_arg;
100 : :
101 : 1772 : rc = nvme_fabric_prop_set_cmd(ctrlr, offset, size, value,
102 : : nvme_fabric_prop_set_cmd_done, ctx);
103 [ - + ]: 1772 : if (rc != 0) {
104 : 0 : SPDK_ERRLOG("Failed to send Property Set fabrics command\n");
105 : 0 : free(ctx);
106 : : }
107 : :
108 : 1772 : return rc;
109 : : }
110 : :
111 : : static int
112 : 58377 : 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 : 58377 : struct spdk_nvmf_fabric_prop_set_cmd cmd = {};
116 : :
117 [ + + - + ]: 58377 : assert(size == SPDK_NVMF_PROP_SIZE_4 || size == SPDK_NVMF_PROP_SIZE_8);
118 : :
119 : 58377 : cmd.opcode = SPDK_NVME_OPC_FABRIC;
120 : 58377 : cmd.fctype = SPDK_NVMF_FABRIC_COMMAND_PROPERTY_GET;
121 : 58377 : cmd.ofst = offset;
122 : 58377 : cmd.attrib.size = size;
123 : :
124 : 58377 : 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 : 1777 : 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 : 1777 : status = calloc(1, sizeof(*status));
137 [ - + ]: 1777 : if (!status) {
138 : 0 : SPDK_ERRLOG("Failed to allocate status tracker\n");
139 : 0 : return -ENOMEM;
140 : : }
141 : :
142 : 1777 : rc = nvme_fabric_prop_get_cmd(ctrlr, offset, size, nvme_completion_poll_cb, status);
143 [ - + ]: 1777 : if (rc < 0) {
144 : 0 : free(status);
145 : 0 : return rc;
146 : : }
147 : :
148 [ - + ]: 1777 : 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 : 1777 : response = (struct spdk_nvmf_fabric_prop_get_rsp *)&status->cpl;
157 : :
158 [ + + ]: 1777 : if (size == SPDK_NVMF_PROP_SIZE_4) {
159 : 1771 : *value = response->value.u32.low;
160 : : } else {
161 : 6 : *value = response->value.u64;
162 : : }
163 : :
164 : 1777 : free(status);
165 : :
166 : 1777 : return 0;
167 : : }
168 : :
169 : : static void
170 : 56597 : nvme_fabric_prop_get_cmd_done(void *ctx, const struct spdk_nvme_cpl *cpl)
171 : : {
172 : 56597 : struct nvme_fabric_prop_ctx *prop_ctx = ctx;
173 : : struct spdk_nvmf_fabric_prop_get_rsp *response;
174 : 56597 : uint64_t value = 0;
175 : :
176 [ + - + - ]: 56597 : if (spdk_nvme_cpl_is_success(cpl)) {
177 : 56597 : response = (struct spdk_nvmf_fabric_prop_get_rsp *)cpl;
178 : :
179 [ + + - ]: 56597 : switch (prop_ctx->size) {
180 : 55677 : case SPDK_NVMF_PROP_SIZE_4:
181 : 55677 : value = response->value.u32.low;
182 : 55677 : break;
183 : 920 : case SPDK_NVMF_PROP_SIZE_8:
184 : 920 : value = response->value.u64;
185 : 920 : break;
186 : 0 : default:
187 : 0 : assert(0 && "Should never happen");
188 : : }
189 : 0 : }
190 : :
191 : 56597 : prop_ctx->cb_fn(prop_ctx->cb_arg, value, cpl);
192 : 56597 : free(prop_ctx);
193 : 56597 : }
194 : :
195 : : static int
196 : 56600 : 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 : 56600 : ctx = calloc(1, sizeof(*ctx));
203 [ - + ]: 56600 : if (ctx == NULL) {
204 : 0 : SPDK_ERRLOG("Failed to allocate fabrics property context\n");
205 : 0 : return -ENOMEM;
206 : : }
207 : :
208 : 56600 : ctx->size = size;
209 : 56600 : ctx->cb_fn = cb_fn;
210 : 56600 : ctx->cb_arg = cb_arg;
211 : :
212 : 56600 : rc = nvme_fabric_prop_get_cmd(ctrlr, offset, size, nvme_fabric_prop_get_cmd_done, ctx);
213 [ + + ]: 56600 : if (rc != 0) {
214 : 3 : SPDK_ERRLOG("Failed to send Property Get fabrics command\n");
215 : 3 : free(ctx);
216 : : }
217 : :
218 : 56600 : 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 : 1765 : 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 : 1765 : rc = nvme_fabric_prop_get_cmd_sync(ctrlr, offset, SPDK_NVMF_PROP_SIZE_4, &tmp_value);
239 : :
240 [ + - ]: 1765 : if (!rc) {
241 : 1765 : *value = (uint32_t)tmp_value;
242 : : }
243 : 1765 : 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 : 1772 : 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 : 1772 : 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 : 55680 : 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 : 55680 : return nvme_fabric_prop_get_cmd_async(ctrlr, offset, SPDK_NVMF_PROP_SIZE_4, cb_fn, cb_arg);
273 : : }
274 : :
275 : : int
276 : 920 : 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 : 920 : return nvme_fabric_prop_get_cmd_async(ctrlr, offset, SPDK_NVMF_PROP_SIZE_8, cb_fn, cb_arg);
280 : : }
281 : :
282 : : static void
283 : 179 : 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 : 15 : struct spdk_nvme_transport_id trid;
288 : : uint8_t *end;
289 : : size_t len;
290 : :
291 : 179 : memset(&trid, 0, sizeof(trid));
292 : :
293 [ + + ]: 179 : if (entry->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY_CURRENT ||
294 [ - + ]: 91 : entry->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY) {
295 : 88 : SPDK_WARNLOG("Skipping unsupported current discovery service or"
296 : : " discovery service referral\n");
297 : 88 : return;
298 [ - + ]: 91 : } 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 : 91 : trid.trtype = entry->trtype;
304 : 91 : spdk_nvme_transport_id_populate_trstring(&trid, spdk_nvme_transport_id_trtype_str(entry->trtype));
305 [ - + ]: 91 : 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 : 91 : trid.adrfam = entry->adrfam;
312 : :
313 : : /* Ensure that subnqn is null terminated. */
314 [ - + ]: 91 : end = memchr(entry->subnqn, '\0', SPDK_NVMF_NQN_MAX_LEN + 1);
315 [ - + ]: 91 : if (!end) {
316 : 0 : SPDK_ERRLOG("Discovery entry SUBNQN is not null terminated\n");
317 : 0 : return;
318 : : }
319 : 91 : len = end - entry->subnqn;
320 [ - + ]: 91 : memcpy(trid.subnqn, entry->subnqn, len);
321 : 91 : trid.subnqn[len] = '\0';
322 : :
323 : : /* Convert traddr to a null terminated string. */
324 : 91 : len = spdk_strlen_pad(entry->traddr, sizeof(entry->traddr), ' ');
325 [ - + ]: 91 : memcpy(trid.traddr, entry->traddr, len);
326 [ - + ]: 91 : 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 : 91 : len = spdk_strlen_pad(entry->trsvcid, sizeof(entry->trsvcid), ' ');
332 [ - + ]: 91 : memcpy(trid.trsvcid, entry->trsvcid, len);
333 [ - + ]: 91 : if (spdk_str_chomp(trid.trsvcid) != 0) {
334 [ # # # # ]: 0 : SPDK_DEBUGLOG(nvme, "Trailing newlines removed from discovery TRSVCID\n");
335 : : }
336 : :
337 [ - + - + ]: 91 : 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 : 91 : trid.priority = discover_priority;
343 : :
344 : 91 : nvme_ctrlr_probe(&trid, probe_ctx, NULL);
345 : : }
346 : :
347 : : static int
348 : 103 : 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 : 103 : status = calloc(1, sizeof(*status));
355 [ - + ]: 103 : if (!status) {
356 : 0 : SPDK_ERRLOG("Failed to allocate status tracker\n");
357 : 0 : return -ENOMEM;
358 : : }
359 : :
360 : 103 : 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 [ + + ]: 103 : if (rc < 0) {
363 : 12 : free(status);
364 : 12 : return -1;
365 : : }
366 : :
367 [ - + ]: 91 : 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 : 91 : free(status);
374 : :
375 : 91 : return 0;
376 : : }
377 : :
378 : : int
379 : 819 : 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 [ - + + + ]: 819 : 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 : 685 : rc = nvme_ctrlr_probe(&probe_ctx->trid, probe_ctx, NULL);
390 : 685 : return rc;
391 : : }
392 : :
393 : 134 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&discovery_opts, sizeof(discovery_opts));
394 [ + + + - ]: 134 : if (direct_connect && probe_ctx->probe_cb) {
395 : 47 : probe_ctx->probe_cb(probe_ctx->cb_ctx, &probe_ctx->trid, &discovery_opts);
396 : : }
397 : :
398 : 134 : discovery_ctrlr = nvme_transport_ctrlr_construct(&probe_ctx->trid, &discovery_opts, NULL);
399 [ + + ]: 134 : if (discovery_ctrlr == NULL) {
400 : 11 : return -1;
401 : : }
402 : :
403 [ + + ]: 952812 : while (discovery_ctrlr->state != NVME_CTRLR_STATE_READY) {
404 [ + + ]: 952690 : if (nvme_ctrlr_process_init(discovery_ctrlr) != 0) {
405 : 1 : nvme_ctrlr_destruct(discovery_ctrlr);
406 : 1 : return -1;
407 : : }
408 : : }
409 : :
410 : 122 : status = calloc(1, sizeof(*status));
411 [ - + ]: 122 : 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 : 122 : rc = nvme_ctrlr_cmd_identify(discovery_ctrlr, SPDK_NVME_IDENTIFY_CTRLR, 0, 0, 0,
419 : 122 : &discovery_ctrlr->cdata, sizeof(discovery_ctrlr->cdata),
420 : : nvme_completion_poll_cb, status);
421 [ - + ]: 122 : 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 [ - + ]: 122 : 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 : 122 : free(status);
438 : :
439 : : /* Direct attach through spdk_nvme_connect() API */
440 [ + + ]: 122 : if (direct_connect == true) {
441 : : /* Set the ready state to skip the normal init process */
442 : 37 : discovery_ctrlr->state = NVME_CTRLR_STATE_READY;
443 : 37 : nvme_ctrlr_connected(probe_ctx, discovery_ctrlr);
444 : 37 : nvme_ctrlr_add_process(discovery_ctrlr, 0);
445 : 37 : return 0;
446 : : }
447 : :
448 : 85 : rc = nvme_fabric_ctrlr_discover(discovery_ctrlr, probe_ctx);
449 : 85 : nvme_ctrlr_destruct(discovery_ctrlr);
450 : 85 : return rc;
451 : : }
452 : :
453 : : int
454 : 85 : 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 : 85 : uint64_t i, numrec, buffer_max_entries_first, buffer_max_entries, log_page_offset = 0;
462 : 85 : uint64_t remaining_num_rec = 0;
463 : : uint16_t recfmt;
464 : :
465 [ - + ]: 85 : memset(buffer, 0x0, 4096);
466 : 85 : 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 : 85 : buffer_max_entries = sizeof(buffer) / sizeof(struct spdk_nvmf_discovery_log_page_entry);
470 : : do {
471 : 85 : rc = nvme_fabric_get_discovery_log_page(ctrlr, buffer, sizeof(buffer), log_page_offset);
472 [ - + ]: 85 : if (rc < 0) {
473 [ # # # # ]: 0 : SPDK_DEBUGLOG(nvme, "Get Log Page - Discovery error\n");
474 : 0 : return rc;
475 : : }
476 : :
477 [ + - ]: 85 : if (!remaining_num_rec) {
478 : 85 : log_page = (struct spdk_nvmf_discovery_log_page *)buffer;
479 : 85 : recfmt = from_le16(&log_page->recfmt);
480 [ - + ]: 85 : if (recfmt != 0) {
481 : 0 : SPDK_ERRLOG("Unrecognized discovery log record format %" PRIu16 "\n", recfmt);
482 : 0 : return -EPROTO;
483 : : }
484 : 85 : remaining_num_rec = log_page->numrec;
485 : 85 : log_page_offset = offsetof(struct spdk_nvmf_discovery_log_page, entries[0]);
486 : 85 : log_page_entry = &log_page->entries[0];
487 : 85 : 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 [ + + ]: 246 : for (i = 0; i < numrec; i++) {
494 : 161 : nvme_fabric_discover_probe(log_page_entry++, probe_ctx, ctrlr->trid.priority);
495 : : }
496 : 85 : remaining_num_rec -= numrec;
497 : 85 : log_page_offset += numrec * sizeof(struct spdk_nvmf_discovery_log_page_entry);
498 [ - + ]: 85 : } while (remaining_num_rec != 0);
499 : :
500 : 85 : return 0;
501 : : }
502 : :
503 : : int
504 : 4274 : nvme_fabric_qpair_connect_async(struct spdk_nvme_qpair *qpair, uint32_t num_entries)
505 : : {
506 : : struct nvme_completion_poll_status *status;
507 : 119 : 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 [ + + - + ]: 4274 : if (num_entries == 0 || num_entries > SPDK_NVME_IO_QUEUE_MAX_ENTRIES) {
514 : 6 : return -EINVAL;
515 : : }
516 : :
517 : 4268 : ctrlr = qpair->ctrlr;
518 [ - + ]: 4268 : if (!ctrlr) {
519 : 0 : return -EINVAL;
520 : : }
521 : :
522 : 4268 : nvmf_data = spdk_zmalloc(sizeof(*nvmf_data), 0, NULL,
523 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
524 [ - + ]: 4268 : if (!nvmf_data) {
525 : 0 : SPDK_ERRLOG("nvmf_data allocation error\n");
526 : 0 : return -ENOMEM;
527 : : }
528 : :
529 : 4268 : status = calloc(1, sizeof(*status));
530 [ - + ]: 4268 : 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 : 4268 : status->dma_data = nvmf_data;
537 : :
538 [ - + ]: 4268 : memset(&cmd, 0, sizeof(cmd));
539 : 4268 : cmd.opcode = SPDK_NVME_OPC_FABRIC;
540 : 4268 : cmd.fctype = SPDK_NVMF_FABRIC_COMMAND_CONNECT;
541 : 4268 : cmd.qid = qpair->id;
542 : 4268 : cmd.sqsize = num_entries - 1;
543 : 4268 : cmd.kato = ctrlr->opts.keep_alive_timeout_ms;
544 : :
545 [ - + ]: 4268 : assert(qpair->reserved_req != NULL);
546 : 4268 : req = qpair->reserved_req;
547 [ - + ]: 4268 : memcpy(&req->cmd, &cmd, sizeof(cmd));
548 : :
549 [ + + ]: 4268 : if (nvme_qpair_is_admin_queue(qpair)) {
550 : 933 : nvmf_data->cntlid = 0xFFFF;
551 : : } else {
552 : 3335 : 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 : 4268 : memcpy(nvmf_data->hostid, ctrlr->opts.extended_host_id, sizeof(nvmf_data->hostid));
558 [ - + ]: 4268 : snprintf(nvmf_data->hostnqn, sizeof(nvmf_data->hostnqn), "%s", ctrlr->opts.hostnqn);
559 [ - + ]: 4268 : snprintf(nvmf_data->subnqn, sizeof(nvmf_data->subnqn), "%s", ctrlr->trid.subnqn);
560 : :
561 : 4268 : NVME_INIT_REQUEST(req, nvme_completion_poll_cb, status, NVME_PAYLOAD_CONTIG(nvmf_data, NULL),
562 : : sizeof(*nvmf_data), 0);
563 : :
564 : 4268 : rc = nvme_qpair_submit_request(qpair, req);
565 [ - + ]: 4268 : 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 [ - + ]: 4268 : 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 : 4268 : qpair->poll_status = status;
579 : 4268 : return 0;
580 : : }
581 : :
582 : : int
583 : 281994 : 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 : 281994 : int rc = 0;
589 : :
590 : 281994 : ctrlr = qpair->ctrlr;
591 : 281994 : status = qpair->poll_status;
592 : :
593 [ + + ]: 281994 : if (nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL) == -EAGAIN) {
594 : 277727 : return -EAGAIN;
595 : : }
596 : :
597 [ + + + + : 4267 : if (status->timed_out || spdk_nvme_cpl_is_error(&status->cpl)) {
+ + - + ]
598 [ + + + + ]: 769 : 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 [ + + + + ]: 769 : if (status->timed_out) {
607 : 6 : rc = -ECANCELED;
608 : : } else {
609 : 763 : SPDK_ERRLOG("Connect command completed with error: sct %d, sc %d\n",
610 : : status->cpl.status.sct, status->cpl.status.sc);
611 : 763 : rc = -EIO;
612 : : }
613 : :
614 : 769 : goto finish;
615 : : }
616 : :
617 [ + + ]: 3498 : if (nvme_qpair_is_admin_queue(qpair)) {
618 : 926 : rsp = (struct spdk_nvmf_fabric_connect_rsp *)&status->cpl;
619 : 926 : ctrlr->cntlid = rsp->status_code_specific.success.cntlid;
620 [ + + + + ]: 926 : SPDK_DEBUGLOG(nvme, "CNTLID 0x%04" PRIx16 "\n", ctrlr->cntlid);
621 : : }
622 : 3490 : finish:
623 : 4267 : qpair->poll_status = NULL;
624 [ + + + + ]: 4267 : if (!status->timed_out) {
625 : 4261 : spdk_free(status->dma_data);
626 : 4261 : free(status);
627 : : }
628 : :
629 : 4267 : return rc;
630 : : }
631 : :
632 : : int
633 : 24 : nvme_fabric_qpair_connect(struct spdk_nvme_qpair *qpair, uint32_t num_entries)
634 : : {
635 : : int rc;
636 : :
637 : 24 : rc = nvme_fabric_qpair_connect_async(qpair, num_entries);
638 [ + + ]: 24 : if (rc) {
639 : 6 : return rc;
640 : : }
641 : :
642 : : do {
643 : : /* Wait until the command completes or times out */
644 : 18 : rc = nvme_fabric_qpair_connect_poll(qpair);
645 [ - + ]: 18 : } while (rc == -EAGAIN);
646 : :
647 : 18 : return rc;
648 : : }
|