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 : 3856 : 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 : 3856 : struct spdk_nvmf_fabric_prop_set_cmd cmd = {};
29 : :
30 [ + + + + : 3856 : assert(size == SPDK_NVMF_PROP_SIZE_4 || size == SPDK_NVMF_PROP_SIZE_8);
# # ]
31 : :
32 : 3856 : cmd.opcode = SPDK_NVME_OPC_FABRIC;
33 : 3856 : cmd.fctype = SPDK_NVMF_FABRIC_COMMAND_PROPERTY_SET;
34 : 3856 : cmd.ofst = offset;
35 : 3856 : cmd.attrib.size = size;
36 [ + - ]: 3856 : cmd.value.u64 = value;
37 : :
38 : 5934 : return spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, (struct spdk_nvme_cmd *)&cmd,
39 : 2077 : NULL, 0, cb_fn, cb_arg);
40 : 1 : }
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 : 1 : struct nvme_completion_poll_status *status;
47 : 1 : 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 : 7 : rc = nvme_fabric_prop_set_cmd(ctrlr, offset, size, value,
56 : 1 : 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 : 0 : }
66 : 0 : SPDK_ERRLOG("Property Set failed\n");
67 : 0 : return -1;
68 : : }
69 : 6 : free(status);
70 : :
71 : 6 : return 0;
72 : 1 : }
73 : :
74 : : static void
75 : 3850 : nvme_fabric_prop_set_cmd_done(void *ctx, const struct spdk_nvme_cpl *cpl)
76 : : {
77 : 3850 : struct nvme_fabric_prop_ctx *prop_ctx = ctx;
78 : :
79 [ + - + - : 3850 : prop_ctx->cb_fn(prop_ctx->cb_arg, prop_ctx->value, cpl);
- + + - +
- + - + -
+ - ]
80 : 3850 : free(prop_ctx);
81 : 3850 : }
82 : :
83 : : static int
84 : 3850 : 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 : 0 : struct nvme_fabric_prop_ctx *ctx;
89 : 0 : int rc;
90 : :
91 : 3850 : ctx = calloc(1, sizeof(*ctx));
92 [ + + ]: 3850 : if (ctx == NULL) {
93 : 0 : SPDK_ERRLOG("Failed to allocate fabrics property context\n");
94 : 0 : return -ENOMEM;
95 : : }
96 : :
97 [ + - + - ]: 3850 : ctx->value = value;
98 [ + - + - ]: 3850 : ctx->cb_fn = cb_fn;
99 [ + - + - ]: 3850 : ctx->cb_arg = cb_arg;
100 : :
101 : 5926 : rc = nvme_fabric_prop_set_cmd(ctrlr, offset, size, value,
102 : 2076 : nvme_fabric_prop_set_cmd_done, ctx);
103 [ + + ]: 3850 : if (rc != 0) {
104 : 0 : SPDK_ERRLOG("Failed to send Property Set fabrics command\n");
105 : 0 : free(ctx);
106 : 0 : }
107 : :
108 : 3850 : return rc;
109 : 2076 : }
110 : :
111 : : static int
112 : 72559 : 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 : 72559 : struct spdk_nvmf_fabric_prop_set_cmd cmd = {};
116 : :
117 [ + + + + : 72559 : assert(size == SPDK_NVMF_PROP_SIZE_4 || size == SPDK_NVMF_PROP_SIZE_8);
# # ]
118 : :
119 : 72559 : cmd.opcode = SPDK_NVME_OPC_FABRIC;
120 : 72559 : cmd.fctype = SPDK_NVMF_FABRIC_COMMAND_PROPERTY_GET;
121 : 72559 : cmd.ofst = offset;
122 : 72559 : cmd.attrib.size = size;
123 : :
124 : 79831 : return spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, (struct spdk_nvme_cmd *)&cmd,
125 : 7270 : NULL, 0, cb_fn, cb_arg);
126 : 2 : }
127 : :
128 : : static int
129 : 1787 : nvme_fabric_prop_get_cmd_sync(struct spdk_nvme_ctrlr *ctrlr,
130 : : uint32_t offset, uint8_t size, uint64_t *value)
131 : : {
132 : 2 : struct nvme_completion_poll_status *status;
133 : 2 : struct spdk_nvmf_fabric_prop_get_rsp *response;
134 : 2 : int rc;
135 : :
136 : 1787 : status = calloc(1, sizeof(*status));
137 [ + + ]: 1787 : if (!status) {
138 : 0 : SPDK_ERRLOG("Failed to allocate status tracker\n");
139 : 0 : return -ENOMEM;
140 : : }
141 : :
142 : 1787 : rc = nvme_fabric_prop_get_cmd(ctrlr, offset, size, nvme_completion_poll_cb, status);
143 [ - + ]: 1787 : if (rc < 0) {
144 : 0 : free(status);
145 : 0 : return rc;
146 : : }
147 : :
148 [ + + + - : 1787 : 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 [ + - ]: 1787 : response = (struct spdk_nvmf_fabric_prop_get_rsp *)&status->cpl;
157 : :
158 [ + + ]: 1787 : if (size == SPDK_NVMF_PROP_SIZE_4) {
159 [ - + - + : 1781 : *value = response->value.u32.low;
- + - + -
+ ]
160 : 1 : } else {
161 [ + - + - : 6 : *value = response->value.u64;
+ - + - ]
162 : : }
163 : :
164 : 1787 : free(status);
165 : :
166 : 1787 : return 0;
167 : 2 : }
168 : :
169 : : static void
170 : 70769 : nvme_fabric_prop_get_cmd_done(void *ctx, const struct spdk_nvme_cpl *cpl)
171 : : {
172 : 70769 : struct nvme_fabric_prop_ctx *prop_ctx = ctx;
173 : 0 : struct spdk_nvmf_fabric_prop_get_rsp *response;
174 : 70769 : uint64_t value = 0;
175 : :
176 [ + - + - : 70769 : if (spdk_nvme_cpl_is_success(cpl)) {
+ - + - +
- + - + -
- + ]
177 : 70769 : response = (struct spdk_nvmf_fabric_prop_get_rsp *)cpl;
178 : :
179 [ + + + - : 70769 : switch (prop_ctx->size) {
+ - + ]
180 : 62580 : case SPDK_NVMF_PROP_SIZE_4:
181 [ + - + - : 68810 : value = response->value.u32.low;
+ - + - ]
182 : 68810 : break;
183 : 921 : case SPDK_NVMF_PROP_SIZE_8:
184 [ + - + - : 1959 : value = response->value.u64;
+ - ]
185 : 1959 : break;
186 : 0 : default:
187 [ # # ]: 0 : assert(0 && "Should never happen");
188 : : }
189 : 7268 : }
190 : :
191 [ + - + - : 70769 : prop_ctx->cb_fn(prop_ctx->cb_arg, value, cpl);
- + + - +
- + - ]
192 : 70769 : free(prop_ctx);
193 : 70769 : }
194 : :
195 : : static int
196 : 70772 : 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 : 0 : struct nvme_fabric_prop_ctx *ctx;
200 : 0 : int rc;
201 : :
202 : 70772 : ctx = calloc(1, sizeof(*ctx));
203 [ + + ]: 70772 : if (ctx == NULL) {
204 : 0 : SPDK_ERRLOG("Failed to allocate fabrics property context\n");
205 : 0 : return -ENOMEM;
206 : : }
207 : :
208 [ + - + - ]: 70772 : ctx->size = size;
209 [ + - + - ]: 70772 : ctx->cb_fn = cb_fn;
210 [ + - + - ]: 70772 : ctx->cb_arg = cb_arg;
211 : :
212 : 70772 : rc = nvme_fabric_prop_get_cmd(ctrlr, offset, size, nvme_fabric_prop_get_cmd_done, ctx);
213 [ + + ]: 70772 : if (rc != 0) {
214 : 3 : SPDK_ERRLOG("Failed to send Property Get fabrics command\n");
215 : 3 : free(ctx);
216 : 0 : }
217 : :
218 : 70772 : return rc;
219 : 7268 : }
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 : 1775 : 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 : 0 : int rc;
238 : 1775 : rc = nvme_fabric_prop_get_cmd_sync(ctrlr, offset, SPDK_NVMF_PROP_SIZE_4, &tmp_value);
239 : :
240 [ + - ]: 1775 : if (!rc) {
241 [ # # ]: 1775 : *value = (uint32_t)tmp_value;
242 : 0 : }
243 : 1775 : return rc;
244 : 0 : }
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 : 3850 : 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 : 5926 : return nvme_fabric_prop_set_cmd_async(ctrlr, offset, SPDK_NVMF_PROP_SIZE_4, value,
257 : 2076 : 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 : 68813 : 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 : 68813 : return nvme_fabric_prop_get_cmd_async(ctrlr, offset, SPDK_NVMF_PROP_SIZE_4, cb_fn, cb_arg);
273 : : }
274 : :
275 : : int
276 : 1959 : 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 : 1959 : 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 : 3 : uint8_t *end;
289 : 3 : size_t len;
290 : :
291 [ + - ]: 179 : memset(&trid, 0, sizeof(trid));
292 : :
293 [ + + + - : 180 : 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 : 0 : }
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 : 0 : }
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 [ - + ]: 3 : }
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 : 3 : struct nvme_completion_poll_status *status;
352 : 3 : 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 : 106 : 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 [ + + ]: 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 : 0 : }
371 : 0 : return -1;
372 : : }
373 : 91 : free(status);
374 : :
375 : 91 : return 0;
376 : 3 : }
377 : :
378 : : int
379 : 1859 : 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 : 0 : struct spdk_nvme_ctrlr *discovery_ctrlr;
384 : 0 : int rc;
385 : 0 : struct nvme_completion_poll_status *status;
386 : :
387 [ + + + + : 1859 : 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 [ + - ]: 1725 : rc = nvme_ctrlr_probe(&probe_ctx->trid, probe_ctx, NULL);
390 : 1725 : 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 : 0 : }
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 [ + + # # : 1019813 : while (discovery_ctrlr->state != NVME_CTRLR_STATE_READY) {
# # ]
404 [ + + ]: 1019691 : 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 : 0 : 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 : 0 : }
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 : 1038 : }
452 : :
453 : : int
454 : 85 : nvme_fabric_ctrlr_discover(struct spdk_nvme_ctrlr *ctrlr,
455 : : struct spdk_nvme_probe_ctx *probe_ctx)
456 : : {
457 : 0 : struct spdk_nvmf_discovery_log_page *log_page;
458 : 0 : struct spdk_nvmf_discovery_log_page_entry *log_page_entry;
459 : 0 : char buffer[4096];
460 : 0 : 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 : 0 : 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 : 0 : 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 : 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 [ + + ]: 246 : for (i = 0; i < numrec; i++) {
494 [ # # # # : 161 : nvme_fabric_discover_probe(log_page_entry++, probe_ctx, ctrlr->trid.priority);
# # # # ]
495 : 0 : }
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 : 0 : }
502 : :
503 : : int
504 : 6379 : nvme_fabric_qpair_connect_async(struct spdk_nvme_qpair *qpair, uint32_t num_entries)
505 : : {
506 : 4 : struct nvme_completion_poll_status *status;
507 : 119 : struct spdk_nvmf_fabric_connect_cmd cmd;
508 : 4 : struct spdk_nvmf_fabric_connect_data *nvmf_data;
509 : 4 : struct spdk_nvme_ctrlr *ctrlr;
510 : 4 : struct nvme_request *req;
511 : 4 : int rc;
512 : :
513 [ + + - + ]: 6379 : if (num_entries == 0 || num_entries > SPDK_NVME_IO_QUEUE_MAX_ENTRIES) {
514 : 6 : return -EINVAL;
515 : : }
516 : :
517 [ + - + - ]: 6373 : ctrlr = qpair->ctrlr;
518 [ + + ]: 6373 : if (!ctrlr) {
519 : 0 : return -EINVAL;
520 : : }
521 : :
522 : 6373 : nvmf_data = spdk_zmalloc(sizeof(*nvmf_data), 0, NULL,
523 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
524 [ + + ]: 6373 : if (!nvmf_data) {
525 : 0 : SPDK_ERRLOG("nvmf_data allocation error\n");
526 : 0 : return -ENOMEM;
527 : : }
528 : :
529 : 6373 : status = calloc(1, sizeof(*status));
530 [ + + ]: 6373 : 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 [ + - + - ]: 6373 : status->dma_data = nvmf_data;
537 : :
538 [ + + ]: 6373 : memset(&cmd, 0, sizeof(cmd));
539 : 6373 : cmd.opcode = SPDK_NVME_OPC_FABRIC;
540 : 6373 : cmd.fctype = SPDK_NVMF_FABRIC_COMMAND_CONNECT;
541 [ + - + - ]: 6373 : cmd.qid = qpair->id;
542 : 6373 : cmd.sqsize = num_entries - 1;
543 [ + - + - : 6373 : cmd.kato = ctrlr->opts.keep_alive_timeout_ms;
+ - ]
544 : :
545 [ + + + - : 6373 : assert(qpair->reserved_req != NULL);
+ - # # ]
546 [ + - + - ]: 6373 : req = qpair->reserved_req;
547 [ + - + - : 6373 : memcpy(&req->cmd, &cmd, sizeof(cmd));
+ - ]
548 : :
549 [ + + ]: 6373 : if (nvme_qpair_is_admin_queue(qpair)) {
550 [ + - + - ]: 1972 : nvmf_data->cntlid = 0xFFFF;
551 : 1040 : } else {
552 [ + - + - : 4401 : 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 [ + - + - : 6373 : memcpy(nvmf_data->hostid, ctrlr->opts.extended_host_id, sizeof(nvmf_data->hostid));
+ - + - +
- ]
558 [ + + + - : 6373 : snprintf(nvmf_data->hostnqn, sizeof(nvmf_data->hostnqn), "%s", ctrlr->opts.hostnqn);
+ - ]
559 [ + + + - : 6373 : snprintf(nvmf_data->subnqn, sizeof(nvmf_data->subnqn), "%s", ctrlr->trid.subnqn);
+ - ]
560 : :
561 [ + - + - : 6373 : NVME_INIT_REQUEST(req, nvme_completion_poll_cb, status, NVME_PAYLOAD_CONTIG(nvmf_data, NULL),
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
562 : : sizeof(*nvmf_data), 0);
563 : :
564 : 6373 : rc = nvme_qpair_submit_request(qpair, req);
565 [ + + ]: 6373 : 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 [ + + + - : 6373 : 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 [ + - + - ]: 6373 : qpair->poll_status = status;
579 : 6373 : return 0;
580 : 2080 : }
581 : :
582 : : int
583 : 328713 : nvme_fabric_qpair_connect_poll(struct spdk_nvme_qpair *qpair)
584 : : {
585 : 3 : struct nvme_completion_poll_status *status;
586 : 3 : struct spdk_nvmf_fabric_connect_rsp *rsp;
587 : 3 : struct spdk_nvme_ctrlr *ctrlr;
588 : 328713 : int rc = 0;
589 : :
590 [ + - + - ]: 328713 : ctrlr = qpair->ctrlr;
591 [ + - + - ]: 328713 : status = qpair->poll_status;
592 : :
593 [ + + ]: 328713 : if (nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL) == -EAGAIN) {
594 : 322340 : return -EAGAIN;
595 : : }
596 : :
597 [ + + + + : 6373 : if (status->timed_out || spdk_nvme_cpl_is_error(&status->cpl)) {
+ + + + +
- + - + -
+ - + - +
- + - + -
+ - + - ]
598 [ + + + + : 787 : 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 [ + + + + : 787 : if (status->timed_out) {
+ - + - ]
607 : 6 : rc = -ECANCELED;
608 : 1 : } else {
609 [ # # # # : 781 : SPDK_ERRLOG("Connect command completed with error: sct %d, sc %d\n",
# # # # #
# # # # #
# # ]
610 : : status->cpl.status.sct, status->cpl.status.sc);
611 : 781 : rc = -EIO;
612 : : }
613 : :
614 : 787 : goto finish;
615 : : }
616 : :
617 [ + + ]: 6625 : if (nvme_qpair_is_admin_queue(qpair)) {
618 [ + - ]: 1965 : rsp = (struct spdk_nvmf_fabric_connect_rsp *)&status->cpl;
619 [ + - + - : 1965 : ctrlr->cntlid = rsp->status_code_specific.success.cntlid;
+ - + - +
- + - ]
620 [ + + + + : 1965 : SPDK_DEBUGLOG(nvme, "CNTLID 0x%04" PRIx16 "\n", ctrlr->cntlid);
+ - # # #
# ]
621 : 1039 : }
622 : 3500 : finish:
623 [ + - + - ]: 6373 : qpair->poll_status = NULL;
624 [ + + + + : 6373 : if (!status->timed_out) {
+ - + + ]
625 [ + - + - ]: 6367 : spdk_free(status->dma_data);
626 : 6367 : free(status);
627 : 2078 : }
628 : :
629 : 6373 : return rc;
630 : 17492 : }
631 : :
632 : : int
633 : 24 : nvme_fabric_qpair_connect(struct spdk_nvme_qpair *qpair, uint32_t num_entries)
634 : : {
635 : 4 : 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 : 3 : 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 : 4 : }
|