Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2015 Intel Corporation. All rights reserved.
3 : : * Copyright (c) 2020 Mellanox Technologies LTD. All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/config.h"
7 : : #include "spdk/nvmf_spec.h"
8 : : #include "spdk/string.h"
9 : : #include "spdk/env.h"
10 : : #include "nvme_internal.h"
11 : : #include "nvme_io_msg.h"
12 : :
13 : : #define SPDK_NVME_DRIVER_NAME "spdk_nvme_driver"
14 : :
15 : : struct nvme_driver *g_spdk_nvme_driver;
16 : : pid_t g_spdk_nvme_pid;
17 : :
18 : : /* gross timeout of 180 seconds in milliseconds */
19 : : static int g_nvme_driver_timeout_ms = 3 * 60 * 1000;
20 : :
21 : : /* Per-process attached controller list */
22 : : static TAILQ_HEAD(, spdk_nvme_ctrlr) g_nvme_attached_ctrlrs =
23 : : TAILQ_HEAD_INITIALIZER(g_nvme_attached_ctrlrs);
24 : :
25 : : /* Returns true if ctrlr should be stored on the multi-process shared_attached_ctrlrs list */
26 : : static bool
27 : 6217 : nvme_ctrlr_shared(const struct spdk_nvme_ctrlr *ctrlr)
28 : : {
29 [ + - + - : 6217 : return ctrlr->trid.trtype == SPDK_NVME_TRANSPORT_PCIE;
+ - ]
30 : : }
31 : :
32 : : void
33 : 41 : nvme_ctrlr_connected(struct spdk_nvme_probe_ctx *probe_ctx,
34 : : struct spdk_nvme_ctrlr *ctrlr)
35 : : {
36 [ # # # # : 41 : TAILQ_INSERT_TAIL(&probe_ctx->init_ctrlrs, ctrlr, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
37 : 41 : }
38 : :
39 : : static void
40 : 3122 : nvme_ctrlr_detach_async_finish(struct spdk_nvme_ctrlr *ctrlr)
41 : : {
42 [ + - ]: 3122 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
43 [ + + ]: 3122 : if (nvme_ctrlr_shared(ctrlr)) {
44 [ + + + - : 738 : TAILQ_REMOVE(&g_spdk_nvme_driver->shared_attached_ctrlrs, ctrlr, tailq);
+ - + - #
# # # # #
# # # # #
# # # # #
# # + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
45 : 37 : } else {
46 [ + + + - : 2384 : TAILQ_REMOVE(&g_nvme_attached_ctrlrs, ctrlr, tailq);
+ - + - #
# # # # #
# # # # #
# # # # #
# # + - +
- + - + -
+ - + - +
- + - + -
+ - + - ]
47 : : }
48 [ + - ]: 3122 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
49 : 3122 : }
50 : :
51 : : static int
52 : 3351 : nvme_ctrlr_detach_async(struct spdk_nvme_ctrlr *ctrlr,
53 : : struct nvme_ctrlr_detach_ctx **_ctx)
54 : : {
55 : : struct nvme_ctrlr_detach_ctx *ctx;
56 : : int ref_count;
57 : :
58 [ + - ]: 3351 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
59 : :
60 : 3351 : ref_count = nvme_ctrlr_get_ref_count(ctrlr);
61 [ + + # # ]: 3351 : assert(ref_count > 0);
62 : :
63 [ + + ]: 3351 : if (ref_count == 1) {
64 : : /* This is the last reference to the controller, so we need to
65 : : * allocate a context to destruct it.
66 : : */
67 : 3122 : ctx = calloc(1, sizeof(*ctx));
68 [ + + ]: 3122 : if (ctx == NULL) {
69 [ # # ]: 0 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
70 : :
71 : 0 : return -ENOMEM;
72 : : }
73 [ + - + - ]: 3122 : ctx->ctrlr = ctrlr;
74 [ + - + - ]: 3122 : ctx->cb_fn = nvme_ctrlr_detach_async_finish;
75 : :
76 : 3122 : nvme_ctrlr_proc_put_ref(ctrlr);
77 : :
78 : 3122 : nvme_io_msg_ctrlr_detach(ctrlr);
79 : :
80 : 3122 : nvme_ctrlr_destruct_async(ctrlr, ctx);
81 : :
82 [ + - ]: 3122 : *_ctx = ctx;
83 : 851 : } else {
84 : 229 : nvme_ctrlr_proc_put_ref(ctrlr);
85 : : }
86 : :
87 [ + - ]: 3351 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
88 : :
89 : 3351 : return 0;
90 : 852 : }
91 : :
92 : : static int
93 : 16299391 : nvme_ctrlr_detach_poll_async(struct nvme_ctrlr_detach_ctx *ctx)
94 : : {
95 : : int rc;
96 : :
97 [ + - + - ]: 16299391 : rc = nvme_ctrlr_destruct_poll_async(ctx->ctrlr, ctx);
98 [ + + ]: 16299391 : if (rc == -EAGAIN) {
99 : 16296269 : return -EAGAIN;
100 : : }
101 : :
102 : 3122 : free(ctx);
103 : :
104 : 3122 : return rc;
105 : 2551246 : }
106 : :
107 : : int
108 : 423 : spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr)
109 : : {
110 : 423 : struct nvme_ctrlr_detach_ctx *ctx = NULL;
111 : : int rc;
112 : :
113 : 423 : rc = nvme_ctrlr_detach_async(ctrlr, &ctx);
114 [ - + ]: 423 : if (rc != 0) {
115 : 0 : return rc;
116 [ + + ]: 423 : } else if (ctx == NULL) {
117 : : /* ctrlr was detached from the caller process but any other process
118 : : * still attaches it.
119 : : */
120 : 4 : return 0;
121 : : }
122 : :
123 : 39 : while (1) {
124 : 3023 : rc = nvme_ctrlr_detach_poll_async(ctx);
125 [ + + ]: 3023 : if (rc != -EAGAIN) {
126 : 419 : break;
127 : : }
128 : 2604 : nvme_delay(1000);
129 : : }
130 : :
131 : 419 : return 0;
132 : 12 : }
133 : :
134 : : int
135 : 2928 : spdk_nvme_detach_async(struct spdk_nvme_ctrlr *ctrlr,
136 : : struct spdk_nvme_detach_ctx **_detach_ctx)
137 : : {
138 : : struct spdk_nvme_detach_ctx *detach_ctx;
139 : 2928 : struct nvme_ctrlr_detach_ctx *ctx = NULL;
140 : : int rc;
141 : :
142 [ + - - + ]: 2928 : if (ctrlr == NULL || _detach_ctx == NULL) {
143 : 0 : return -EINVAL;
144 : : }
145 : :
146 : : /* Use a context header to poll detachment for multiple controllers.
147 : : * Allocate an new one if not allocated yet, or use the passed one otherwise.
148 : : */
149 [ + - ]: 2928 : detach_ctx = *_detach_ctx;
150 [ + + ]: 2928 : if (detach_ctx == NULL) {
151 : 2881 : detach_ctx = calloc(1, sizeof(*detach_ctx));
152 [ + + ]: 2881 : if (detach_ctx == NULL) {
153 : 0 : return -ENOMEM;
154 : : }
155 [ + - + - : 2881 : TAILQ_INIT(&detach_ctx->head);
+ - + - +
- + - + -
+ - ]
156 : 837 : }
157 : :
158 : 2928 : rc = nvme_ctrlr_detach_async(ctrlr, &ctx);
159 [ + - + + ]: 2928 : if (rc != 0 || ctx == NULL) {
160 : : /* If this detach failed and the context header is empty, it means we just
161 : : * allocated the header and need to free it before returning.
162 : : */
163 [ + - # # : 225 : if (TAILQ_EMPTY(&detach_ctx->head)) {
# # # # ]
164 : 225 : free(detach_ctx);
165 : 0 : }
166 : 225 : return rc;
167 : : }
168 : :
169 : : /* Append a context for this detachment to the context header. */
170 [ + - + - : 2703 : TAILQ_INSERT_TAIL(&detach_ctx->head, ctx, link);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
171 : :
172 [ + - ]: 2703 : *_detach_ctx = detach_ctx;
173 : :
174 : 2703 : return 0;
175 : 840 : }
176 : :
177 : : int
178 : 16296253 : spdk_nvme_detach_poll_async(struct spdk_nvme_detach_ctx *detach_ctx)
179 : : {
180 : : struct nvme_ctrlr_detach_ctx *ctx, *tmp_ctx;
181 : : int rc;
182 : :
183 [ + + ]: 16296253 : if (detach_ctx == NULL) {
184 : 0 : return -EINVAL;
185 : : }
186 : :
187 [ + + + + : 32592621 : TAILQ_FOREACH_SAFE(ctx, &detach_ctx->head, link, tmp_ctx) {
+ - + + +
- + - + -
+ + ]
188 [ + + + - : 16296368 : TAILQ_REMOVE(&detach_ctx->head, ctx, link);
+ - - + #
# # # # #
# # # # #
# # # # #
# # + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
189 : :
190 : 16296368 : rc = nvme_ctrlr_detach_poll_async(ctx);
191 [ + + ]: 16296368 : if (rc == -EAGAIN) {
192 : : /* If not -EAGAIN, ctx was freed by nvme_ctrlr_detach_poll_async(). */
193 [ + + + - : 16293665 : TAILQ_INSERT_HEAD(&detach_ctx->head, ctx, link);
+ - + - +
- + - - +
# # # # #
# # # # #
# # # # #
# + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
194 : 2550367 : }
195 : 2551207 : }
196 : :
197 [ + + + - : 16296253 : if (!TAILQ_EMPTY(&detach_ctx->head)) {
+ - + + ]
198 : 16293597 : return -EAGAIN;
199 : : }
200 : :
201 : 2656 : free(detach_ctx);
202 : 2656 : return 0;
203 : 2551204 : }
204 : :
205 : : void
206 : 1064 : spdk_nvme_detach_poll(struct spdk_nvme_detach_ctx *detach_ctx)
207 : : {
208 [ + + + + ]: 16155883 : while (detach_ctx && spdk_nvme_detach_poll_async(detach_ctx) == -EAGAIN) {
209 : : ;
210 : : }
211 : 1064 : }
212 : :
213 : : void
214 : 17604 : nvme_completion_poll_cb(void *arg, const struct spdk_nvme_cpl *cpl)
215 : : {
216 : 17604 : struct nvme_completion_poll_status *status = arg;
217 : :
218 [ + + + + : 17604 : if (status->timed_out) {
+ - - + ]
219 : : /* There is no routine waiting for the completion of this request, free allocated memory */
220 [ # # # # ]: 0 : spdk_free(status->dma_data);
221 : 0 : free(status);
222 : 0 : return;
223 : : }
224 : :
225 : : /*
226 : : * Copy status into the argument passed by the caller, so that
227 : : * the caller can check the status to determine if the
228 : : * the request passed or failed.
229 : : */
230 [ + - + - : 17604 : memcpy(&status->cpl, cpl, sizeof(*cpl));
+ - ]
231 [ + - + - ]: 17604 : status->done = true;
232 : 1705 : }
233 : :
234 : : static void
235 : 0 : dummy_disconnected_qpair_cb(struct spdk_nvme_qpair *qpair, void *poll_group_ctx)
236 : : {
237 : 0 : }
238 : :
239 : : int
240 : 3328829 : nvme_wait_for_completion_robust_lock_timeout_poll(struct spdk_nvme_qpair *qpair,
241 : : struct nvme_completion_poll_status *status,
242 : : pthread_mutex_t *robust_mutex)
243 : : {
244 : : int rc;
245 : :
246 [ + + ]: 3328829 : if (robust_mutex) {
247 : 606677 : nvme_robust_mutex_lock(robust_mutex);
248 : 5 : }
249 : :
250 [ + + + - : 3328829 : if (qpair->poll_group) {
+ - ]
251 [ # # # # : 1243401 : rc = (int)spdk_nvme_poll_group_process_completions(qpair->poll_group->group, 0,
# # # # ]
252 : : dummy_disconnected_qpair_cb);
253 : 0 : } else {
254 : 2085428 : rc = spdk_nvme_qpair_process_completions(qpair, 0);
255 : : }
256 : :
257 [ + + ]: 3328829 : if (robust_mutex) {
258 : 606677 : nvme_robust_mutex_unlock(robust_mutex);
259 : 5 : }
260 : :
261 [ + + ]: 3328829 : if (rc < 0) {
262 [ # # # # : 16 : status->cpl.status.sct = SPDK_NVME_SCT_GENERIC;
# # # # ]
263 [ # # # # : 16 : status->cpl.status.sc = SPDK_NVME_SC_ABORTED_SQ_DELETION;
# # # # ]
264 : 16 : goto error;
265 : : }
266 : :
267 [ + + + + : 3328813 : if (!status->done && status->timeout_tsc && spdk_get_ticks() > status->timeout_tsc) {
+ + + + +
- + - - +
# # # # #
# ]
268 : 8 : goto error;
269 : : }
270 : :
271 [ + + + - : 3328805 : if (qpair->ctrlr->trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
+ - + - +
- + + ]
272 [ + - + - ]: 17182 : union spdk_nvme_csts_register csts = spdk_nvme_ctrlr_get_regs_csts(qpair->ctrlr);
273 [ + + ]: 17182 : if (csts.raw == SPDK_NVME_INVALID_REGISTER_VALUE) {
274 [ # # # # : 0 : status->cpl.status.sct = SPDK_NVME_SCT_GENERIC;
# # # # ]
275 [ # # # # : 0 : status->cpl.status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
# # # # ]
276 : 0 : goto error;
277 : : }
278 : 203 : }
279 : :
280 [ + + + + : 3328805 : if (!status->done) {
+ - + + ]
281 : 3311189 : return -EAGAIN;
282 [ + + + + : 17616 : } else if (spdk_nvme_cpl_is_error(&status->cpl)) {
+ - + - +
- - + - +
- + - + -
+ ]
283 : 263 : return -EIO;
284 : : } else {
285 : 17353 : return 0;
286 : : }
287 : 18 : error:
288 : : /* Either transport error occurred or we've timed out. Either way, if the response hasn't
289 : : * been received yet, mark the command as timed out, so the status gets freed when the
290 : : * command is completed or aborted.
291 : : */
292 [ + + + - : 24 : if (!status->done) {
# # # # ]
293 [ # # # # ]: 24 : status->timed_out = true;
294 : 6 : }
295 : :
296 : 24 : return -ECANCELED;
297 : 48610 : }
298 : :
299 : : /**
300 : : * Poll qpair for completions until a command completes.
301 : : *
302 : : * \param qpair queue to poll
303 : : * \param status completion status. The user must fill this structure with zeroes before calling
304 : : * this function
305 : : * \param robust_mutex optional robust mutex to lock while polling qpair
306 : : * \param timeout_in_usecs optional timeout
307 : : *
308 : : * \return 0 if command completed without error,
309 : : * -EIO if command completed with error,
310 : : * -ECANCELED if command is not completed due to transport/device error or time expired
311 : : *
312 : : * The command to wait upon must be submitted with nvme_completion_poll_cb as the callback
313 : : * and status as the callback argument.
314 : : */
315 : : int
316 : 5991 : nvme_wait_for_completion_robust_lock_timeout(
317 : : struct spdk_nvme_qpair *qpair,
318 : : struct nvme_completion_poll_status *status,
319 : : pthread_mutex_t *robust_mutex,
320 : : uint64_t timeout_in_usecs)
321 : : {
322 : : int rc;
323 : :
324 [ + + ]: 5991 : if (timeout_in_usecs) {
325 [ # # # # ]: 422 : status->timeout_tsc = spdk_get_ticks() + timeout_in_usecs *
326 [ # # # # ]: 217 : spdk_get_ticks_hz() / SPDK_SEC_TO_USEC;
327 : 6 : } else {
328 [ + - + - ]: 5780 : status->timeout_tsc = 0;
329 : : }
330 : :
331 [ + - + - : 5991 : status->cpl.status_raw = 0;
+ - + - ]
332 : 104 : do {
333 : 1662258 : rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, robust_mutex);
334 [ + + ]: 1662258 : } while (rc == -EAGAIN);
335 : :
336 : 5991 : return rc;
337 : : }
338 : :
339 : : /**
340 : : * Poll qpair for completions until a command completes.
341 : : *
342 : : * \param qpair queue to poll
343 : : * \param status completion status. The user must fill this structure with zeroes before calling
344 : : * this function
345 : : * \param robust_mutex optional robust mutex to lock while polling qpair
346 : : *
347 : : * \return 0 if command completed without error,
348 : : * -EIO if command completed with error,
349 : : * -ECANCELED if command is not completed due to transport/device error
350 : : *
351 : : * The command to wait upon must be submitted with nvme_completion_poll_cb as the callback
352 : : * and status as the callback argument.
353 : : */
354 : : int
355 : 2301 : nvme_wait_for_completion_robust_lock(
356 : : struct spdk_nvme_qpair *qpair,
357 : : struct nvme_completion_poll_status *status,
358 : : pthread_mutex_t *robust_mutex)
359 : : {
360 : 2301 : return nvme_wait_for_completion_robust_lock_timeout(qpair, status, robust_mutex, 0);
361 : : }
362 : :
363 : : int
364 : 3479 : nvme_wait_for_completion(struct spdk_nvme_qpair *qpair,
365 : : struct nvme_completion_poll_status *status)
366 : : {
367 : 3479 : return nvme_wait_for_completion_robust_lock_timeout(qpair, status, NULL, 0);
368 : : }
369 : :
370 : : /**
371 : : * Poll qpair for completions until a command completes.
372 : : *
373 : : * \param qpair queue to poll
374 : : * \param status completion status. The user must fill this structure with zeroes before calling
375 : : * this function
376 : : * \param timeout_in_usecs optional timeout
377 : : *
378 : : * \return 0 if command completed without error,
379 : : * -EIO if command completed with error,
380 : : * -ECANCELED if command is not completed due to transport/device error or time expired
381 : : *
382 : : * The command to wait upon must be submitted with nvme_completion_poll_cb as the callback
383 : : * and status as the callback argument.
384 : : */
385 : : int
386 : 186 : nvme_wait_for_completion_timeout(struct spdk_nvme_qpair *qpair,
387 : : struct nvme_completion_poll_status *status,
388 : : uint64_t timeout_in_usecs)
389 : : {
390 : 186 : return nvme_wait_for_completion_robust_lock_timeout(qpair, status, NULL, timeout_in_usecs);
391 : : }
392 : :
393 : : static void
394 : 93007 : nvme_user_copy_cmd_complete(void *arg, const struct spdk_nvme_cpl *cpl)
395 : : {
396 : 93007 : struct nvme_request *req = arg;
397 : : spdk_nvme_cmd_cb user_cb_fn;
398 : : void *user_cb_arg;
399 : : enum spdk_nvme_data_transfer xfer;
400 : :
401 [ + + + + : 93007 : if (req->user_buffer && req->payload_size) {
+ + + - +
- - + ]
402 : : /* Copy back to the user buffer */
403 [ + + + - : 84039 : assert(nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_CONTIG);
# # ]
404 [ + - + - ]: 84039 : xfer = spdk_nvme_opc_get_data_transfer(req->cmd.opc);
405 [ + + - + ]: 84039 : if (xfer == SPDK_NVME_DATA_CONTROLLER_TO_HOST ||
406 : 35 : xfer == SPDK_NVME_DATA_BIDIRECTIONAL) {
407 [ + + + - : 17190 : assert(req->pid == getpid());
+ - # # ]
408 [ + + + + : 17190 : memcpy(req->user_buffer, req->payload.contig_or_cb_arg, req->payload_size);
+ - + - +
- + - + -
+ - + - ]
409 : 3494 : }
410 : 3529 : }
411 : :
412 [ + - + - ]: 93007 : user_cb_fn = req->user_cb_fn;
413 [ + - + - ]: 93007 : user_cb_arg = req->user_cb_arg;
414 : 93007 : nvme_cleanup_user_req(req);
415 : :
416 : : /* Call the user's original callback now that the buffer has been copied */
417 [ - + + - ]: 93007 : user_cb_fn(user_cb_arg, cpl);
418 : :
419 : 93007 : }
420 : :
421 : : /**
422 : : * Allocate a request as well as a DMA-capable buffer to copy to/from the user's buffer.
423 : : *
424 : : * This is intended for use in non-fast-path functions (admin commands, reservations, etc.)
425 : : * where the overhead of a copy is not a problem.
426 : : */
427 : : struct nvme_request *
428 : 93051 : nvme_allocate_request_user_copy(struct spdk_nvme_qpair *qpair,
429 : : void *buffer, uint32_t payload_size, spdk_nvme_cmd_cb cb_fn,
430 : : void *cb_arg, bool host_to_controller)
431 : : {
432 : : struct nvme_request *req;
433 : 93051 : void *dma_buffer = NULL;
434 : :
435 [ + + + + ]: 93051 : if (buffer && payload_size) {
436 : 84083 : dma_buffer = spdk_zmalloc(payload_size, 4096, NULL,
437 : : SPDK_ENV_NUMA_ID_ANY, SPDK_MALLOC_DMA);
438 [ + + ]: 84083 : if (!dma_buffer) {
439 : 4 : return NULL;
440 : : }
441 : :
442 [ + + + - ]: 84079 : if (host_to_controller) {
443 [ - + - + ]: 66876 : memcpy(dma_buffer, buffer, payload_size);
444 : 42 : }
445 : 3539 : }
446 : :
447 : 93047 : req = nvme_allocate_request_contig(qpair, dma_buffer, payload_size, nvme_user_copy_cmd_complete,
448 : : NULL);
449 [ + + ]: 93047 : if (!req) {
450 : 4 : spdk_free(dma_buffer);
451 : 4 : return NULL;
452 : : }
453 : :
454 [ + - + - ]: 93043 : req->user_cb_fn = cb_fn;
455 [ + - + - ]: 93043 : req->user_cb_arg = cb_arg;
456 [ + - + - ]: 93043 : req->user_buffer = buffer;
457 [ + - + - ]: 93043 : req->cb_arg = req;
458 : :
459 : 93043 : return req;
460 : 6043 : }
461 : :
462 : : /**
463 : : * Check if a request has exceeded the controller timeout.
464 : : *
465 : : * \param req request to check for timeout.
466 : : * \param cid command ID for command submitted by req (will be passed to timeout_cb_fn)
467 : : * \param active_proc per-process data for the controller associated with req
468 : : * \param now_tick current time from spdk_get_ticks()
469 : : * \return 0 if requests submitted more recently than req should still be checked for timeouts, or
470 : : * 1 if requests newer than req need not be checked.
471 : : *
472 : : * The request's timeout callback will be called if needed; the caller is only responsible for
473 : : * calling this function on each outstanding request.
474 : : */
475 : : int
476 : 122673 : nvme_request_check_timeout(struct nvme_request *req, uint16_t cid,
477 : : struct spdk_nvme_ctrlr_process *active_proc,
478 : : uint64_t now_tick)
479 : : {
480 [ # # # # ]: 122673 : struct spdk_nvme_qpair *qpair = req->qpair;
481 [ # # # # ]: 122673 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
482 [ + + ]: 122673 : uint64_t timeout_ticks = nvme_qpair_is_admin_queue(qpair) ?
483 [ + + # # : 122673 : active_proc->timeout_admin_ticks : active_proc->timeout_io_ticks;
# # # # ]
484 : :
485 [ + + # # : 122673 : assert(active_proc->timeout_cb_fn != NULL);
# # # # ]
486 : :
487 [ + + + + : 122673 : if (req->timed_out || req->submit_tick == 0) {
# # # # #
# ]
488 : 3676 : return 0;
489 : : }
490 : :
491 [ + + # # : 118997 : if (req->pid != g_spdk_nvme_pid) {
# # ]
492 : 4 : return 0;
493 : : }
494 : :
495 [ + + - + ]: 118993 : if (nvme_qpair_is_admin_queue(qpair) &&
496 [ + + # # ]: 865 : req->cmd.opc == SPDK_NVME_OPC_ASYNC_EVENT_REQUEST) {
497 : 4 : return 0;
498 : : }
499 : :
500 [ + + # # : 118989 : if (req->submit_tick + timeout_ticks > now_tick) {
# # ]
501 : 118985 : return 1;
502 : : }
503 : :
504 [ # # ]: 4 : req->timed_out = true;
505 : :
506 : : /*
507 : : * We don't want to expose the admin queue to the user,
508 : : * so when we're timing out admin commands set the
509 : : * qpair to NULL.
510 : : */
511 [ + - # # : 7 : active_proc->timeout_cb_fn(active_proc->timeout_cb_arg, ctrlr,
# # # # #
# # # ]
512 [ - + ]: 4 : nvme_qpair_is_admin_queue(qpair) ? NULL : qpair,
513 : 1 : cid);
514 : 4 : return 0;
515 : 6 : }
516 : :
517 : : int
518 : 956 : nvme_robust_mutex_init_shared(pthread_mutex_t *mtx)
519 : : {
520 : 956 : int rc = 0;
521 : :
522 : : #ifdef __FreeBSD__
523 : 35 : pthread_mutex_init(mtx, NULL);
524 : : #else
525 : 267 : pthread_mutexattr_t attr;
526 : :
527 [ + + + + ]: 921 : if (pthread_mutexattr_init(&attr)) {
528 : 6 : return -1;
529 : : }
530 [ + + + - : 1830 : if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) ||
+ + ]
531 [ + + + + ]: 1796 : pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST) ||
532 [ + + ]: 915 : pthread_mutex_init(mtx, &attr)) {
533 : 3 : rc = -1;
534 : 0 : }
535 [ + + ]: 915 : pthread_mutexattr_destroy(&attr);
536 : : #endif
537 : :
538 : 950 : return rc;
539 : 34 : }
540 : :
541 : : int
542 : 132850 : nvme_driver_init(void)
543 : : {
544 : : static pthread_mutex_t g_init_mutex = PTHREAD_MUTEX_INITIALIZER;
545 : 132850 : int ret = 0;
546 : :
547 : : /* Use a special process-private mutex to ensure the global
548 : : * nvme driver object (g_spdk_nvme_driver) gets initialized by
549 : : * only one thread. Once that object is established and its
550 : : * mutex is initialized, we can unlock this mutex and use that
551 : : * one instead.
552 : : */
553 [ + + ]: 132850 : pthread_mutex_lock(&g_init_mutex);
554 : :
555 : : /* Each process needs its own pid. */
556 : 132850 : g_spdk_nvme_pid = getpid();
557 : :
558 : : /*
559 : : * Only one thread from one process will do this driver init work.
560 : : * The primary process will reserve the shared memory and do the
561 : : * initialization.
562 : : * The secondary process will lookup the existing reserved memory.
563 : : */
564 [ + + ]: 132850 : if (spdk_process_is_primary()) {
565 : : /* The unique named memzone already reserved. */
566 [ + + ]: 132588 : if (g_spdk_nvme_driver != NULL) {
567 [ + + ]: 131640 : pthread_mutex_unlock(&g_init_mutex);
568 : 131640 : return 0;
569 : : } else {
570 : 948 : g_spdk_nvme_driver = spdk_memzone_reserve(SPDK_NVME_DRIVER_NAME,
571 : : sizeof(struct nvme_driver), SPDK_ENV_NUMA_ID_ANY,
572 : : SPDK_MEMZONE_NO_IOVA_CONTIG);
573 : : }
574 : :
575 [ + + ]: 948 : if (g_spdk_nvme_driver == NULL) {
576 : 4 : SPDK_ERRLOG("primary process failed to reserve memory\n");
577 [ - + ]: 4 : pthread_mutex_unlock(&g_init_mutex);
578 : 4 : return -1;
579 : : }
580 : 66 : } else {
581 : 262 : g_spdk_nvme_driver = spdk_memzone_lookup(SPDK_NVME_DRIVER_NAME);
582 : :
583 : : /* The unique named memzone already reserved by the primary process. */
584 [ + + ]: 262 : if (g_spdk_nvme_driver != NULL) {
585 : 250 : int ms_waited = 0;
586 : :
587 : : /* Wait the nvme driver to get initialized. */
588 [ + + + + : 665 : while ((g_spdk_nvme_driver->initialized == false) &&
# # # # #
# ]
589 [ + + ]: 404 : (ms_waited < g_nvme_driver_timeout_ms)) {
590 [ # # ]: 400 : ms_waited++;
591 : 400 : nvme_delay(1000); /* delay 1ms */
592 : : }
593 [ + + + + : 250 : if (g_spdk_nvme_driver->initialized == false) {
# # # # ]
594 : 4 : SPDK_ERRLOG("timeout waiting for primary process to init\n");
595 [ - + ]: 4 : pthread_mutex_unlock(&g_init_mutex);
596 : 4 : return -1;
597 : : }
598 : 14 : } else {
599 : 12 : SPDK_ERRLOG("primary process is not started yet\n");
600 [ - + ]: 12 : pthread_mutex_unlock(&g_init_mutex);
601 : 12 : return -1;
602 : : }
603 : :
604 [ - + ]: 246 : pthread_mutex_unlock(&g_init_mutex);
605 : 246 : return 0;
606 : : }
607 : :
608 : : /*
609 : : * At this moment, only one thread from the primary process will do
610 : : * the g_spdk_nvme_driver initialization
611 : : */
612 [ + + # # ]: 944 : assert(spdk_process_is_primary());
613 : :
614 [ + - ]: 944 : ret = nvme_robust_mutex_init_shared(&g_spdk_nvme_driver->lock);
615 [ + + ]: 944 : if (ret != 0) {
616 : 3 : SPDK_ERRLOG("failed to initialize mutex\n");
617 : 3 : spdk_memzone_free(SPDK_NVME_DRIVER_NAME);
618 [ - + ]: 3 : pthread_mutex_unlock(&g_init_mutex);
619 : 3 : return ret;
620 : : }
621 : :
622 : : /* The lock in the shared g_spdk_nvme_driver object is now ready to
623 : : * be used - so we can unlock the g_init_mutex here.
624 : : */
625 [ + + ]: 941 : pthread_mutex_unlock(&g_init_mutex);
626 [ + - ]: 941 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
627 : :
628 [ + - + - ]: 941 : g_spdk_nvme_driver->initialized = false;
629 [ + - + - ]: 941 : g_spdk_nvme_driver->hotplug_fd = spdk_pci_event_listen();
630 [ + + + - : 941 : if (g_spdk_nvme_driver->hotplug_fd < 0) {
+ - ]
631 [ + - # # : 28 : SPDK_DEBUGLOG(nvme, "Failed to open uevent netlink socket\n");
# # ]
632 : 28 : }
633 : :
634 [ + - + - : 941 : TAILQ_INIT(&g_spdk_nvme_driver->shared_attached_ctrlrs);
+ - + - +
- + - + -
+ - ]
635 : :
636 [ + - ]: 941 : spdk_uuid_generate(&g_spdk_nvme_driver->default_extended_host_id);
637 : :
638 [ + - ]: 941 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
639 : :
640 : 941 : return ret;
641 : 2777 : }
642 : :
643 : : /* This function must only be called while holding g_spdk_nvme_driver->lock */
644 : : int
645 : 3150 : nvme_ctrlr_probe(const struct spdk_nvme_transport_id *trid,
646 : : struct spdk_nvme_probe_ctx *probe_ctx, void *devhandle)
647 : : {
648 : : struct spdk_nvme_ctrlr *ctrlr;
649 : 396 : struct spdk_nvme_ctrlr_opts opts;
650 : :
651 [ + + # # ]: 3150 : assert(trid != NULL);
652 : :
653 : 3150 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&opts, sizeof(opts));
654 : :
655 [ + + + + : 3150 : if (!probe_ctx->probe_cb || probe_ctx->probe_cb(probe_ctx->cb_ctx, trid, &opts)) {
+ + + - +
- - + + -
+ - + - +
- ]
656 : 3124 : ctrlr = nvme_get_ctrlr_by_trid_unsafe(trid, opts.hostnqn);
657 [ + + ]: 3124 : if (ctrlr) {
658 : : /* This ctrlr already exists. */
659 : :
660 [ + + + - : 4 : if (ctrlr->is_destructed) {
# # # # ]
661 : : /* This ctrlr is being destructed asynchronously. */
662 [ # # ]: 4 : SPDK_ERRLOG("NVMe controller for SSD: %s is being destructed\n",
663 : : trid->traddr);
664 [ # # # # : 4 : probe_ctx->attach_fail_cb(probe_ctx->cb_ctx, trid, -EBUSY);
# # # # #
# # # ]
665 : 4 : return -EBUSY;
666 : : }
667 : :
668 : : /* Increase the ref count before calling attach_cb() as the user may
669 : : * call nvme_detach() immediately. */
670 : 0 : nvme_ctrlr_proc_get_ref(ctrlr);
671 : :
672 [ # # # # : 0 : if (probe_ctx->attach_cb) {
# # ]
673 [ # # ]: 0 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
674 [ # # # # : 0 : probe_ctx->attach_cb(probe_ctx->cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts);
# # # # #
# # # # #
# # ]
675 [ # # ]: 0 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
676 : 0 : }
677 : 0 : return 0;
678 : : }
679 : :
680 : 3120 : ctrlr = nvme_transport_ctrlr_construct(trid, &opts, devhandle);
681 [ + + ]: 3120 : if (ctrlr == NULL) {
682 [ # # ]: 11 : SPDK_ERRLOG("Failed to construct NVMe controller for SSD: %s\n", trid->traddr);
683 [ # # # # : 11 : probe_ctx->attach_fail_cb(probe_ctx->cb_ctx, trid, -ENODEV);
# # # # #
# # # ]
684 : 11 : return -1;
685 : : }
686 [ + - + - : 3109 : ctrlr->remove_cb = probe_ctx->remove_cb;
+ - + - ]
687 [ + - + - : 3109 : ctrlr->cb_ctx = probe_ctx->cb_ctx;
+ - + - ]
688 : :
689 [ + - + - ]: 3109 : nvme_qpair_set_state(ctrlr->adminq, NVME_QPAIR_ENABLED);
690 [ + - + - : 3109 : TAILQ_INSERT_TAIL(&probe_ctx->init_ctrlrs, ctrlr, tailq);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
691 : 3109 : return 0;
692 : : }
693 : :
694 : 26 : return 1;
695 : 848 : }
696 : :
697 : : static void
698 : 133625974 : nvme_ctrlr_poll_internal(struct spdk_nvme_ctrlr *ctrlr,
699 : : struct spdk_nvme_probe_ctx *probe_ctx)
700 : : {
701 : 133625974 : int rc = 0;
702 : : struct nvme_ctrlr_detach_ctx *detach_ctx;
703 : :
704 : 133625974 : rc = nvme_ctrlr_process_init(ctrlr);
705 : :
706 [ + + ]: 133625974 : if (rc) {
707 : : /* Controller failed to initialize. */
708 [ - + # # : 59 : TAILQ_REMOVE(&probe_ctx->init_ctrlrs, ctrlr, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
709 [ # # # # ]: 59 : SPDK_ERRLOG("Failed to initialize SSD: %s\n", ctrlr->trid.traddr);
710 [ # # # # : 59 : probe_ctx->attach_fail_cb(probe_ctx->cb_ctx, &ctrlr->trid, rc);
# # # # #
# # # #
# ]
711 : 59 : nvme_ctrlr_lock(ctrlr);
712 : 59 : nvme_ctrlr_fail(ctrlr, false);
713 : 59 : nvme_ctrlr_unlock(ctrlr);
714 : :
715 : : /* allocate a context to detach this controller asynchronously */
716 : 59 : detach_ctx = calloc(1, sizeof(*detach_ctx));
717 [ + + ]: 59 : if (detach_ctx == NULL) {
718 : 0 : SPDK_WARNLOG("Failed to allocate asynchronous detach context. Performing synchronous destruct.\n");
719 : 0 : nvme_ctrlr_destruct(ctrlr);
720 : 0 : return;
721 : : }
722 [ # # # # ]: 59 : detach_ctx->ctrlr = ctrlr;
723 [ # # # # : 59 : TAILQ_INSERT_TAIL(&probe_ctx->failed_ctxs.head, detach_ctx, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
724 : 59 : nvme_ctrlr_destruct_async(ctrlr, detach_ctx);
725 : 59 : return;
726 : : }
727 : :
728 [ + + + - : 133625915 : if (ctrlr->state != NVME_CTRLR_STATE_READY) {
+ + ]
729 : 133622820 : return;
730 : : }
731 : :
732 [ + - + - : 3095 : STAILQ_INIT(&ctrlr->io_producers);
+ - + - +
- + - + -
+ - ]
733 : :
734 : : /*
735 : : * Controller has been initialized.
736 : : * Move it to the attached_ctrlrs list.
737 : : */
738 [ + + + - : 3095 : TAILQ_REMOVE(&probe_ctx->init_ctrlrs, ctrlr, tailq);
+ - - + #
# # # # #
# # # # #
# # # # #
# # + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
739 : :
740 [ + - ]: 3095 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
741 [ + + ]: 3095 : if (nvme_ctrlr_shared(ctrlr)) {
742 [ + - + - : 715 : TAILQ_INSERT_TAIL(&g_spdk_nvme_driver->shared_attached_ctrlrs, ctrlr, tailq);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
743 : 31 : } else {
744 [ + - + - : 2380 : TAILQ_INSERT_TAIL(&g_nvme_attached_ctrlrs, ctrlr, tailq);
+ - + - +
- + - + -
+ - + - +
- + - +
- ]
745 : : }
746 : :
747 : : /*
748 : : * Increase the ref count before calling attach_cb() as the user may
749 : : * call nvme_detach() immediately.
750 : : */
751 : 3095 : nvme_ctrlr_proc_get_ref(ctrlr);
752 [ + - ]: 3095 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
753 : :
754 [ + + + - : 3095 : if (probe_ctx->attach_cb) {
+ + ]
755 [ + - + - : 1839 : probe_ctx->attach_cb(probe_ctx->cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts);
- + + - +
- + - + -
+ - ]
756 : 26 : }
757 : 26994250 : }
758 : :
759 : : static int
760 : 85111 : nvme_init_controllers(struct spdk_nvme_probe_ctx *probe_ctx)
761 : : {
762 : 85111 : int rc = 0;
763 : :
764 : 26991726 : while (true) {
765 : 133421204 : rc = spdk_nvme_probe_poll_async(probe_ctx);
766 [ + + ]: 133421204 : if (rc != -EAGAIN) {
767 : 85111 : return rc;
768 : : }
769 : : }
770 : :
771 : : return rc;
772 : : }
773 : :
774 : : /* This function must not be called while holding g_spdk_nvme_driver->lock */
775 : : static struct spdk_nvme_ctrlr *
776 : 1320 : nvme_get_ctrlr_by_trid(const struct spdk_nvme_transport_id *trid, const char *hostnqn)
777 : : {
778 : : struct spdk_nvme_ctrlr *ctrlr;
779 : :
780 [ + - ]: 1320 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
781 : 1320 : ctrlr = nvme_get_ctrlr_by_trid_unsafe(trid, hostnqn);
782 [ + - ]: 1320 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
783 : :
784 : 1320 : return ctrlr;
785 : : }
786 : :
787 : : /* This function must be called while holding g_spdk_nvme_driver->lock */
788 : : struct spdk_nvme_ctrlr *
789 : 5474 : nvme_get_ctrlr_by_trid_unsafe(const struct spdk_nvme_transport_id *trid, const char *hostnqn)
790 : : {
791 : : struct spdk_nvme_ctrlr *ctrlr;
792 : :
793 : : /* Search per-process list */
794 [ + + # # : 5850 : TAILQ_FOREACH(ctrlr, &g_nvme_attached_ctrlrs, tailq) {
# # # # ]
795 [ + + - + ]: 1595 : if (spdk_nvme_transport_id_compare(&ctrlr->trid, trid) != 0) {
796 : 373 : continue;
797 : : }
798 [ + - + + : 1222 : if (hostnqn && strcmp(ctrlr->opts.hostnqn, hostnqn) != 0) {
+ + + + +
- + - ]
799 : 3 : continue;
800 : : }
801 : 1219 : return ctrlr;
802 : : }
803 : :
804 : : /* Search multi-process shared list */
805 [ + + + - : 4779 : TAILQ_FOREACH(ctrlr, &g_spdk_nvme_driver->shared_attached_ctrlrs, tailq) {
+ - - + #
# # # #
# ]
806 [ + + # # ]: 922 : if (spdk_nvme_transport_id_compare(&ctrlr->trid, trid) != 0) {
807 : 524 : continue;
808 : : }
809 [ + + - + : 398 : if (hostnqn && strcmp(ctrlr->opts.hostnqn, hostnqn) != 0) {
- + - + #
# # # ]
810 : 0 : continue;
811 : : }
812 : 398 : return ctrlr;
813 : : }
814 : :
815 : 3857 : return NULL;
816 : 1706 : }
817 : :
818 : : /* This function must only be called while holding g_spdk_nvme_driver->lock */
819 : : static int
820 : 90438 : nvme_probe_internal(struct spdk_nvme_probe_ctx *probe_ctx,
821 : : bool direct_connect)
822 : : {
823 : : int rc;
824 : : struct spdk_nvme_ctrlr *ctrlr, *ctrlr_tmp;
825 [ + - + - ]: 90438 : const struct spdk_nvme_ctrlr_opts *opts = probe_ctx->opts;
826 : :
827 [ + + + - : 90438 : if (strlen(probe_ctx->trid.trstring) == 0) {
+ - + + ]
828 : : /* If user didn't provide trstring, derive it from trtype */
829 [ + - + - : 94 : spdk_nvme_trid_populate_transport(&probe_ctx->trid, probe_ctx->trid.trtype);
+ - + - ]
830 : 17 : }
831 : :
832 [ + + + - : 90438 : if (!spdk_nvme_transport_available_by_name(probe_ctx->trid.trstring)) {
+ - ]
833 [ # # # # : 4 : SPDK_ERRLOG("NVMe trtype %u (%s) not available\n",
# # # # #
# ]
834 : : probe_ctx->trid.trtype, probe_ctx->trid.trstring);
835 : 4 : return -1;
836 : : }
837 : :
838 [ + - ]: 90434 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
839 : :
840 [ + - ]: 90434 : rc = nvme_transport_ctrlr_scan(probe_ctx, direct_connect);
841 [ + + ]: 90434 : if (rc != 0) {
842 : 22 : SPDK_ERRLOG("NVMe ctrlr scan failed\n");
843 [ + + + + : 26 : TAILQ_FOREACH_SAFE(ctrlr, &probe_ctx->init_ctrlrs, tailq, ctrlr_tmp) {
# # # # #
# # # # #
# # ]
844 [ - + # # : 4 : TAILQ_REMOVE(&probe_ctx->init_ctrlrs, ctrlr, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
845 [ # # # # : 4 : probe_ctx->attach_fail_cb(probe_ctx->cb_ctx, &ctrlr->trid, -EFAULT);
# # # # #
# # # #
# ]
846 : 4 : nvme_transport_ctrlr_destruct(ctrlr);
847 : 1 : }
848 [ # # ]: 22 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
849 : 22 : return -1;
850 : : }
851 : :
852 : : /*
853 : : * Probe controllers on the shared_attached_ctrlrs list
854 : : */
855 [ + + + + : 90412 : if (!spdk_process_is_primary() && (probe_ctx->trid.trtype == SPDK_NVME_TRANSPORT_PCIE)) {
# # # # #
# ]
856 [ + + # # : 466 : TAILQ_FOREACH(ctrlr, &g_spdk_nvme_driver->shared_attached_ctrlrs, tailq) {
# # # # #
# # # #
# ]
857 : : /* Do not attach other ctrlrs if user specify a valid trid */
858 [ + + + + : 357 : if ((strlen(probe_ctx->trid.traddr) != 0) &&
# # # # #
# ]
859 [ # # # # ]: 74 : (spdk_nvme_transport_id_compare(&probe_ctx->trid, &ctrlr->trid))) {
860 : 30 : continue;
861 : : }
862 : :
863 [ + + - + : 258 : if (opts && strcmp(opts->hostnqn, ctrlr->opts.hostnqn) != 0) {
- + - + #
# # # #
# ]
864 : 0 : continue;
865 : : }
866 : :
867 : : /* Do not attach if we failed to initialize it in this process */
868 [ + + ]: 258 : if (nvme_ctrlr_get_current_process(ctrlr) == NULL) {
869 : 0 : continue;
870 : : }
871 : :
872 : 258 : nvme_ctrlr_proc_get_ref(ctrlr);
873 : :
874 : : /*
875 : : * Unlock while calling attach_cb() so the user can call other functions
876 : : * that may take the driver lock, like nvme_detach().
877 : : */
878 [ + + # # : 258 : if (probe_ctx->attach_cb) {
# # ]
879 [ # # ]: 218 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
880 [ # # # # : 218 : probe_ctx->attach_cb(probe_ctx->cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts);
# # # # #
# # # # #
# # ]
881 [ # # ]: 218 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
882 : 1 : }
883 : 6 : }
884 : 7 : }
885 : :
886 [ + - ]: 90412 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
887 : :
888 : 90412 : return 0;
889 : 855 : }
890 : :
891 : : static void
892 : 58 : nvme_dummy_attach_fail_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
893 : : int rc)
894 : : {
895 [ # # # # : 58 : SPDK_ERRLOG("Failed to attach nvme ctrlr: trtype=%s adrfam=%s traddr=%s trsvcid=%s "
# # # # #
# # # # #
# # ]
896 : : "subnqn=%s, %s\n", spdk_nvme_transport_id_trtype_str(trid->trtype),
897 : : spdk_nvme_transport_id_adrfam_str(trid->adrfam), trid->traddr, trid->trsvcid,
898 : : trid->subnqn, spdk_strerror(-rc));
899 : 58 : }
900 : :
901 : : static void
902 : 126442 : nvme_probe_ctx_init(struct spdk_nvme_probe_ctx *probe_ctx,
903 : : const struct spdk_nvme_transport_id *trid,
904 : : const struct spdk_nvme_ctrlr_opts *opts,
905 : : void *cb_ctx,
906 : : spdk_nvme_probe_cb probe_cb,
907 : : spdk_nvme_attach_cb attach_cb,
908 : : spdk_nvme_attach_fail_cb attach_fail_cb,
909 : : spdk_nvme_remove_cb remove_cb)
910 : : {
911 [ + - ]: 126442 : probe_ctx->trid = *trid;
912 [ + - + - ]: 126442 : probe_ctx->opts = opts;
913 [ + - + - ]: 126442 : probe_ctx->cb_ctx = cb_ctx;
914 [ + - + - ]: 126442 : probe_ctx->probe_cb = probe_cb;
915 [ + - + - ]: 126442 : probe_ctx->attach_cb = attach_cb;
916 [ + + ]: 126442 : if (attach_fail_cb != NULL) {
917 [ # # # # ]: 24 : probe_ctx->attach_fail_cb = attach_fail_cb;
918 : 6 : } else {
919 [ + - + - ]: 126418 : probe_ctx->attach_fail_cb = nvme_dummy_attach_fail_cb;
920 : : }
921 [ + - + - ]: 126442 : probe_ctx->remove_cb = remove_cb;
922 [ + - + - : 126442 : TAILQ_INIT(&probe_ctx->init_ctrlrs);
+ - + - +
- + - + -
+ - ]
923 [ + - + - : 126442 : TAILQ_INIT(&probe_ctx->failed_ctxs.head);
+ - + - +
- + - + -
+ - + - +
- + - ]
924 : 126442 : }
925 : :
926 : : int
927 : 83789 : spdk_nvme_probe(const struct spdk_nvme_transport_id *trid, void *cb_ctx,
928 : : spdk_nvme_probe_cb probe_cb, spdk_nvme_attach_cb attach_cb,
929 : : spdk_nvme_remove_cb remove_cb)
930 : : {
931 : 83789 : return spdk_nvme_probe_ext(trid, cb_ctx, probe_cb, attach_cb, NULL, remove_cb);
932 : : }
933 : :
934 : : int
935 : 83805 : spdk_nvme_probe_ext(const struct spdk_nvme_transport_id *trid, void *cb_ctx,
936 : : spdk_nvme_probe_cb probe_cb, spdk_nvme_attach_cb attach_cb,
937 : : spdk_nvme_attach_fail_cb attach_fail_cb, spdk_nvme_remove_cb remove_cb)
938 : : {
939 : 42302 : struct spdk_nvme_transport_id trid_pcie;
940 : : struct spdk_nvme_probe_ctx *probe_ctx;
941 : :
942 [ + + ]: 83805 : if (trid == NULL) {
943 [ + + ]: 83556 : memset(&trid_pcie, 0, sizeof(trid_pcie));
944 : 83556 : spdk_nvme_trid_populate_transport(&trid_pcie, SPDK_NVME_TRANSPORT_PCIE);
945 : 83556 : trid = &trid_pcie;
946 : 10 : }
947 : :
948 : 83824 : probe_ctx = spdk_nvme_probe_async_ext(trid, cb_ctx, probe_cb,
949 : 19 : attach_cb, attach_fail_cb, remove_cb);
950 [ + + ]: 83805 : if (!probe_ctx) {
951 : 10 : SPDK_ERRLOG("Create probe context failed\n");
952 : 10 : return -1;
953 : : }
954 : :
955 : : /*
956 : : * Keep going even if one or more nvme_attach() calls failed,
957 : : * but maintain the value of rc to signal errors when we return.
958 : : */
959 : 83795 : return nvme_init_controllers(probe_ctx);
960 : 19 : }
961 : :
962 : : static bool
963 : 1657 : nvme_connect_probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
964 : : struct spdk_nvme_ctrlr_opts *opts)
965 : : {
966 : 1657 : struct spdk_nvme_ctrlr_opts *requested_opts = cb_ctx;
967 : :
968 [ + + # # ]: 1657 : assert(requested_opts);
969 [ + + + + ]: 1657 : memcpy(opts, requested_opts, sizeof(*opts));
970 : :
971 : 1657 : return true;
972 : : }
973 : :
974 : : static void
975 : 83 : nvme_ctrlr_opts_init(struct spdk_nvme_ctrlr_opts *opts,
976 : : const struct spdk_nvme_ctrlr_opts *opts_user,
977 : : size_t opts_size_user)
978 : : {
979 [ + + # # ]: 83 : assert(opts);
980 [ - + # # ]: 83 : assert(opts_user);
981 : :
982 : 83 : spdk_nvme_ctrlr_get_default_ctrlr_opts(opts, opts_size_user);
983 : :
984 : : #define FIELD_OK(field) \
985 : : offsetof(struct spdk_nvme_ctrlr_opts, field) + sizeof(opts->field) <= (opts->opts_size)
986 : :
987 : : #define SET_FIELD(field) \
988 : : if (FIELD_OK(field)) { \
989 : : opts->field = opts_user->field; \
990 : : }
991 : :
992 : : #define SET_FIELD_ARRAY(field) \
993 : : if (FIELD_OK(field)) { \
994 : : memcpy(opts->field, opts_user->field, sizeof(opts_user->field)); \
995 : : }
996 : :
997 [ + + # # : 83 : SET_FIELD(num_io_queues);
# # # # #
# # # #
# ]
998 [ + + - + : 83 : SET_FIELD(use_cmb_sqs);
# # # # #
# # # # #
# # ]
999 [ + + - + : 83 : SET_FIELD(no_shn_notification);
# # # # #
# # # # #
# # ]
1000 [ + + - + : 83 : SET_FIELD(enable_interrupts);
# # # # #
# # # # #
# # ]
1001 [ + + # # : 83 : SET_FIELD(arb_mechanism);
# # # # #
# # # #
# ]
1002 [ + + # # : 83 : SET_FIELD(arbitration_burst);
# # # # #
# # # #
# ]
1003 [ + + # # : 83 : SET_FIELD(low_priority_weight);
# # # # #
# # # #
# ]
1004 [ + + # # : 83 : SET_FIELD(medium_priority_weight);
# # # # #
# # # #
# ]
1005 [ + + # # : 83 : SET_FIELD(high_priority_weight);
# # # # #
# # # #
# ]
1006 [ + + # # : 83 : SET_FIELD(keep_alive_timeout_ms);
# # # # #
# # # #
# ]
1007 [ + + # # : 83 : SET_FIELD(transport_retry_count);
# # # # #
# # # #
# ]
1008 [ + + # # : 83 : SET_FIELD(io_queue_size);
# # # # #
# # # #
# ]
1009 [ + + - + : 83 : SET_FIELD_ARRAY(hostnqn);
- + # # #
# # # #
# ]
1010 [ + + # # : 83 : SET_FIELD(io_queue_requests);
# # # # #
# # # #
# ]
1011 [ + + - + : 83 : SET_FIELD_ARRAY(src_addr);
- + # # #
# # # #
# ]
1012 [ + + - + : 83 : SET_FIELD_ARRAY(src_svcid);
- + # # #
# # # #
# ]
1013 [ + + # # : 83 : SET_FIELD_ARRAY(host_id);
# # # # #
# # # #
# ]
1014 [ + + # # : 83 : SET_FIELD_ARRAY(extended_host_id);
# # # # #
# # # #
# ]
1015 [ + + # # : 83 : SET_FIELD(command_set);
# # # # #
# # # #
# ]
1016 [ + + # # : 83 : SET_FIELD(admin_timeout_ms);
# # # # #
# # # #
# ]
1017 [ + + - + : 83 : SET_FIELD(header_digest);
# # # # #
# # # # #
# # ]
1018 [ + + - + : 83 : SET_FIELD(data_digest);
# # # # #
# # # # #
# # ]
1019 [ + + - + : 83 : SET_FIELD(disable_error_logging);
# # # # #
# # # # #
# # ]
1020 [ + + # # : 83 : SET_FIELD(transport_ack_timeout);
# # # # #
# # # #
# ]
1021 [ + + # # : 83 : SET_FIELD(admin_queue_size);
# # # # #
# # # #
# ]
1022 [ + + # # : 83 : SET_FIELD(fabrics_connect_timeout_us);
# # # # #
# # # #
# ]
1023 [ + + - + : 83 : SET_FIELD(disable_read_ana_log_page);
# # # # #
# # # # #
# # ]
1024 [ + + # # : 83 : SET_FIELD(disable_read_changed_ns_list_log_page);
# # # # #
# # # #
# ]
1025 [ + + # # : 83 : SET_FIELD(tls_psk);
# # # # #
# # # #
# ]
1026 [ + + # # : 83 : SET_FIELD(dhchap_key);
# # # # #
# # # #
# ]
1027 [ + + # # : 83 : SET_FIELD(dhchap_ctrlr_key);
# # # # #
# # # #
# ]
1028 [ + + # # : 83 : SET_FIELD(dhchap_digests);
# # # # #
# # # #
# ]
1029 [ + + # # : 83 : SET_FIELD(dhchap_dhgroups);
# # # # #
# # # #
# ]
1030 : :
1031 : : #undef FIELD_OK
1032 : : #undef SET_FIELD
1033 : : #undef SET_FIELD_ARRAY
1034 : 83 : }
1035 : :
1036 : : struct spdk_nvme_ctrlr *
1037 : 1312 : spdk_nvme_connect(const struct spdk_nvme_transport_id *trid,
1038 : : const struct spdk_nvme_ctrlr_opts *opts, size_t opts_size)
1039 : : {
1040 : : int rc;
1041 : 1312 : struct spdk_nvme_ctrlr *ctrlr = NULL;
1042 : : struct spdk_nvme_probe_ctx *probe_ctx;
1043 : 1312 : struct spdk_nvme_ctrlr_opts *opts_local_p = NULL;
1044 : 60 : struct spdk_nvme_ctrlr_opts opts_local;
1045 : 60 : char hostnqn[SPDK_NVMF_NQN_MAX_LEN + 1];
1046 : :
1047 [ + + ]: 1312 : if (trid == NULL) {
1048 : 4 : SPDK_ERRLOG("No transport ID specified\n");
1049 : 4 : return NULL;
1050 : : }
1051 : :
1052 : 1308 : rc = nvme_driver_init();
1053 [ + + ]: 1308 : if (rc != 0) {
1054 : 4 : return NULL;
1055 : : }
1056 : :
1057 : 1304 : nvme_get_default_hostnqn(hostnqn, sizeof(hostnqn));
1058 [ + + ]: 1304 : if (opts) {
1059 : 83 : opts_local_p = &opts_local;
1060 : 83 : nvme_ctrlr_opts_init(opts_local_p, opts, opts_size);
1061 [ # # # # ]: 83 : memcpy(hostnqn, opts_local.hostnqn, sizeof(hostnqn));
1062 : 7 : }
1063 : :
1064 : 1304 : probe_ctx = spdk_nvme_connect_async(trid, opts_local_p, NULL);
1065 [ + + ]: 1304 : if (!probe_ctx) {
1066 : 0 : SPDK_ERRLOG("Create probe context failed\n");
1067 : 0 : return NULL;
1068 : : }
1069 : :
1070 : 1304 : rc = nvme_init_controllers(probe_ctx);
1071 [ + + ]: 1304 : if (rc != 0) {
1072 : 0 : return NULL;
1073 : : }
1074 : :
1075 : 1304 : ctrlr = nvme_get_ctrlr_by_trid(trid, hostnqn);
1076 : :
1077 : 1304 : return ctrlr;
1078 : 827 : }
1079 : :
1080 : : void
1081 : 137469 : spdk_nvme_trid_populate_transport(struct spdk_nvme_transport_id *trid,
1082 : : enum spdk_nvme_transport_type trtype)
1083 : : {
1084 : : const char *trstring;
1085 : :
1086 [ + - + - ]: 137469 : trid->trtype = trtype;
1087 [ - + + + : 137469 : switch (trtype) {
+ - - ]
1088 : 0 : case SPDK_NVME_TRANSPORT_FC:
1089 : 0 : trstring = SPDK_NVME_TRANSPORT_NAME_FC;
1090 : 0 : break;
1091 : 124205 : case SPDK_NVME_TRANSPORT_PCIE:
1092 : 124492 : trstring = SPDK_NVME_TRANSPORT_NAME_PCIE;
1093 : 124492 : break;
1094 : 2051 : case SPDK_NVME_TRANSPORT_RDMA:
1095 : 2051 : trstring = SPDK_NVME_TRANSPORT_NAME_RDMA;
1096 : 2051 : break;
1097 : 8479 : case SPDK_NVME_TRANSPORT_TCP:
1098 : 10919 : trstring = SPDK_NVME_TRANSPORT_NAME_TCP;
1099 : 10919 : break;
1100 : 0 : case SPDK_NVME_TRANSPORT_VFIOUSER:
1101 : 7 : trstring = SPDK_NVME_TRANSPORT_NAME_VFIOUSER;
1102 : 7 : break;
1103 : 0 : case SPDK_NVME_TRANSPORT_CUSTOM:
1104 : 0 : trstring = SPDK_NVME_TRANSPORT_NAME_CUSTOM;
1105 : 0 : break;
1106 : 0 : default:
1107 : 0 : SPDK_ERRLOG("no available transports\n");
1108 [ # # ]: 0 : assert(0);
1109 : : return;
1110 : : }
1111 [ + + ]: 137469 : snprintf(trid->trstring, SPDK_NVMF_TRSTRING_MAX_LEN, "%s", trstring);
1112 : 2734 : }
1113 : :
1114 : : int
1115 : 2893 : spdk_nvme_transport_id_populate_trstring(struct spdk_nvme_transport_id *trid, const char *trstring)
1116 : : {
1117 : 2893 : int i = 0;
1118 : :
1119 [ + - - + ]: 2893 : if (trid == NULL || trstring == NULL) {
1120 : 0 : return -EINVAL;
1121 : : }
1122 : :
1123 : : /* Note: gcc-11 has some false positive -Wstringop-overread warnings with LTO builds if we
1124 : : * use strnlen here. So do the trstring copy manually instead. See GitHub issue #2391.
1125 : : */
1126 : :
1127 : : /* cast official trstring to uppercase version of input. */
1128 [ + + + + : 13042 : while (i < SPDK_NVMF_TRSTRING_MAX_LEN && trstring[i] != 0) {
+ - + + ]
1129 [ + - + - : 10149 : trid->trstring[i] = toupper(trstring[i]);
+ - + - +
- + - ]
1130 [ + - ]: 10149 : i++;
1131 : : }
1132 : :
1133 [ + + + - : 2893 : if (trstring[i] != 0) {
+ - ]
1134 : 0 : return -EINVAL;
1135 : : } else {
1136 [ + - + - : 2893 : trid->trstring[i] = 0;
+ - + - ]
1137 : 2893 : return 0;
1138 : : }
1139 : 93 : }
1140 : :
1141 : : int
1142 : 2789 : spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str)
1143 : : {
1144 [ + + + + ]: 2789 : if (trtype == NULL || str == NULL) {
1145 : 8 : return -EINVAL;
1146 : : }
1147 : :
1148 [ + + + + : 2781 : if (strcasecmp(str, "PCIe") == 0) {
+ + ]
1149 [ + - ]: 660 : *trtype = SPDK_NVME_TRANSPORT_PCIE;
1150 [ + + + + : 2150 : } else if (strcasecmp(str, "RDMA") == 0) {
+ - ]
1151 [ # # ]: 427 : *trtype = SPDK_NVME_TRANSPORT_RDMA;
1152 [ + + + + : 1697 : } else if (strcasecmp(str, "FC") == 0) {
+ - ]
1153 [ # # ]: 8 : *trtype = SPDK_NVME_TRANSPORT_FC;
1154 [ + + + + : 1688 : } else if (strcasecmp(str, "TCP") == 0) {
+ + ]
1155 [ + - ]: 1612 : *trtype = SPDK_NVME_TRANSPORT_TCP;
1156 [ + + + + : 127 : } else if (strcasecmp(str, "VFIOUSER") == 0) {
- + ]
1157 [ - + ]: 70 : *trtype = SPDK_NVME_TRANSPORT_VFIOUSER;
1158 : 14 : } else {
1159 [ # # ]: 4 : *trtype = SPDK_NVME_TRANSPORT_CUSTOM;
1160 : : }
1161 : 2781 : return 0;
1162 : 104 : }
1163 : :
1164 : : const char *
1165 : 2694 : spdk_nvme_transport_id_trtype_str(enum spdk_nvme_transport_type trtype)
1166 : : {
1167 [ + + + + : 2694 : switch (trtype) {
- - + ]
1168 : 1031 : case SPDK_NVME_TRANSPORT_PCIE:
1169 : 1040 : return "PCIe";
1170 : 488 : case SPDK_NVME_TRANSPORT_RDMA:
1171 : 489 : return "RDMA";
1172 : 3 : case SPDK_NVME_TRANSPORT_FC:
1173 : 4 : return "FC";
1174 : 1156 : case SPDK_NVME_TRANSPORT_TCP:
1175 : 1157 : return "TCP";
1176 : 0 : case SPDK_NVME_TRANSPORT_VFIOUSER:
1177 : 0 : return "VFIOUSER";
1178 : 0 : case SPDK_NVME_TRANSPORT_CUSTOM:
1179 : 0 : return "CUSTOM";
1180 : 3 : default:
1181 : 4 : return NULL;
1182 : : }
1183 : 13 : }
1184 : :
1185 : : int
1186 : 1362 : spdk_nvme_transport_id_parse_adrfam(enum spdk_nvmf_adrfam *adrfam, const char *str)
1187 : : {
1188 [ + + + + ]: 1362 : if (adrfam == NULL || str == NULL) {
1189 : 8 : return -EINVAL;
1190 : : }
1191 : :
1192 [ + + + + : 1354 : if (strcasecmp(str, "IPv4") == 0) {
- + ]
1193 [ + - ]: 1326 : *adrfam = SPDK_NVMF_ADRFAM_IPV4;
1194 [ + + + + : 82 : } else if (strcasecmp(str, "IPv6") == 0) {
# # ]
1195 [ # # ]: 8 : *adrfam = SPDK_NVMF_ADRFAM_IPV6;
1196 [ + + + + : 22 : } else if (strcasecmp(str, "IB") == 0) {
# # ]
1197 [ # # ]: 8 : *adrfam = SPDK_NVMF_ADRFAM_IB;
1198 [ + + + + : 14 : } else if (strcasecmp(str, "FC") == 0) {
# # ]
1199 [ # # ]: 8 : *adrfam = SPDK_NVMF_ADRFAM_FC;
1200 : 2 : } else {
1201 : 4 : return -ENOENT;
1202 : : }
1203 : 1350 : return 0;
1204 : 63 : }
1205 : :
1206 : : const char *
1207 : 4544 : spdk_nvme_transport_id_adrfam_str(enum spdk_nvmf_adrfam adrfam)
1208 : : {
1209 [ + + + + : 4544 : switch (adrfam) {
+ ]
1210 : 3513 : case SPDK_NVMF_ADRFAM_IPV4:
1211 : 3514 : return "IPv4";
1212 : 3 : case SPDK_NVMF_ADRFAM_IPV6:
1213 : 4 : return "IPv6";
1214 : 3 : case SPDK_NVMF_ADRFAM_IB:
1215 : 4 : return "IB";
1216 : 3 : case SPDK_NVMF_ADRFAM_FC:
1217 : 4 : return "FC";
1218 : 1009 : default:
1219 : 1018 : return NULL;
1220 : : }
1221 : 13 : }
1222 : :
1223 : : static size_t
1224 : 1190 : parse_next_key(const char **str, char *key, char *val, size_t key_buf_size, size_t val_buf_size)
1225 : : {
1226 : :
1227 : : const char *sep, *sep1;
1228 : 1190 : const char *whitespace = " \t\n";
1229 : : size_t key_len, val_len;
1230 : :
1231 [ + + + + : 1190 : *str += strspn(*str, whitespace);
+ - + - +
- ]
1232 : :
1233 [ + + + - ]: 1190 : sep = strchr(*str, ':');
1234 [ + + ]: 1190 : if (!sep) {
1235 [ - + # # ]: 58 : sep = strchr(*str, '=');
1236 [ + + ]: 58 : if (!sep) {
1237 : 4 : SPDK_ERRLOG("Key without ':' or '=' separator\n");
1238 : 4 : return 0;
1239 : : }
1240 : 2 : } else {
1241 [ + + + - ]: 1132 : sep1 = strchr(*str, '=');
1242 [ + + + + ]: 1132 : if ((sep1 != NULL) && (sep1 < sep)) {
1243 : 16 : sep = sep1;
1244 : 4 : }
1245 : : }
1246 : :
1247 [ + - ]: 1186 : key_len = sep - *str;
1248 [ + + ]: 1186 : if (key_len >= key_buf_size) {
1249 : 4 : SPDK_ERRLOG("Key length %zu greater than maximum allowed %zu\n",
1250 : : key_len, key_buf_size - 1);
1251 : 4 : return 0;
1252 : : }
1253 : :
1254 [ + + + + : 1182 : memcpy(key, *str, key_len);
+ - ]
1255 [ + - + - ]: 1182 : key[key_len] = '\0';
1256 : :
1257 [ + - + - ]: 1182 : *str += key_len + 1; /* Skip key: */
1258 [ + + + + : 1182 : val_len = strcspn(*str, whitespace);
+ - ]
1259 [ + + ]: 1182 : if (val_len == 0) {
1260 : 4 : SPDK_ERRLOG("Key without value\n");
1261 : 4 : return 0;
1262 : : }
1263 : :
1264 [ - + ]: 1178 : if (val_len >= val_buf_size) {
1265 : 0 : SPDK_ERRLOG("Value length %zu greater than maximum allowed %zu\n",
1266 : : val_len, val_buf_size - 1);
1267 : 0 : return 0;
1268 : : }
1269 : :
1270 [ - + - + : 1178 : memcpy(val, *str, val_len);
- + ]
1271 [ - + - + ]: 1178 : val[val_len] = '\0';
1272 : :
1273 [ - + - + ]: 1178 : *str += val_len;
1274 : :
1275 : 1178 : return val_len;
1276 : 175 : }
1277 : :
1278 : : int
1279 : 388 : spdk_nvme_transport_id_parse(struct spdk_nvme_transport_id *trid, const char *str)
1280 : : {
1281 : : size_t val_len;
1282 : 112 : char key[32];
1283 : 112 : char val[1024];
1284 : :
1285 [ + + + + ]: 388 : if (trid == NULL || str == NULL) {
1286 : 12 : return -EINVAL;
1287 : : }
1288 : :
1289 [ + + + + ]: 1530 : while (*str != '\0') {
1290 : :
1291 : 1166 : val_len = parse_next_key(&str, key, val, sizeof(key), sizeof(val));
1292 : :
1293 [ + + ]: 1166 : if (val_len == 0) {
1294 : 12 : SPDK_ERRLOG("Failed to parse transport ID\n");
1295 : 12 : return -EINVAL;
1296 : : }
1297 : :
1298 [ + + + - : 1154 : if (strcasecmp(key, "trtype") == 0) {
+ + ]
1299 [ + + ]: 364 : if (spdk_nvme_transport_id_populate_trstring(trid, val) != 0) {
1300 : 0 : SPDK_ERRLOG("invalid transport '%s'\n", val);
1301 : 0 : return -EINVAL;
1302 : : }
1303 [ + + + - ]: 364 : if (spdk_nvme_transport_id_parse_trtype(&trid->trtype, val) != 0) {
1304 : 0 : SPDK_ERRLOG("Unknown trtype '%s'\n", val);
1305 : 0 : return -EINVAL;
1306 : : }
1307 [ + + + - : 833 : } else if (strcasecmp(key, "adrfam") == 0) {
+ + ]
1308 [ + + + - ]: 169 : if (spdk_nvme_transport_id_parse_adrfam(&trid->adrfam, val) != 0) {
1309 : 0 : SPDK_ERRLOG("Unknown adrfam '%s'\n", val);
1310 : 0 : return -EINVAL;
1311 : : }
1312 [ + + + - : 648 : } else if (strcasecmp(key, "traddr") == 0) {
+ + ]
1313 [ + + ]: 314 : if (val_len > SPDK_NVMF_TRADDR_MAX_LEN) {
1314 : 0 : SPDK_ERRLOG("traddr length %zu greater than maximum allowed %u\n",
1315 : : val_len, SPDK_NVMF_TRADDR_MAX_LEN);
1316 : 0 : return -EINVAL;
1317 : : }
1318 [ + + + - : 314 : memcpy(trid->traddr, val, val_len + 1);
+ - ]
1319 [ + + + - : 348 : } else if (strcasecmp(key, "trsvcid") == 0) {
+ + ]
1320 [ + + ]: 169 : if (val_len > SPDK_NVMF_TRSVCID_MAX_LEN) {
1321 : 0 : SPDK_ERRLOG("trsvcid length %zu greater than maximum allowed %u\n",
1322 : : val_len, SPDK_NVMF_TRSVCID_MAX_LEN);
1323 : 0 : return -EINVAL;
1324 : : }
1325 [ + + + - : 169 : memcpy(trid->trsvcid, val, val_len + 1);
+ - ]
1326 [ + + + - : 165 : } else if (strcasecmp(key, "priority") == 0) {
+ - ]
1327 [ + + ]: 4 : if (val_len > SPDK_NVMF_PRIORITY_MAX_LEN) {
1328 : 0 : SPDK_ERRLOG("priority length %zu greater than maximum allowed %u\n",
1329 : : val_len, SPDK_NVMF_PRIORITY_MAX_LEN);
1330 : 0 : return -EINVAL;
1331 : : }
1332 [ # # # # ]: 4 : trid->priority = spdk_strtol(val, 10);
1333 [ + + + - : 135 : } else if (strcasecmp(key, "subnqn") == 0) {
- + ]
1334 [ + + ]: 125 : if (val_len > SPDK_NVMF_NQN_MAX_LEN) {
1335 : 0 : SPDK_ERRLOG("subnqn length %zu greater than maximum allowed %u\n",
1336 : : val_len, SPDK_NVMF_NQN_MAX_LEN);
1337 : 0 : return -EINVAL;
1338 : : }
1339 [ + + + - : 125 : memcpy(trid->subnqn, val, val_len + 1);
+ - ]
1340 [ - + # # : 36 : } else if (strcasecmp(key, "hostaddr") == 0) {
# # ]
1341 : 0 : continue;
1342 [ - + # # : 9 : } else if (strcasecmp(key, "hostsvcid") == 0) {
# # ]
1343 : 0 : continue;
1344 [ + + # # : 9 : } else if (strcasecmp(key, "hostnqn") == 0) {
# # ]
1345 : 3 : continue;
1346 [ + + # # : 6 : } else if (strcasecmp(key, "ns") == 0) {
# # ]
1347 : : /*
1348 : : * Special case. The namespace id parameter may
1349 : : * optionally be passed in the transport id string
1350 : : * for an SPDK application (e.g. spdk_nvme_perf)
1351 : : * and additionally parsed therein to limit
1352 : : * targeting a specific namespace. For this
1353 : : * scenario, just silently ignore this key
1354 : : * rather than letting it default to logging
1355 : : * it as an invalid key.
1356 : : */
1357 : 5 : continue;
1358 [ + - # # : 1 : } else if (strcasecmp(key, "alt_traddr") == 0) {
# # ]
1359 : : /*
1360 : : * Used by applications for enabling transport ID failover.
1361 : : * Please see the case above for more information on custom parameters.
1362 : : */
1363 : 1 : continue;
1364 : : } else {
1365 : 0 : SPDK_ERRLOG("Unknown transport ID key '%s'\n", key);
1366 : : }
1367 : : }
1368 : :
1369 : 364 : return 0;
1370 : 49 : }
1371 : :
1372 : : int
1373 : 12 : spdk_nvme_host_id_parse(struct spdk_nvme_host_id *hostid, const char *str)
1374 : 9 : {
1375 : :
1376 : 12 : size_t key_size = 32;
1377 : 12 : size_t val_size = 1024;
1378 : : size_t val_len;
1379 [ - + ]: 12 : char key[key_size];
1380 [ - + ]: 12 : char val[val_size];
1381 : :
1382 [ + - - + ]: 12 : if (hostid == NULL || str == NULL) {
1383 : 0 : return -EINVAL;
1384 : : }
1385 : :
1386 [ + + # # ]: 24 : while (*str != '\0') {
1387 : :
1388 : 12 : val_len = parse_next_key(&str, key, val, key_size, val_size);
1389 : :
1390 [ + + ]: 12 : if (val_len == 0) {
1391 : 0 : SPDK_ERRLOG("Failed to parse host ID\n");
1392 : 0 : return val_len;
1393 : : }
1394 : :
1395 : : /* Ignore the rest of the options from the transport ID. */
1396 [ + + + + : 12 : if (strcasecmp(key, "trtype") == 0) {
# # ]
1397 : 4 : continue;
1398 [ + + - + : 8 : } else if (strcasecmp(key, "adrfam") == 0) {
# # ]
1399 : 0 : continue;
1400 [ + + - + : 8 : } else if (strcasecmp(key, "traddr") == 0) {
# # ]
1401 : 0 : continue;
1402 [ + + - + : 8 : } else if (strcasecmp(key, "trsvcid") == 0) {
# # ]
1403 : 0 : continue;
1404 [ + + - + : 8 : } else if (strcasecmp(key, "subnqn") == 0) {
# # ]
1405 : 0 : continue;
1406 [ + + - + : 8 : } else if (strcasecmp(key, "priority") == 0) {
# # ]
1407 : 0 : continue;
1408 [ + + - + : 8 : } else if (strcasecmp(key, "ns") == 0) {
# # ]
1409 : 0 : continue;
1410 [ + + + + : 8 : } else if (strcasecmp(key, "hostaddr") == 0) {
# # ]
1411 [ + + ]: 4 : if (val_len > SPDK_NVMF_TRADDR_MAX_LEN) {
1412 : 0 : SPDK_ERRLOG("hostaddr length %zu greater than maximum allowed %u\n",
1413 : : val_len, SPDK_NVMF_TRADDR_MAX_LEN);
1414 : 0 : return -EINVAL;
1415 : : }
1416 [ - + - + : 4 : memcpy(hostid->hostaddr, val, val_len + 1);
# # ]
1417 : :
1418 [ + + + - : 5 : } else if (strcasecmp(key, "hostsvcid") == 0) {
# # ]
1419 [ - + ]: 4 : if (val_len > SPDK_NVMF_TRSVCID_MAX_LEN) {
1420 : 0 : SPDK_ERRLOG("trsvcid length %zu greater than maximum allowed %u\n",
1421 : : val_len, SPDK_NVMF_TRSVCID_MAX_LEN);
1422 : 0 : return -EINVAL;
1423 : : }
1424 [ - + - + : 4 : memcpy(hostid->hostsvcid, val, val_len + 1);
# # ]
1425 : 1 : } else {
1426 : 0 : SPDK_ERRLOG("Unknown transport ID key '%s'\n", key);
1427 : : }
1428 : : }
1429 : :
1430 : 12 : return 0;
1431 : 3 : }
1432 : :
1433 : : static int
1434 : 35719 : cmp_int(int a, int b)
1435 : : {
1436 [ + - ]: 35719 : return a - b;
1437 : : }
1438 : :
1439 : : int
1440 : 18643 : spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1,
1441 : : const struct spdk_nvme_transport_id *trid2)
1442 : : {
1443 : : int cmp;
1444 : :
1445 [ + + + - : 18643 : if (trid1->trtype == SPDK_NVME_TRANSPORT_CUSTOM) {
- + ]
1446 [ # # # # : 0 : cmp = strcasecmp(trid1->trstring, trid2->trstring);
# # # # ]
1447 : 0 : } else {
1448 [ + - + - : 18643 : cmp = cmp_int(trid1->trtype, trid2->trtype);
+ - + - ]
1449 : : }
1450 : :
1451 [ + + ]: 18643 : if (cmp) {
1452 : 4 : return cmp;
1453 : : }
1454 : :
1455 [ + + + - : 18639 : if (trid1->trtype == SPDK_NVME_TRANSPORT_PCIE) {
- + ]
1456 : 1221 : struct spdk_pci_addr pci_addr1 = {};
1457 : 1221 : struct spdk_pci_addr pci_addr2 = {};
1458 : :
1459 : : /* Normalize PCI addresses before comparing */
1460 [ + - + + : 2417 : if (spdk_pci_addr_parse(&pci_addr1, trid1->traddr) < 0 ||
# # ]
1461 [ # # ]: 1221 : spdk_pci_addr_parse(&pci_addr2, trid2->traddr) < 0) {
1462 : 0 : return -1;
1463 : : }
1464 : :
1465 : : /* PCIe transport ID only uses trtype and traddr */
1466 : 1221 : return spdk_pci_addr_compare(&pci_addr1, &pci_addr2);
1467 : : }
1468 : :
1469 [ + + + + : 17418 : cmp = strcasecmp(trid1->traddr, trid2->traddr);
+ - + - ]
1470 [ + + ]: 17418 : if (cmp) {
1471 : 342 : return cmp;
1472 : : }
1473 : :
1474 [ + - + - : 17076 : cmp = cmp_int(trid1->adrfam, trid2->adrfam);
+ - + - ]
1475 [ + + ]: 17076 : if (cmp) {
1476 : 4 : return cmp;
1477 : : }
1478 : :
1479 [ + + + + : 17072 : cmp = strcasecmp(trid1->trsvcid, trid2->trsvcid);
+ - + - ]
1480 [ + + ]: 17072 : if (cmp) {
1481 : 1244 : return cmp;
1482 : : }
1483 : :
1484 [ + + + + : 15828 : cmp = strcmp(trid1->subnqn, trid2->subnqn);
+ - + - ]
1485 [ + + ]: 15828 : if (cmp) {
1486 : 596 : return cmp;
1487 : : }
1488 : :
1489 : 15232 : return 0;
1490 : 3543 : }
1491 : :
1492 : : int
1493 : 16 : spdk_nvme_prchk_flags_parse(uint32_t *prchk_flags, const char *str)
1494 : : {
1495 : : size_t val_len;
1496 : 12 : char key[32];
1497 : 12 : char val[1024];
1498 : :
1499 [ + + - + ]: 16 : if (prchk_flags == NULL || str == NULL) {
1500 : 4 : return -EINVAL;
1501 : : }
1502 : :
1503 [ + + # # ]: 27 : while (*str != '\0') {
1504 : 12 : val_len = parse_next_key(&str, key, val, sizeof(key), sizeof(val));
1505 : :
1506 [ + + ]: 12 : if (val_len == 0) {
1507 : 0 : SPDK_ERRLOG("Failed to parse prchk\n");
1508 : 0 : return -EINVAL;
1509 : : }
1510 : :
1511 [ + + # # : 12 : if (strcasecmp(key, "prchk") == 0) {
# # ]
1512 [ + + # # : 12 : if (strcasestr(val, "reftag") != NULL) {
# # ]
1513 [ # # # # ]: 8 : *prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_REFTAG;
1514 : 2 : }
1515 [ + + # # : 12 : if (strcasestr(val, "guard") != NULL) {
# # ]
1516 [ # # # # ]: 8 : *prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_GUARD;
1517 : 2 : }
1518 : 3 : } else {
1519 : 0 : SPDK_ERRLOG("Unknown key '%s'\n", key);
1520 : 0 : return -EINVAL;
1521 : : }
1522 : : }
1523 : :
1524 : 12 : return 0;
1525 : 4 : }
1526 : :
1527 : : const char *
1528 : 12 : spdk_nvme_prchk_flags_str(uint32_t prchk_flags)
1529 : : {
1530 [ + + # # ]: 12 : if (prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_REFTAG) {
1531 [ + + # # ]: 8 : if (prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_GUARD) {
1532 : 4 : return "prchk:reftag|guard";
1533 : : } else {
1534 : 4 : return "prchk:reftag";
1535 : : }
1536 : : } else {
1537 [ + - # # ]: 4 : if (prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_GUARD) {
1538 : 4 : return "prchk:guard";
1539 : : } else {
1540 : 0 : return NULL;
1541 : : }
1542 : : }
1543 : 3 : }
1544 : :
1545 : : int
1546 : 35988 : spdk_nvme_scan_attached(const struct spdk_nvme_transport_id *trid)
1547 : : {
1548 : : int rc;
1549 : : struct spdk_nvme_probe_ctx *probe_ctx;
1550 : :
1551 : 35988 : rc = nvme_driver_init();
1552 [ - + ]: 35988 : if (rc != 0) {
1553 : 0 : return rc;
1554 : : }
1555 : :
1556 : 35988 : probe_ctx = calloc(1, sizeof(*probe_ctx));
1557 [ + + ]: 35988 : if (!probe_ctx) {
1558 : 0 : return -ENOMEM;
1559 : : }
1560 : :
1561 : 35988 : nvme_probe_ctx_init(probe_ctx, trid, NULL, NULL, NULL, NULL, NULL, NULL);
1562 : :
1563 [ - + ]: 35988 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
1564 : 35988 : rc = nvme_transport_ctrlr_scan_attached(probe_ctx);
1565 [ - + ]: 35988 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
1566 : 35988 : free(probe_ctx);
1567 : :
1568 [ + + ]: 35988 : return rc < 0 ? rc : 0;
1569 : 228 : }
1570 : :
1571 : : struct spdk_nvme_probe_ctx *
1572 : 3745 : spdk_nvme_probe_async(const struct spdk_nvme_transport_id *trid,
1573 : : void *cb_ctx,
1574 : : spdk_nvme_probe_cb probe_cb,
1575 : : spdk_nvme_attach_cb attach_cb,
1576 : : spdk_nvme_remove_cb remove_cb)
1577 : : {
1578 : 3745 : return spdk_nvme_probe_async_ext(trid, cb_ctx, probe_cb, attach_cb, NULL, remove_cb);
1579 : : }
1580 : :
1581 : : struct spdk_nvme_probe_ctx *
1582 : 87550 : spdk_nvme_probe_async_ext(const struct spdk_nvme_transport_id *trid,
1583 : : void *cb_ctx,
1584 : : spdk_nvme_probe_cb probe_cb,
1585 : : spdk_nvme_attach_cb attach_cb,
1586 : : spdk_nvme_attach_fail_cb attach_fail_cb,
1587 : : spdk_nvme_remove_cb remove_cb)
1588 : : {
1589 : : int rc;
1590 : : struct spdk_nvme_probe_ctx *probe_ctx;
1591 : :
1592 : 87550 : rc = nvme_driver_init();
1593 [ + + ]: 87550 : if (rc != 0) {
1594 : 4 : return NULL;
1595 : : }
1596 : :
1597 : 87546 : probe_ctx = calloc(1, sizeof(*probe_ctx));
1598 [ + + ]: 87546 : if (!probe_ctx) {
1599 : 0 : return NULL;
1600 : : }
1601 : :
1602 : 87564 : nvme_probe_ctx_init(probe_ctx, trid, NULL, cb_ctx, probe_cb, attach_cb, attach_fail_cb,
1603 : 18 : remove_cb);
1604 : 87546 : rc = nvme_probe_internal(probe_ctx, false);
1605 [ + + ]: 87546 : if (rc != 0) {
1606 : 6 : free(probe_ctx);
1607 : 6 : return NULL;
1608 : : }
1609 : :
1610 : 87540 : return probe_ctx;
1611 : 19 : }
1612 : :
1613 : : int
1614 : 133681666 : spdk_nvme_probe_poll_async(struct spdk_nvme_probe_ctx *probe_ctx)
1615 : : {
1616 : : struct spdk_nvme_ctrlr *ctrlr, *ctrlr_tmp;
1617 : : struct nvme_ctrlr_detach_ctx *detach_ctx, *detach_ctx_tmp;
1618 : : int rc;
1619 : :
1620 [ + + + + : 133681666 : if (!spdk_process_is_primary() && probe_ctx->trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
# # # # #
# ]
1621 : 178 : free(probe_ctx);
1622 : 178 : return 0;
1623 : : }
1624 : :
1625 [ + + + + : 267307462 : TAILQ_FOREACH_SAFE(ctrlr, &probe_ctx->init_ctrlrs, tailq, ctrlr_tmp) {
+ - + + +
- + - + -
+ + ]
1626 : 133625974 : nvme_ctrlr_poll_internal(ctrlr, probe_ctx);
1627 : 26994250 : }
1628 : :
1629 : : /* poll failed controllers destruction */
1630 [ + + + + : 133681547 : TAILQ_FOREACH_SAFE(detach_ctx, &probe_ctx->failed_ctxs.head, link, detach_ctx_tmp) {
+ - + - -
+ # # # #
# # - + ]
1631 [ # # # # ]: 59 : rc = nvme_ctrlr_destruct_poll_async(detach_ctx->ctrlr, detach_ctx);
1632 [ - + ]: 59 : if (rc == -EAGAIN) {
1633 : 0 : continue;
1634 : : }
1635 : :
1636 [ - + ]: 59 : if (rc != 0) {
1637 : 0 : SPDK_ERRLOG("Failure while polling the controller destruction (rc = %d)\n", rc);
1638 : 0 : }
1639 : :
1640 [ - + # # : 59 : TAILQ_REMOVE(&probe_ctx->failed_ctxs.head, detach_ctx, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1641 : 59 : free(detach_ctx);
1642 : 1 : }
1643 : :
1644 [ + + + - : 133681488 : if (TAILQ_EMPTY(&probe_ctx->init_ctrlrs) && TAILQ_EMPTY(&probe_ctx->failed_ctxs.head)) {
+ - + + +
- + - + -
+ - - + ]
1645 [ + - ]: 90246 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
1646 [ + - + - ]: 90246 : g_spdk_nvme_driver->initialized = true;
1647 [ + - ]: 90246 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
1648 : 90246 : free(probe_ctx);
1649 : 90246 : return 0;
1650 : : }
1651 : :
1652 : 133591242 : return -EAGAIN;
1653 : 26994261 : }
1654 : :
1655 : : struct spdk_nvme_probe_ctx *
1656 : 2888 : spdk_nvme_connect_async(const struct spdk_nvme_transport_id *trid,
1657 : : const struct spdk_nvme_ctrlr_opts *opts,
1658 : : spdk_nvme_attach_cb attach_cb)
1659 : : {
1660 : : int rc;
1661 : 2888 : spdk_nvme_probe_cb probe_cb = NULL;
1662 : : struct spdk_nvme_probe_ctx *probe_ctx;
1663 : :
1664 : 2888 : rc = nvme_driver_init();
1665 [ - + ]: 2888 : if (rc != 0) {
1666 : 0 : return NULL;
1667 : : }
1668 : :
1669 : 2888 : probe_ctx = calloc(1, sizeof(*probe_ctx));
1670 [ + + ]: 2888 : if (!probe_ctx) {
1671 : 0 : return NULL;
1672 : : }
1673 : :
1674 [ + + ]: 2888 : if (opts) {
1675 : 1667 : probe_cb = nvme_connect_probe_cb;
1676 : 18 : }
1677 : :
1678 : 2888 : nvme_probe_ctx_init(probe_ctx, trid, opts, (void *)opts, probe_cb, attach_cb, NULL, NULL);
1679 : 2888 : rc = nvme_probe_internal(probe_ctx, true);
1680 [ + + ]: 2888 : if (rc != 0) {
1681 : 16 : free(probe_ctx);
1682 : 16 : return NULL;
1683 : : }
1684 : :
1685 : 2872 : return probe_ctx;
1686 : 836 : }
1687 : :
1688 : : int
1689 : 21213 : nvme_parse_addr(struct sockaddr_storage *sa, int family, const char *addr, const char *service,
1690 : : long int *port)
1691 : : {
1692 : 102 : struct addrinfo *res;
1693 : 102 : struct addrinfo hints;
1694 : : int ret;
1695 : :
1696 [ + + ]: 21213 : memset(&hints, 0, sizeof(hints));
1697 [ + - ]: 21213 : hints.ai_family = family;
1698 [ + - ]: 21213 : hints.ai_socktype = SOCK_STREAM;
1699 [ + - ]: 21213 : hints.ai_protocol = 0;
1700 : :
1701 [ + + ]: 21213 : if (service != NULL) {
1702 [ + - ]: 21197 : *port = spdk_strtol(service, 10);
1703 [ + - + + : 21197 : if (*port <= 0 || *port >= 65536) {
+ - - + ]
1704 : 0 : SPDK_ERRLOG("Invalid port: %s\n", service);
1705 : 0 : return -EINVAL;
1706 : : }
1707 : 1611 : }
1708 : :
1709 : 21213 : ret = getaddrinfo(addr, service, &hints, &res);
1710 [ + + ]: 21213 : if (ret) {
1711 : 4 : SPDK_ERRLOG("getaddrinfo failed: %s (%d)\n", gai_strerror(ret), ret);
1712 [ # # ]: 4 : return -(abs(ret));
1713 : : }
1714 : :
1715 [ + + + - : 21209 : if (res->ai_addrlen > sizeof(*sa)) {
- + ]
1716 [ # # # # ]: 0 : SPDK_ERRLOG("getaddrinfo() ai_addrlen %zu too large\n", (size_t)res->ai_addrlen);
1717 : 0 : ret = -EINVAL;
1718 : 0 : } else {
1719 [ + + + + : 21209 : memcpy(sa, res->ai_addr, res->ai_addrlen);
+ - + - +
- + - ]
1720 : : }
1721 : :
1722 : 21209 : freeaddrinfo(res);
1723 : 21209 : return ret;
1724 : 1612 : }
1725 : :
1726 : : int
1727 : 6440 : nvme_get_default_hostnqn(char *buf, int len)
1728 : : {
1729 : 885 : char uuid[SPDK_UUID_STRING_LEN];
1730 : : int rc;
1731 : :
1732 [ + - ]: 6440 : spdk_uuid_fmt_lower(uuid, sizeof(uuid), &g_spdk_nvme_driver->default_extended_host_id);
1733 [ - + ]: 6440 : rc = snprintf(buf, len, "nqn.2014-08.org.nvmexpress:uuid:%s", uuid);
1734 [ + - - + ]: 6440 : if (rc < 0 || rc >= len) {
1735 : 0 : return -EINVAL;
1736 : : }
1737 : :
1738 : 6440 : return 0;
1739 : 1698 : }
1740 : :
1741 : 2579 : SPDK_LOG_REGISTER_COMPONENT(nvme)
|