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 : 4318 : nvme_ctrlr_shared(const struct spdk_nvme_ctrlr *ctrlr)
28 : : {
29 : 4318 : 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 : 2173 : nvme_ctrlr_detach_async_finish(struct spdk_nvme_ctrlr *ctrlr)
41 : : {
42 : 2173 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
43 [ + + ]: 2173 : if (nvme_ctrlr_shared(ctrlr)) {
44 [ + + ]: 726 : TAILQ_REMOVE(&g_spdk_nvme_driver->shared_attached_ctrlrs, ctrlr, tailq);
45 : : } else {
46 [ + + ]: 1447 : TAILQ_REMOVE(&g_nvme_attached_ctrlrs, ctrlr, tailq);
47 : : }
48 : 2173 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
49 : 2173 : }
50 : :
51 : : static int
52 : 2402 : 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 : 2402 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
59 : :
60 : 2402 : ref_count = nvme_ctrlr_get_ref_count(ctrlr);
61 [ - + ]: 2402 : assert(ref_count > 0);
62 : :
63 [ + + ]: 2402 : 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 : 2173 : ctx = calloc(1, sizeof(*ctx));
68 [ - + ]: 2173 : if (ctx == NULL) {
69 : 0 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
70 : :
71 : 0 : return -ENOMEM;
72 : : }
73 : 2173 : ctx->ctrlr = ctrlr;
74 : 2173 : ctx->cb_fn = nvme_ctrlr_detach_async_finish;
75 : :
76 : 2173 : nvme_ctrlr_proc_put_ref(ctrlr);
77 : :
78 : 2173 : nvme_io_msg_ctrlr_detach(ctrlr);
79 : :
80 : 2173 : nvme_ctrlr_destruct_async(ctrlr, ctx);
81 : :
82 : 2173 : *_ctx = ctx;
83 : : } else {
84 : 229 : nvme_ctrlr_proc_put_ref(ctrlr);
85 : : }
86 : :
87 : 2402 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
88 : :
89 : 2402 : return 0;
90 : : }
91 : :
92 : : static int
93 : 15348821 : nvme_ctrlr_detach_poll_async(struct nvme_ctrlr_detach_ctx *ctx)
94 : : {
95 : : int rc;
96 : :
97 : 15348821 : rc = nvme_ctrlr_destruct_poll_async(ctx->ctrlr, ctx);
98 [ + + ]: 15348821 : if (rc == -EAGAIN) {
99 : 15346648 : return -EAGAIN;
100 : : }
101 : :
102 : 2173 : free(ctx);
103 : :
104 : 2173 : return rc;
105 : : }
106 : :
107 : : int
108 : 411 : spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr)
109 : : {
110 : 411 : struct nvme_ctrlr_detach_ctx *ctx = NULL;
111 : : int rc;
112 : :
113 : 411 : rc = nvme_ctrlr_detach_async(ctrlr, &ctx);
114 [ - + ]: 411 : if (rc != 0) {
115 : 0 : return rc;
116 [ + + ]: 411 : } 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 : : while (1) {
124 : 2948 : rc = nvme_ctrlr_detach_poll_async(ctx);
125 [ + + ]: 2948 : if (rc != -EAGAIN) {
126 : 407 : break;
127 : : }
128 : 2541 : nvme_delay(1000);
129 : : }
130 : :
131 : 407 : return 0;
132 : : }
133 : :
134 : : int
135 : 1991 : 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 : 1991 : struct nvme_ctrlr_detach_ctx *ctx = NULL;
140 : : int rc;
141 : :
142 [ + - - + ]: 1991 : 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 : 1991 : detach_ctx = *_detach_ctx;
150 [ + + ]: 1991 : if (detach_ctx == NULL) {
151 : 1963 : detach_ctx = calloc(1, sizeof(*detach_ctx));
152 [ - + ]: 1963 : if (detach_ctx == NULL) {
153 : 0 : return -ENOMEM;
154 : : }
155 : 1963 : TAILQ_INIT(&detach_ctx->head);
156 : : }
157 : :
158 : 1991 : rc = nvme_ctrlr_detach_async(ctrlr, &ctx);
159 [ + - + + ]: 1991 : 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 : : }
166 : 225 : return rc;
167 : : }
168 : :
169 : : /* Append a context for this detachment to the context header. */
170 : 1766 : TAILQ_INSERT_TAIL(&detach_ctx->head, ctx, link);
171 : :
172 : 1766 : *_detach_ctx = detach_ctx;
173 : :
174 : 1766 : return 0;
175 : : }
176 : :
177 : : int
178 : 15345781 : 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 [ - + ]: 15345781 : if (detach_ctx == NULL) {
184 : 0 : return -EINVAL;
185 : : }
186 : :
187 [ + + ]: 30691654 : TAILQ_FOREACH_SAFE(ctx, &detach_ctx->head, link, tmp_ctx) {
188 [ + + ]: 15345873 : TAILQ_REMOVE(&detach_ctx->head, ctx, link);
189 : :
190 : 15345873 : rc = nvme_ctrlr_detach_poll_async(ctx);
191 [ + + ]: 15345873 : if (rc == -EAGAIN) {
192 : : /* If not -EAGAIN, ctx was freed by nvme_ctrlr_detach_poll_async(). */
193 [ + + ]: 15344107 : TAILQ_INSERT_HEAD(&detach_ctx->head, ctx, link);
194 : : }
195 : : }
196 : :
197 [ + + ]: 15345781 : if (!TAILQ_EMPTY(&detach_ctx->head)) {
198 : 15344043 : return -EAGAIN;
199 : : }
200 : :
201 : 1738 : free(detach_ctx);
202 : 1738 : return 0;
203 : : }
204 : :
205 : : void
206 : 215 : spdk_nvme_detach_poll(struct spdk_nvme_detach_ctx *detach_ctx)
207 : : {
208 [ + - + + ]: 15185169 : while (detach_ctx && spdk_nvme_detach_poll_async(detach_ctx) == -EAGAIN) {
209 : : ;
210 : : }
211 : 215 : }
212 : :
213 : : void
214 : 15238 : nvme_completion_poll_cb(void *arg, const struct spdk_nvme_cpl *cpl)
215 : : {
216 : 15238 : struct nvme_completion_poll_status *status = arg;
217 : :
218 [ - + + + ]: 15238 : if (status->timed_out) {
219 : : /* There is no routine waiting for the completion of this request, free allocated memory */
220 : 4 : spdk_free(status->dma_data);
221 : 4 : free(status);
222 : 4 : 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 : 15234 : memcpy(&status->cpl, cpl, sizeof(*cpl));
231 : 15234 : status->done = true;
232 : : }
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 : 2474959 : 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 [ + + ]: 2474959 : if (robust_mutex) {
247 : 426616 : nvme_robust_mutex_lock(robust_mutex);
248 : : }
249 : :
250 [ + + ]: 2474959 : if (qpair->poll_group) {
251 : 1007761 : rc = (int)spdk_nvme_poll_group_process_completions(qpair->poll_group->group, 0,
252 : : dummy_disconnected_qpair_cb);
253 : : } else {
254 : 1467198 : rc = spdk_nvme_qpair_process_completions(qpair, 0);
255 : : }
256 : :
257 [ + + ]: 2474959 : if (robust_mutex) {
258 : 426616 : nvme_robust_mutex_unlock(robust_mutex);
259 : : }
260 : :
261 [ + + ]: 2474959 : 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 [ + + + + : 2474943 : if (!status->done && status->timeout_tsc && spdk_get_ticks() > status->timeout_tsc) {
+ + + + ]
268 : 12 : goto error;
269 : : }
270 : :
271 [ + + ]: 2474931 : if (qpair->ctrlr->trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
272 : 18720 : union spdk_nvme_csts_register csts = spdk_nvme_ctrlr_get_regs_csts(qpair->ctrlr);
273 [ - + ]: 18720 : 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 : : }
279 : :
280 [ + + + + ]: 2474931 : if (!status->done) {
281 : 2459685 : return -EAGAIN;
282 [ + + - + ]: 15246 : } else if (spdk_nvme_cpl_is_error(&status->cpl)) {
283 : 787 : return -EIO;
284 : : } else {
285 : 14459 : return 0;
286 : : }
287 : 28 : 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 [ + + + - ]: 28 : if (!status->done) {
293 : 28 : status->timed_out = true;
294 : : }
295 : :
296 : 28 : return -ECANCELED;
297 : : }
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 : 5650 : 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 [ + + ]: 5650 : if (timeout_in_usecs) {
325 : 264 : status->timeout_tsc = spdk_get_ticks() + timeout_in_usecs *
326 : 138 : spdk_get_ticks_hz() / SPDK_SEC_TO_USEC;
327 : : } else {
328 : 5512 : status->timeout_tsc = 0;
329 : : }
330 : :
331 : 5650 : status->cpl.status_raw = 0;
332 : : do {
333 : 1114929 : rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, robust_mutex);
334 [ + + ]: 1114929 : } while (rc == -EAGAIN);
335 : :
336 : 5650 : 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 : 2124 : 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 : 2124 : return nvme_wait_for_completion_robust_lock_timeout(qpair, status, robust_mutex, 0);
361 : : }
362 : :
363 : : int
364 : 3388 : nvme_wait_for_completion(struct spdk_nvme_qpair *qpair,
365 : : struct nvme_completion_poll_status *status)
366 : : {
367 : 3388 : 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 : 113 : 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 : 113 : return nvme_wait_for_completion_robust_lock_timeout(qpair, status, NULL, timeout_in_usecs);
391 : : }
392 : :
393 : : static void
394 : 73135 : nvme_user_copy_cmd_complete(void *arg, const struct spdk_nvme_cpl *cpl)
395 : : {
396 : 73135 : 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 [ + + + - ]: 73135 : if (req->user_buffer && req->payload_size) {
402 : : /* Copy back to the user buffer */
403 [ - + ]: 67074 : assert(nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_CONTIG);
404 : 67074 : xfer = spdk_nvme_opc_get_data_transfer(req->cmd.opc);
405 [ + + - + ]: 67074 : if (xfer == SPDK_NVME_DATA_CONTROLLER_TO_HOST ||
406 : : xfer == SPDK_NVME_DATA_BIDIRECTIONAL) {
407 [ - + ]: 12923 : assert(req->pid == getpid());
408 [ - + - + ]: 12923 : memcpy(req->user_buffer, req->payload.contig_or_cb_arg, req->payload_size);
409 : : }
410 : : }
411 : :
412 : 73135 : user_cb_fn = req->user_cb_fn;
413 : 73135 : user_cb_arg = req->user_cb_arg;
414 : 73135 : nvme_cleanup_user_req(req);
415 : :
416 : : /* Call the user's original callback now that the buffer has been copied */
417 : 73135 : user_cb_fn(user_cb_arg, cpl);
418 : :
419 : 73135 : }
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 : 73179 : 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 : 73179 : void *dma_buffer = NULL;
434 : :
435 [ + + + - ]: 73179 : if (buffer && payload_size) {
436 : 67118 : dma_buffer = spdk_zmalloc(payload_size, 4096, NULL,
437 : : SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
438 [ + + ]: 67118 : if (!dma_buffer) {
439 : 4 : return NULL;
440 : : }
441 : :
442 [ + + ]: 67114 : if (host_to_controller) {
443 [ - + - + ]: 54178 : memcpy(dma_buffer, buffer, payload_size);
444 : : }
445 : : }
446 : :
447 : 73175 : req = nvme_allocate_request_contig(qpair, dma_buffer, payload_size, nvme_user_copy_cmd_complete,
448 : : NULL);
449 [ + + ]: 73175 : if (!req) {
450 : 4 : spdk_free(dma_buffer);
451 : 4 : return NULL;
452 : : }
453 : :
454 : 73171 : req->user_cb_fn = cb_fn;
455 : 73171 : req->user_cb_arg = cb_arg;
456 : 73171 : req->user_buffer = buffer;
457 : 73171 : req->cb_arg = req;
458 : :
459 : 73171 : return req;
460 : : }
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 : 118157 : 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 : 118157 : struct spdk_nvme_qpair *qpair = req->qpair;
481 : 118157 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
482 : 118157 : uint64_t timeout_ticks = nvme_qpair_is_admin_queue(qpair) ?
483 [ + + ]: 118157 : active_proc->timeout_admin_ticks : active_proc->timeout_io_ticks;
484 : :
485 [ - + ]: 118157 : assert(active_proc->timeout_cb_fn != NULL);
486 : :
487 [ + + + + ]: 118157 : if (req->timed_out || req->submit_tick == 0) {
488 : 1956 : return 0;
489 : : }
490 : :
491 [ + + ]: 116201 : if (req->pid != g_spdk_nvme_pid) {
492 : 4 : return 0;
493 : : }
494 : :
495 [ + + ]: 116197 : if (nvme_qpair_is_admin_queue(qpair) &&
496 [ + + ]: 435 : req->cmd.opc == SPDK_NVME_OPC_ASYNC_EVENT_REQUEST) {
497 : 4 : return 0;
498 : : }
499 : :
500 [ + + ]: 116193 : if (req->submit_tick + timeout_ticks > now_tick) {
501 : 116189 : 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 [ + - ]: 6 : active_proc->timeout_cb_fn(active_proc->timeout_cb_arg, ctrlr,
512 : 4 : nvme_qpair_is_admin_queue(qpair) ? NULL : qpair,
513 : : cid);
514 : 4 : return 0;
515 : : }
516 : :
517 : : int
518 : 855 : nvme_robust_mutex_init_shared(pthread_mutex_t *mtx)
519 : : {
520 : 855 : int rc = 0;
521 : :
522 : : #ifdef __FreeBSD__
523 : : pthread_mutex_init(mtx, NULL);
524 : : #else
525 : 305 : pthread_mutexattr_t attr;
526 : :
527 [ + + + + ]: 855 : if (pthread_mutexattr_init(&attr)) {
528 : 8 : return -1;
529 : : }
530 [ + + + - : 1694 : if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) ||
+ - ]
531 [ + + + + ]: 1694 : pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST) ||
532 [ - + ]: 847 : pthread_mutex_init(mtx, &attr)) {
533 : 4 : rc = -1;
534 : : }
535 [ - + ]: 847 : pthread_mutexattr_destroy(&attr);
536 : : #endif
537 : :
538 : 847 : return rc;
539 : : }
540 : :
541 : : int
542 : 93029 : nvme_driver_init(void)
543 : : {
544 : : static pthread_mutex_t g_init_mutex = PTHREAD_MUTEX_INITIALIZER;
545 : 93029 : int ret = 0;
546 : : /* Any socket ID */
547 : 93029 : int socket_id = -1;
548 : :
549 : : /* Use a special process-private mutex to ensure the global
550 : : * nvme driver object (g_spdk_nvme_driver) gets initialized by
551 : : * only one thread. Once that object is established and its
552 : : * mutex is initialized, we can unlock this mutex and use that
553 : : * one instead.
554 : : */
555 [ - + ]: 93029 : pthread_mutex_lock(&g_init_mutex);
556 : :
557 : : /* Each process needs its own pid. */
558 : 93029 : g_spdk_nvme_pid = getpid();
559 : :
560 : : /*
561 : : * Only one thread from one process will do this driver init work.
562 : : * The primary process will reserve the shared memory and do the
563 : : * initialization.
564 : : * The secondary process will lookup the existing reserved memory.
565 : : */
566 [ + + ]: 93029 : if (spdk_process_is_primary()) {
567 : : /* The unique named memzone already reserved. */
568 [ + + ]: 92767 : if (g_spdk_nvme_driver != NULL) {
569 [ - + ]: 91920 : pthread_mutex_unlock(&g_init_mutex);
570 : 91920 : return 0;
571 : : } else {
572 : 847 : g_spdk_nvme_driver = spdk_memzone_reserve(SPDK_NVME_DRIVER_NAME,
573 : : sizeof(struct nvme_driver), socket_id,
574 : : SPDK_MEMZONE_NO_IOVA_CONTIG);
575 : : }
576 : :
577 [ + + ]: 847 : if (g_spdk_nvme_driver == NULL) {
578 : 4 : SPDK_ERRLOG("primary process failed to reserve memory\n");
579 [ # # ]: 4 : pthread_mutex_unlock(&g_init_mutex);
580 : 4 : return -1;
581 : : }
582 : : } else {
583 : 262 : g_spdk_nvme_driver = spdk_memzone_lookup(SPDK_NVME_DRIVER_NAME);
584 : :
585 : : /* The unique named memzone already reserved by the primary process. */
586 [ + + ]: 262 : if (g_spdk_nvme_driver != NULL) {
587 : 250 : int ms_waited = 0;
588 : :
589 : : /* Wait the nvme driver to get initialized. */
590 [ + + + + ]: 650 : while ((g_spdk_nvme_driver->initialized == false) &&
591 [ + + ]: 404 : (ms_waited < g_nvme_driver_timeout_ms)) {
592 : 400 : ms_waited++;
593 : 400 : nvme_delay(1000); /* delay 1ms */
594 : : }
595 [ + + + + ]: 250 : if (g_spdk_nvme_driver->initialized == false) {
596 : 4 : SPDK_ERRLOG("timeout waiting for primary process to init\n");
597 [ # # ]: 4 : pthread_mutex_unlock(&g_init_mutex);
598 : 4 : return -1;
599 : : }
600 : : } else {
601 : 12 : SPDK_ERRLOG("primary process is not started yet\n");
602 [ # # ]: 12 : pthread_mutex_unlock(&g_init_mutex);
603 : 12 : return -1;
604 : : }
605 : :
606 [ - + ]: 246 : pthread_mutex_unlock(&g_init_mutex);
607 : 246 : return 0;
608 : : }
609 : :
610 : : /*
611 : : * At this moment, only one thread from the primary process will do
612 : : * the g_spdk_nvme_driver initialization
613 : : */
614 [ - + ]: 843 : assert(spdk_process_is_primary());
615 : :
616 : 843 : ret = nvme_robust_mutex_init_shared(&g_spdk_nvme_driver->lock);
617 [ + + ]: 843 : if (ret != 0) {
618 : 4 : SPDK_ERRLOG("failed to initialize mutex\n");
619 : 4 : spdk_memzone_free(SPDK_NVME_DRIVER_NAME);
620 [ # # ]: 4 : pthread_mutex_unlock(&g_init_mutex);
621 : 4 : return ret;
622 : : }
623 : :
624 : : /* The lock in the shared g_spdk_nvme_driver object is now ready to
625 : : * be used - so we can unlock the g_init_mutex here.
626 : : */
627 [ - + ]: 839 : pthread_mutex_unlock(&g_init_mutex);
628 : 839 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
629 : :
630 : 839 : g_spdk_nvme_driver->initialized = false;
631 : 839 : g_spdk_nvme_driver->hotplug_fd = spdk_pci_event_listen();
632 [ - + ]: 839 : if (g_spdk_nvme_driver->hotplug_fd < 0) {
633 [ # # # # ]: 0 : SPDK_DEBUGLOG(nvme, "Failed to open uevent netlink socket\n");
634 : : }
635 : :
636 : 839 : TAILQ_INIT(&g_spdk_nvme_driver->shared_attached_ctrlrs);
637 : :
638 : 839 : spdk_uuid_generate(&g_spdk_nvme_driver->default_extended_host_id);
639 : :
640 : 839 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
641 : :
642 : 839 : return ret;
643 : : }
644 : :
645 : : /* This function must only be called while holding g_spdk_nvme_driver->lock */
646 : : int
647 : 2195 : nvme_ctrlr_probe(const struct spdk_nvme_transport_id *trid,
648 : : struct spdk_nvme_probe_ctx *probe_ctx, void *devhandle)
649 : : {
650 : : struct spdk_nvme_ctrlr *ctrlr;
651 : 428 : struct spdk_nvme_ctrlr_opts opts;
652 : :
653 [ - + ]: 2195 : assert(trid != NULL);
654 : :
655 : 2195 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&opts, sizeof(opts));
656 : :
657 [ + + + + ]: 2195 : if (!probe_ctx->probe_cb || probe_ctx->probe_cb(probe_ctx->cb_ctx, trid, &opts)) {
658 : 2169 : ctrlr = nvme_get_ctrlr_by_trid_unsafe(trid, opts.hostnqn);
659 [ - + ]: 2169 : if (ctrlr) {
660 : : /* This ctrlr already exists. */
661 : :
662 [ # # # # ]: 0 : if (ctrlr->is_destructed) {
663 : : /* This ctrlr is being destructed asynchronously. */
664 : 0 : SPDK_ERRLOG("NVMe controller for SSD: %s is being destructed\n",
665 : : trid->traddr);
666 : 0 : return -EBUSY;
667 : : }
668 : :
669 : : /* Increase the ref count before calling attach_cb() as the user may
670 : : * call nvme_detach() immediately. */
671 : 0 : nvme_ctrlr_proc_get_ref(ctrlr);
672 : :
673 [ # # ]: 0 : if (probe_ctx->attach_cb) {
674 : 0 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
675 : 0 : probe_ctx->attach_cb(probe_ctx->cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts);
676 : 0 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
677 : : }
678 : 0 : return 0;
679 : : }
680 : :
681 : 2169 : ctrlr = nvme_transport_ctrlr_construct(trid, &opts, devhandle);
682 [ + + ]: 2169 : if (ctrlr == NULL) {
683 : 11 : SPDK_ERRLOG("Failed to construct NVMe controller for SSD: %s\n", trid->traddr);
684 : 11 : return -1;
685 : : }
686 : 2158 : ctrlr->remove_cb = probe_ctx->remove_cb;
687 : 2158 : ctrlr->cb_ctx = probe_ctx->cb_ctx;
688 : :
689 : 2158 : nvme_qpair_set_state(ctrlr->adminq, NVME_QPAIR_ENABLED);
690 : 2158 : TAILQ_INSERT_TAIL(&probe_ctx->init_ctrlrs, ctrlr, tailq);
691 : 2158 : return 0;
692 : : }
693 : :
694 : 26 : return 1;
695 : : }
696 : :
697 : : static void
698 : 120700151 : nvme_ctrlr_poll_internal(struct spdk_nvme_ctrlr *ctrlr,
699 : : struct spdk_nvme_probe_ctx *probe_ctx)
700 : : {
701 : 120700151 : int rc = 0;
702 : :
703 : 120700151 : rc = nvme_ctrlr_process_init(ctrlr);
704 : :
705 [ + + ]: 120700151 : if (rc) {
706 : : /* Controller failed to initialize. */
707 [ - + ]: 58 : TAILQ_REMOVE(&probe_ctx->init_ctrlrs, ctrlr, tailq);
708 : 58 : SPDK_ERRLOG("Failed to initialize SSD: %s\n", ctrlr->trid.traddr);
709 : 58 : nvme_ctrlr_lock(ctrlr);
710 : 58 : nvme_ctrlr_fail(ctrlr, false);
711 : 58 : nvme_ctrlr_unlock(ctrlr);
712 : 58 : nvme_ctrlr_destruct(ctrlr);
713 : 58 : return;
714 : : }
715 : :
716 [ + + ]: 120700093 : if (ctrlr->state != NVME_CTRLR_STATE_READY) {
717 : 120697948 : return;
718 : : }
719 : :
720 : 2145 : STAILQ_INIT(&ctrlr->io_producers);
721 : :
722 : : /*
723 : : * Controller has been initialized.
724 : : * Move it to the attached_ctrlrs list.
725 : : */
726 [ + + ]: 2145 : TAILQ_REMOVE(&probe_ctx->init_ctrlrs, ctrlr, tailq);
727 : :
728 : 2145 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
729 [ + + ]: 2145 : if (nvme_ctrlr_shared(ctrlr)) {
730 : 702 : TAILQ_INSERT_TAIL(&g_spdk_nvme_driver->shared_attached_ctrlrs, ctrlr, tailq);
731 : : } else {
732 : 1443 : TAILQ_INSERT_TAIL(&g_nvme_attached_ctrlrs, ctrlr, tailq);
733 : : }
734 : :
735 : : /*
736 : : * Increase the ref count before calling attach_cb() as the user may
737 : : * call nvme_detach() immediately.
738 : : */
739 : 2145 : nvme_ctrlr_proc_get_ref(ctrlr);
740 : 2145 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
741 : :
742 [ + + ]: 2145 : if (probe_ctx->attach_cb) {
743 : 1711 : probe_ctx->attach_cb(probe_ctx->cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts);
744 : : }
745 : : }
746 : :
747 : : static int
748 : 81926 : nvme_init_controllers(struct spdk_nvme_probe_ctx *probe_ctx)
749 : : {
750 : 81926 : int rc = 0;
751 : :
752 : : while (true) {
753 : 120410421 : rc = spdk_nvme_probe_poll_async(probe_ctx);
754 [ + + ]: 120410421 : if (rc != -EAGAIN) {
755 : 81926 : return rc;
756 : : }
757 : : }
758 : :
759 : : return rc;
760 : : }
761 : :
762 : : /* This function must not be called while holding g_spdk_nvme_driver->lock */
763 : : static struct spdk_nvme_ctrlr *
764 : 498 : nvme_get_ctrlr_by_trid(const struct spdk_nvme_transport_id *trid, const char *hostnqn)
765 : : {
766 : : struct spdk_nvme_ctrlr *ctrlr;
767 : :
768 : 498 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
769 : 498 : ctrlr = nvme_get_ctrlr_by_trid_unsafe(trid, hostnqn);
770 : 498 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
771 : :
772 : 498 : return ctrlr;
773 : : }
774 : :
775 : : /* This function must be called while holding g_spdk_nvme_driver->lock */
776 : : struct spdk_nvme_ctrlr *
777 : 3684 : nvme_get_ctrlr_by_trid_unsafe(const struct spdk_nvme_transport_id *trid, const char *hostnqn)
778 : : {
779 : : struct spdk_nvme_ctrlr *ctrlr;
780 : :
781 : : /* Search per-process list */
782 [ + + ]: 4009 : TAILQ_FOREACH(ctrlr, &g_nvme_attached_ctrlrs, tailq) {
783 [ + + ]: 721 : if (spdk_nvme_transport_id_compare(&ctrlr->trid, trid) != 0) {
784 : 322 : continue;
785 : : }
786 [ + - - + : 399 : if (hostnqn && strcmp(ctrlr->opts.hostnqn, hostnqn) != 0) {
- + + + ]
787 : 3 : continue;
788 : : }
789 : 396 : return ctrlr;
790 : : }
791 : :
792 : : /* Search multi-process shared list */
793 [ + + ]: 3811 : TAILQ_FOREACH(ctrlr, &g_spdk_nvme_driver->shared_attached_ctrlrs, tailq) {
794 [ + + ]: 918 : if (spdk_nvme_transport_id_compare(&ctrlr->trid, trid) != 0) {
795 : 523 : continue;
796 : : }
797 [ + + - + : 395 : if (hostnqn && strcmp(ctrlr->opts.hostnqn, hostnqn) != 0) {
- + - + ]
798 : 0 : continue;
799 : : }
800 : 395 : return ctrlr;
801 : : }
802 : :
803 : 2893 : return NULL;
804 : : }
805 : :
806 : : /* This function must only be called while holding g_spdk_nvme_driver->lock */
807 : : static int
808 : 88483 : nvme_probe_internal(struct spdk_nvme_probe_ctx *probe_ctx,
809 : : bool direct_connect)
810 : : {
811 : : int rc;
812 : : struct spdk_nvme_ctrlr *ctrlr, *ctrlr_tmp;
813 : 88483 : const struct spdk_nvme_ctrlr_opts *opts = probe_ctx->opts;
814 : :
815 [ + + ]: 88483 : if (strlen(probe_ctx->trid.trstring) == 0) {
816 : : /* If user didn't provide trstring, derive it from trtype */
817 : 84 : spdk_nvme_trid_populate_transport(&probe_ctx->trid, probe_ctx->trid.trtype);
818 : : }
819 : :
820 [ + + ]: 88483 : if (!spdk_nvme_transport_available_by_name(probe_ctx->trid.trstring)) {
821 : 4 : SPDK_ERRLOG("NVMe trtype %u (%s) not available\n",
822 : : probe_ctx->trid.trtype, probe_ctx->trid.trstring);
823 : 4 : return -1;
824 : : }
825 : :
826 : 88479 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
827 : :
828 : 88479 : rc = nvme_transport_ctrlr_scan(probe_ctx, direct_connect);
829 [ + + ]: 88479 : if (rc != 0) {
830 : 19 : SPDK_ERRLOG("NVMe ctrlr scan failed\n");
831 [ + + ]: 23 : TAILQ_FOREACH_SAFE(ctrlr, &probe_ctx->init_ctrlrs, tailq, ctrlr_tmp) {
832 [ - + ]: 4 : TAILQ_REMOVE(&probe_ctx->init_ctrlrs, ctrlr, tailq);
833 : 4 : nvme_transport_ctrlr_destruct(ctrlr);
834 : : }
835 : 19 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
836 : 19 : return -1;
837 : : }
838 : :
839 : : /*
840 : : * Probe controllers on the shared_attached_ctrlrs list
841 : : */
842 [ + + + - ]: 88460 : if (!spdk_process_is_primary() && (probe_ctx->trid.trtype == SPDK_NVME_TRANSPORT_PCIE)) {
843 [ + + ]: 466 : TAILQ_FOREACH(ctrlr, &g_spdk_nvme_driver->shared_attached_ctrlrs, tailq) {
844 : : /* Do not attach other ctrlrs if user specify a valid trid */
845 [ + + + + ]: 362 : if ((strlen(probe_ctx->trid.traddr) != 0) &&
846 : 74 : (spdk_nvme_transport_id_compare(&probe_ctx->trid, &ctrlr->trid))) {
847 : 30 : continue;
848 : : }
849 : :
850 [ + + - + : 258 : if (opts && strcmp(opts->hostnqn, ctrlr->opts.hostnqn) != 0) {
- + - + ]
851 : 0 : continue;
852 : : }
853 : :
854 : : /* Do not attach if we failed to initialize it in this process */
855 [ - + ]: 258 : if (nvme_ctrlr_get_current_process(ctrlr) == NULL) {
856 : 0 : continue;
857 : : }
858 : :
859 : 258 : nvme_ctrlr_proc_get_ref(ctrlr);
860 : :
861 : : /*
862 : : * Unlock while calling attach_cb() so the user can call other functions
863 : : * that may take the driver lock, like nvme_detach().
864 : : */
865 [ + + ]: 258 : if (probe_ctx->attach_cb) {
866 : 218 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
867 : 218 : probe_ctx->attach_cb(probe_ctx->cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts);
868 : 218 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
869 : : }
870 : : }
871 : : }
872 : :
873 : 88460 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
874 : :
875 : 88460 : return 0;
876 : : }
877 : :
878 : : static void
879 : 88495 : nvme_probe_ctx_init(struct spdk_nvme_probe_ctx *probe_ctx,
880 : : const struct spdk_nvme_transport_id *trid,
881 : : const struct spdk_nvme_ctrlr_opts *opts,
882 : : void *cb_ctx,
883 : : spdk_nvme_probe_cb probe_cb,
884 : : spdk_nvme_attach_cb attach_cb,
885 : : spdk_nvme_remove_cb remove_cb)
886 : : {
887 : 88495 : probe_ctx->trid = *trid;
888 : 88495 : probe_ctx->opts = opts;
889 : 88495 : probe_ctx->cb_ctx = cb_ctx;
890 : 88495 : probe_ctx->probe_cb = probe_cb;
891 : 88495 : probe_ctx->attach_cb = attach_cb;
892 : 88495 : probe_ctx->remove_cb = remove_cb;
893 : 88495 : TAILQ_INIT(&probe_ctx->init_ctrlrs);
894 : 88495 : }
895 : :
896 : : int
897 : 81442 : spdk_nvme_probe(const struct spdk_nvme_transport_id *trid, void *cb_ctx,
898 : : spdk_nvme_probe_cb probe_cb, spdk_nvme_attach_cb attach_cb,
899 : : spdk_nvme_remove_cb remove_cb)
900 : : {
901 : 37144 : struct spdk_nvme_transport_id trid_pcie;
902 : : struct spdk_nvme_probe_ctx *probe_ctx;
903 : :
904 [ + + ]: 81442 : if (trid == NULL) {
905 [ - + ]: 81230 : memset(&trid_pcie, 0, sizeof(trid_pcie));
906 : 81230 : spdk_nvme_trid_populate_transport(&trid_pcie, SPDK_NVME_TRANSPORT_PCIE);
907 : 81230 : trid = &trid_pcie;
908 : : }
909 : :
910 : 81442 : probe_ctx = spdk_nvme_probe_async(trid, cb_ctx, probe_cb,
911 : : attach_cb, remove_cb);
912 [ + + ]: 81442 : if (!probe_ctx) {
913 : 10 : SPDK_ERRLOG("Create probe context failed\n");
914 : 10 : return -1;
915 : : }
916 : :
917 : : /*
918 : : * Keep going even if one or more nvme_attach() calls failed,
919 : : * but maintain the value of rc to signal errors when we return.
920 : : */
921 : 81432 : return nvme_init_controllers(probe_ctx);
922 : : }
923 : :
924 : : static bool
925 : 1585 : nvme_connect_probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
926 : : struct spdk_nvme_ctrlr_opts *opts)
927 : : {
928 : 1585 : struct spdk_nvme_ctrlr_opts *requested_opts = cb_ctx;
929 : :
930 [ - + ]: 1585 : assert(requested_opts);
931 [ - + - + ]: 1585 : memcpy(opts, requested_opts, sizeof(*opts));
932 : :
933 : 1585 : return true;
934 : : }
935 : :
936 : : static void
937 : 81 : nvme_ctrlr_opts_init(struct spdk_nvme_ctrlr_opts *opts,
938 : : const struct spdk_nvme_ctrlr_opts *opts_user,
939 : : size_t opts_size_user)
940 : : {
941 [ - + ]: 81 : assert(opts);
942 [ - + ]: 81 : assert(opts_user);
943 : :
944 : 81 : spdk_nvme_ctrlr_get_default_ctrlr_opts(opts, opts_size_user);
945 : :
946 : : #define FIELD_OK(field) \
947 : : offsetof(struct spdk_nvme_ctrlr_opts, field) + sizeof(opts->field) <= (opts->opts_size)
948 : :
949 : : #define SET_FIELD(field) \
950 : : if (FIELD_OK(field)) { \
951 : : opts->field = opts_user->field; \
952 : : }
953 : :
954 : : #define SET_FIELD_ARRAY(field) \
955 : : if (FIELD_OK(field)) { \
956 : : memcpy(opts->field, opts_user->field, sizeof(opts_user->field)); \
957 : : }
958 : :
959 [ + + ]: 81 : SET_FIELD(num_io_queues);
960 [ + + - + ]: 81 : SET_FIELD(use_cmb_sqs);
961 [ + + - + ]: 81 : SET_FIELD(no_shn_notification);
962 [ + + ]: 81 : SET_FIELD(arb_mechanism);
963 [ + + ]: 81 : SET_FIELD(arbitration_burst);
964 [ + + ]: 81 : SET_FIELD(low_priority_weight);
965 [ + + ]: 81 : SET_FIELD(medium_priority_weight);
966 [ + + ]: 81 : SET_FIELD(high_priority_weight);
967 [ + + ]: 81 : SET_FIELD(keep_alive_timeout_ms);
968 [ + + ]: 81 : SET_FIELD(transport_retry_count);
969 [ + + ]: 81 : SET_FIELD(io_queue_size);
970 [ + + - + : 81 : SET_FIELD_ARRAY(hostnqn);
- + ]
971 [ + + ]: 81 : SET_FIELD(io_queue_requests);
972 [ + + - + : 81 : SET_FIELD_ARRAY(src_addr);
- + ]
973 [ + + - + : 81 : SET_FIELD_ARRAY(src_svcid);
- + ]
974 [ + + ]: 81 : SET_FIELD_ARRAY(host_id);
975 [ + + ]: 81 : SET_FIELD_ARRAY(extended_host_id);
976 [ + + ]: 81 : SET_FIELD(command_set);
977 [ + + ]: 81 : SET_FIELD(admin_timeout_ms);
978 [ + + - + ]: 81 : SET_FIELD(header_digest);
979 [ + + - + ]: 81 : SET_FIELD(data_digest);
980 [ + + - + ]: 81 : SET_FIELD(disable_error_logging);
981 [ + + ]: 81 : SET_FIELD(transport_ack_timeout);
982 [ + + ]: 81 : SET_FIELD(admin_queue_size);
983 [ + + ]: 81 : SET_FIELD(fabrics_connect_timeout_us);
984 [ + + - + ]: 81 : SET_FIELD(disable_read_ana_log_page);
985 [ + + ]: 81 : SET_FIELD(disable_read_changed_ns_list_log_page);
986 [ + + - + : 81 : SET_FIELD_ARRAY(psk);
- + ]
987 [ + + ]: 81 : SET_FIELD(tls_psk);
988 [ + + ]: 81 : SET_FIELD(dhchap_key);
989 [ + + ]: 81 : SET_FIELD(dhchap_ctrlr_key);
990 [ + + ]: 81 : SET_FIELD(dhchap_digests);
991 [ + + ]: 81 : SET_FIELD(dhchap_dhgroups);
992 : :
993 : : #undef FIELD_OK
994 : : #undef SET_FIELD
995 : : #undef SET_FIELD_ARRAY
996 : 81 : }
997 : :
998 : : struct spdk_nvme_ctrlr *
999 : 490 : spdk_nvme_connect(const struct spdk_nvme_transport_id *trid,
1000 : : const struct spdk_nvme_ctrlr_opts *opts, size_t opts_size)
1001 : : {
1002 : : int rc;
1003 : 490 : struct spdk_nvme_ctrlr *ctrlr = NULL;
1004 : : struct spdk_nvme_probe_ctx *probe_ctx;
1005 : 490 : struct spdk_nvme_ctrlr_opts *opts_local_p = NULL;
1006 : 72 : struct spdk_nvme_ctrlr_opts opts_local;
1007 : 72 : char hostnqn[SPDK_NVMF_NQN_MAX_LEN + 1];
1008 : :
1009 [ + + ]: 490 : if (trid == NULL) {
1010 : 4 : SPDK_ERRLOG("No transport ID specified\n");
1011 : 4 : return NULL;
1012 : : }
1013 : :
1014 : 486 : rc = nvme_driver_init();
1015 [ + + ]: 486 : if (rc != 0) {
1016 : 4 : return NULL;
1017 : : }
1018 : :
1019 : 482 : nvme_get_default_hostnqn(hostnqn, sizeof(hostnqn));
1020 [ + + ]: 482 : if (opts) {
1021 : 81 : opts_local_p = &opts_local;
1022 : 81 : nvme_ctrlr_opts_init(opts_local_p, opts, opts_size);
1023 : 81 : memcpy(hostnqn, opts_local.hostnqn, sizeof(hostnqn));
1024 : : }
1025 : :
1026 : 482 : probe_ctx = spdk_nvme_connect_async(trid, opts_local_p, NULL);
1027 [ - + ]: 482 : if (!probe_ctx) {
1028 : 0 : SPDK_ERRLOG("Create probe context failed\n");
1029 : 0 : return NULL;
1030 : : }
1031 : :
1032 : 482 : rc = nvme_init_controllers(probe_ctx);
1033 [ - + ]: 482 : if (rc != 0) {
1034 : 0 : return NULL;
1035 : : }
1036 : :
1037 : 482 : ctrlr = nvme_get_ctrlr_by_trid(trid, hostnqn);
1038 : :
1039 : 482 : return ctrlr;
1040 : : }
1041 : :
1042 : : void
1043 : 97302 : spdk_nvme_trid_populate_transport(struct spdk_nvme_transport_id *trid,
1044 : : enum spdk_nvme_transport_type trtype)
1045 : : {
1046 : : const char *trstring;
1047 : :
1048 : 97302 : trid->trtype = trtype;
1049 [ - + + + : 97302 : switch (trtype) {
- - - ]
1050 : 0 : case SPDK_NVME_TRANSPORT_FC:
1051 : 0 : trstring = SPDK_NVME_TRANSPORT_NAME_FC;
1052 : 0 : break;
1053 : 87457 : case SPDK_NVME_TRANSPORT_PCIE:
1054 : 87457 : trstring = SPDK_NVME_TRANSPORT_NAME_PCIE;
1055 : 87457 : break;
1056 : 1868 : case SPDK_NVME_TRANSPORT_RDMA:
1057 : 1868 : trstring = SPDK_NVME_TRANSPORT_NAME_RDMA;
1058 : 1868 : break;
1059 : 7977 : case SPDK_NVME_TRANSPORT_TCP:
1060 : 7977 : trstring = SPDK_NVME_TRANSPORT_NAME_TCP;
1061 : 7977 : break;
1062 : 0 : case SPDK_NVME_TRANSPORT_VFIOUSER:
1063 : 0 : trstring = SPDK_NVME_TRANSPORT_NAME_VFIOUSER;
1064 : 0 : break;
1065 : 0 : case SPDK_NVME_TRANSPORT_CUSTOM:
1066 : 0 : trstring = SPDK_NVME_TRANSPORT_NAME_CUSTOM;
1067 : 0 : break;
1068 : 0 : default:
1069 : 0 : SPDK_ERRLOG("no available transports\n");
1070 : 0 : assert(0);
1071 : : return;
1072 : : }
1073 [ - + ]: 97302 : snprintf(trid->trstring, SPDK_NVMF_TRSTRING_MAX_LEN, "%s", trstring);
1074 : 49 : }
1075 : :
1076 : : int
1077 : 2588 : spdk_nvme_transport_id_populate_trstring(struct spdk_nvme_transport_id *trid, const char *trstring)
1078 : : {
1079 : 2588 : int i = 0;
1080 : :
1081 [ + - - + ]: 2588 : if (trid == NULL || trstring == NULL) {
1082 : 0 : return -EINVAL;
1083 : : }
1084 : :
1085 : : /* Note: gcc-11 has some false positive -Wstringop-overread warnings with LTO builds if we
1086 : : * use strnlen here. So do the trstring copy manually instead. See GitHub issue #2391.
1087 : : */
1088 : :
1089 : : /* cast official trstring to uppercase version of input. */
1090 [ + - + + ]: 11708 : while (i < SPDK_NVMF_TRSTRING_MAX_LEN && trstring[i] != 0) {
1091 : 9120 : trid->trstring[i] = toupper(trstring[i]);
1092 : 9120 : i++;
1093 : : }
1094 : :
1095 [ - + ]: 2588 : if (trstring[i] != 0) {
1096 : 0 : return -EINVAL;
1097 : : } else {
1098 : 2588 : trid->trstring[i] = 0;
1099 : 2588 : return 0;
1100 : : }
1101 : : }
1102 : :
1103 : : int
1104 : 2532 : spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str)
1105 : : {
1106 [ + + + + ]: 2532 : if (trtype == NULL || str == NULL) {
1107 : 8 : return -EINVAL;
1108 : : }
1109 : :
1110 [ + + + + ]: 2524 : if (strcasecmp(str, "PCIe") == 0) {
1111 : 660 : *trtype = SPDK_NVME_TRANSPORT_PCIE;
1112 [ + + + + ]: 1864 : } else if (strcasecmp(str, "RDMA") == 0) {
1113 : 393 : *trtype = SPDK_NVME_TRANSPORT_RDMA;
1114 [ + + + + ]: 1471 : } else if (strcasecmp(str, "FC") == 0) {
1115 : 8 : *trtype = SPDK_NVME_TRANSPORT_FC;
1116 [ + + + + ]: 1463 : } else if (strcasecmp(str, "TCP") == 0) {
1117 : 1403 : *trtype = SPDK_NVME_TRANSPORT_TCP;
1118 [ - + + + ]: 60 : } else if (strcasecmp(str, "VFIOUSER") == 0) {
1119 : 56 : *trtype = SPDK_NVME_TRANSPORT_VFIOUSER;
1120 : : } else {
1121 : 4 : *trtype = SPDK_NVME_TRANSPORT_CUSTOM;
1122 : : }
1123 : 2524 : return 0;
1124 : : }
1125 : :
1126 : : const char *
1127 : 3176 : spdk_nvme_transport_id_trtype_str(enum spdk_nvme_transport_type trtype)
1128 : : {
1129 [ + + + + : 3176 : switch (trtype) {
- - + ]
1130 : 1184 : case SPDK_NVME_TRANSPORT_PCIE:
1131 : 1184 : return "PCIe";
1132 : 451 : case SPDK_NVME_TRANSPORT_RDMA:
1133 : 451 : return "RDMA";
1134 : 4 : case SPDK_NVME_TRANSPORT_FC:
1135 : 4 : return "FC";
1136 : 1533 : case SPDK_NVME_TRANSPORT_TCP:
1137 : 1533 : return "TCP";
1138 : 0 : case SPDK_NVME_TRANSPORT_VFIOUSER:
1139 : 0 : return "VFIOUSER";
1140 : 0 : case SPDK_NVME_TRANSPORT_CUSTOM:
1141 : 0 : return "CUSTOM";
1142 : 4 : default:
1143 : 4 : return NULL;
1144 : : }
1145 : : }
1146 : :
1147 : : int
1148 : 1208 : spdk_nvme_transport_id_parse_adrfam(enum spdk_nvmf_adrfam *adrfam, const char *str)
1149 : : {
1150 [ + + + + ]: 1208 : if (adrfam == NULL || str == NULL) {
1151 : 8 : return -EINVAL;
1152 : : }
1153 : :
1154 [ + + + + ]: 1200 : if (strcasecmp(str, "IPv4") == 0) {
1155 : 1172 : *adrfam = SPDK_NVMF_ADRFAM_IPV4;
1156 [ + + + + ]: 28 : } else if (strcasecmp(str, "IPv6") == 0) {
1157 : 8 : *adrfam = SPDK_NVMF_ADRFAM_IPV6;
1158 [ + + + + ]: 20 : } else if (strcasecmp(str, "IB") == 0) {
1159 : 8 : *adrfam = SPDK_NVMF_ADRFAM_IB;
1160 [ + + + + ]: 12 : } else if (strcasecmp(str, "FC") == 0) {
1161 : 8 : *adrfam = SPDK_NVMF_ADRFAM_FC;
1162 : : } else {
1163 : 4 : return -ENOENT;
1164 : : }
1165 : 1196 : return 0;
1166 : : }
1167 : :
1168 : : const char *
1169 : 5088 : spdk_nvme_transport_id_adrfam_str(enum spdk_nvmf_adrfam adrfam)
1170 : : {
1171 [ + + + + : 5088 : switch (adrfam) {
+ ]
1172 : 3914 : case SPDK_NVMF_ADRFAM_IPV4:
1173 : 3914 : return "IPv4";
1174 : 4 : case SPDK_NVMF_ADRFAM_IPV6:
1175 : 4 : return "IPv6";
1176 : 4 : case SPDK_NVMF_ADRFAM_IB:
1177 : 4 : return "IB";
1178 : 4 : case SPDK_NVMF_ADRFAM_FC:
1179 : 4 : return "FC";
1180 : 1162 : default:
1181 : 1162 : return NULL;
1182 : : }
1183 : : }
1184 : :
1185 : : static size_t
1186 : 939 : parse_next_key(const char **str, char *key, char *val, size_t key_buf_size, size_t val_buf_size)
1187 : : {
1188 : :
1189 : : const char *sep, *sep1;
1190 : 939 : const char *whitespace = " \t\n";
1191 : : size_t key_len, val_len;
1192 : :
1193 [ - + - + ]: 939 : *str += strspn(*str, whitespace);
1194 : :
1195 [ - + ]: 939 : sep = strchr(*str, ':');
1196 [ + + ]: 939 : if (!sep) {
1197 [ - + ]: 56 : sep = strchr(*str, '=');
1198 [ + + ]: 56 : if (!sep) {
1199 : 4 : SPDK_ERRLOG("Key without ':' or '=' separator\n");
1200 : 4 : return 0;
1201 : : }
1202 : : } else {
1203 [ - + ]: 883 : sep1 = strchr(*str, '=');
1204 [ + + + - ]: 883 : if ((sep1 != NULL) && (sep1 < sep)) {
1205 : 16 : sep = sep1;
1206 : : }
1207 : : }
1208 : :
1209 : 935 : key_len = sep - *str;
1210 [ + + ]: 935 : if (key_len >= key_buf_size) {
1211 : 4 : SPDK_ERRLOG("Key length %zu greater than maximum allowed %zu\n",
1212 : : key_len, key_buf_size - 1);
1213 : 4 : return 0;
1214 : : }
1215 : :
1216 [ - + - + ]: 931 : memcpy(key, *str, key_len);
1217 : 931 : key[key_len] = '\0';
1218 : :
1219 : 931 : *str += key_len + 1; /* Skip key: */
1220 [ - + - + ]: 931 : val_len = strcspn(*str, whitespace);
1221 [ + + ]: 931 : if (val_len == 0) {
1222 : 4 : SPDK_ERRLOG("Key without value\n");
1223 : 4 : return 0;
1224 : : }
1225 : :
1226 [ - + ]: 927 : if (val_len >= val_buf_size) {
1227 : 0 : SPDK_ERRLOG("Value length %zu greater than maximum allowed %zu\n",
1228 : : val_len, val_buf_size - 1);
1229 : 0 : return 0;
1230 : : }
1231 : :
1232 [ - + - + ]: 927 : memcpy(val, *str, val_len);
1233 : 927 : val[val_len] = '\0';
1234 : :
1235 : 927 : *str += val_len;
1236 : :
1237 : 927 : return val_len;
1238 : : }
1239 : :
1240 : : int
1241 : 329 : spdk_nvme_transport_id_parse(struct spdk_nvme_transport_id *trid, const char *str)
1242 : : {
1243 : : size_t val_len;
1244 : 130 : char key[32];
1245 : 130 : char val[1024];
1246 : :
1247 [ + + + + ]: 329 : if (trid == NULL || str == NULL) {
1248 : 12 : return -EINVAL;
1249 : : }
1250 : :
1251 [ + + ]: 1220 : while (*str != '\0') {
1252 : :
1253 : 915 : val_len = parse_next_key(&str, key, val, sizeof(key), sizeof(val));
1254 : :
1255 [ + + ]: 915 : if (val_len == 0) {
1256 : 12 : SPDK_ERRLOG("Failed to parse transport ID\n");
1257 : 12 : return -EINVAL;
1258 : : }
1259 : :
1260 [ + + ]: 903 : if (strcasecmp(key, "trtype") == 0) {
1261 [ - + ]: 305 : if (spdk_nvme_transport_id_populate_trstring(trid, val) != 0) {
1262 : 0 : SPDK_ERRLOG("invalid transport '%s'\n", val);
1263 : 0 : return -EINVAL;
1264 : : }
1265 [ - + ]: 305 : if (spdk_nvme_transport_id_parse_trtype(&trid->trtype, val) != 0) {
1266 : 0 : SPDK_ERRLOG("Unknown trtype '%s'\n", val);
1267 : 0 : return -EINVAL;
1268 : : }
1269 [ + + ]: 598 : } else if (strcasecmp(key, "adrfam") == 0) {
1270 [ - + ]: 116 : if (spdk_nvme_transport_id_parse_adrfam(&trid->adrfam, val) != 0) {
1271 : 0 : SPDK_ERRLOG("Unknown adrfam '%s'\n", val);
1272 : 0 : return -EINVAL;
1273 : : }
1274 [ + + ]: 482 : } else if (strcasecmp(key, "traddr") == 0) {
1275 [ - + ]: 257 : if (val_len > SPDK_NVMF_TRADDR_MAX_LEN) {
1276 : 0 : SPDK_ERRLOG("traddr length %zu greater than maximum allowed %u\n",
1277 : : val_len, SPDK_NVMF_TRADDR_MAX_LEN);
1278 : 0 : return -EINVAL;
1279 : : }
1280 [ - + ]: 257 : memcpy(trid->traddr, val, val_len + 1);
1281 [ + + ]: 225 : } else if (strcasecmp(key, "trsvcid") == 0) {
1282 [ - + ]: 116 : if (val_len > SPDK_NVMF_TRSVCID_MAX_LEN) {
1283 : 0 : SPDK_ERRLOG("trsvcid length %zu greater than maximum allowed %u\n",
1284 : : val_len, SPDK_NVMF_TRSVCID_MAX_LEN);
1285 : 0 : return -EINVAL;
1286 : : }
1287 [ - + ]: 116 : memcpy(trid->trsvcid, val, val_len + 1);
1288 [ + + ]: 109 : } else if (strcasecmp(key, "priority") == 0) {
1289 [ - + ]: 4 : if (val_len > SPDK_NVMF_PRIORITY_MAX_LEN) {
1290 : 0 : SPDK_ERRLOG("priority length %zu greater than maximum allowed %u\n",
1291 : : val_len, SPDK_NVMF_PRIORITY_MAX_LEN);
1292 : 0 : return -EINVAL;
1293 : : }
1294 : 4 : trid->priority = spdk_strtol(val, 10);
1295 [ + + ]: 105 : } else if (strcasecmp(key, "subnqn") == 0) {
1296 [ - + ]: 98 : if (val_len > SPDK_NVMF_NQN_MAX_LEN) {
1297 : 0 : SPDK_ERRLOG("subnqn length %zu greater than maximum allowed %u\n",
1298 : : val_len, SPDK_NVMF_NQN_MAX_LEN);
1299 : 0 : return -EINVAL;
1300 : : }
1301 [ - + ]: 98 : memcpy(trid->subnqn, val, val_len + 1);
1302 [ - + ]: 7 : } else if (strcasecmp(key, "hostaddr") == 0) {
1303 : 0 : continue;
1304 [ - + ]: 7 : } else if (strcasecmp(key, "hostsvcid") == 0) {
1305 : 0 : continue;
1306 [ + + ]: 7 : } else if (strcasecmp(key, "hostnqn") == 0) {
1307 : 3 : continue;
1308 [ + + ]: 4 : } else if (strcasecmp(key, "ns") == 0) {
1309 : : /*
1310 : : * Special case. The namespace id parameter may
1311 : : * optionally be passed in the transport id string
1312 : : * for an SPDK application (e.g. spdk_nvme_perf)
1313 : : * and additionally parsed therein to limit
1314 : : * targeting a specific namespace. For this
1315 : : * scenario, just silently ignore this key
1316 : : * rather than letting it default to logging
1317 : : * it as an invalid key.
1318 : : */
1319 : 3 : continue;
1320 [ + - ]: 1 : } else if (strcasecmp(key, "alt_traddr") == 0) {
1321 : : /*
1322 : : * Used by applications for enabling transport ID failover.
1323 : : * Please see the case above for more information on custom parameters.
1324 : : */
1325 : 1 : continue;
1326 : : } else {
1327 : 0 : SPDK_ERRLOG("Unknown transport ID key '%s'\n", key);
1328 : : }
1329 : : }
1330 : :
1331 : 305 : return 0;
1332 : : }
1333 : :
1334 : : int
1335 : 12 : spdk_nvme_host_id_parse(struct spdk_nvme_host_id *hostid, const char *str)
1336 : 12 : {
1337 : :
1338 : 12 : size_t key_size = 32;
1339 : 12 : size_t val_size = 1024;
1340 : : size_t val_len;
1341 [ - + ]: 12 : char key[key_size];
1342 [ - + ]: 12 : char val[val_size];
1343 : :
1344 [ + - - + ]: 12 : if (hostid == NULL || str == NULL) {
1345 : 0 : return -EINVAL;
1346 : : }
1347 : :
1348 [ + + ]: 24 : while (*str != '\0') {
1349 : :
1350 : 12 : val_len = parse_next_key(&str, key, val, key_size, val_size);
1351 : :
1352 [ - + ]: 12 : if (val_len == 0) {
1353 : 0 : SPDK_ERRLOG("Failed to parse host ID\n");
1354 : 0 : return val_len;
1355 : : }
1356 : :
1357 : : /* Ignore the rest of the options from the transport ID. */
1358 [ + + + + ]: 12 : if (strcasecmp(key, "trtype") == 0) {
1359 : 4 : continue;
1360 [ - + - + ]: 8 : } else if (strcasecmp(key, "adrfam") == 0) {
1361 : 0 : continue;
1362 [ - + - + ]: 8 : } else if (strcasecmp(key, "traddr") == 0) {
1363 : 0 : continue;
1364 [ - + - + ]: 8 : } else if (strcasecmp(key, "trsvcid") == 0) {
1365 : 0 : continue;
1366 [ - + - + ]: 8 : } else if (strcasecmp(key, "subnqn") == 0) {
1367 : 0 : continue;
1368 [ - + - + ]: 8 : } else if (strcasecmp(key, "priority") == 0) {
1369 : 0 : continue;
1370 [ - + - + ]: 8 : } else if (strcasecmp(key, "ns") == 0) {
1371 : 0 : continue;
1372 [ + + + + ]: 8 : } else if (strcasecmp(key, "hostaddr") == 0) {
1373 [ - + ]: 4 : if (val_len > SPDK_NVMF_TRADDR_MAX_LEN) {
1374 : 0 : SPDK_ERRLOG("hostaddr length %zu greater than maximum allowed %u\n",
1375 : : val_len, SPDK_NVMF_TRADDR_MAX_LEN);
1376 : 0 : return -EINVAL;
1377 : : }
1378 [ - + - + ]: 4 : memcpy(hostid->hostaddr, val, val_len + 1);
1379 : :
1380 [ + + + - ]: 4 : } else if (strcasecmp(key, "hostsvcid") == 0) {
1381 [ - + ]: 4 : if (val_len > SPDK_NVMF_TRSVCID_MAX_LEN) {
1382 : 0 : SPDK_ERRLOG("trsvcid length %zu greater than maximum allowed %u\n",
1383 : : val_len, SPDK_NVMF_TRSVCID_MAX_LEN);
1384 : 0 : return -EINVAL;
1385 : : }
1386 [ - + - + ]: 4 : memcpy(hostid->hostsvcid, val, val_len + 1);
1387 : : } else {
1388 : 0 : SPDK_ERRLOG("Unknown transport ID key '%s'\n", key);
1389 : : }
1390 : : }
1391 : :
1392 : 12 : return 0;
1393 : : }
1394 : :
1395 : : static int
1396 : 26692 : cmp_int(int a, int b)
1397 : : {
1398 : 26692 : return a - b;
1399 : : }
1400 : :
1401 : : int
1402 : 14105 : spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1,
1403 : : const struct spdk_nvme_transport_id *trid2)
1404 : : {
1405 : : int cmp;
1406 : :
1407 [ - + ]: 14105 : if (trid1->trtype == SPDK_NVME_TRANSPORT_CUSTOM) {
1408 [ # # # # ]: 0 : cmp = strcasecmp(trid1->trstring, trid2->trstring);
1409 : : } else {
1410 : 14105 : cmp = cmp_int(trid1->trtype, trid2->trtype);
1411 : : }
1412 : :
1413 [ + + ]: 14105 : if (cmp) {
1414 : 4 : return cmp;
1415 : : }
1416 : :
1417 [ + + ]: 14101 : if (trid1->trtype == SPDK_NVME_TRANSPORT_PCIE) {
1418 : 1217 : struct spdk_pci_addr pci_addr1 = {};
1419 : 1217 : struct spdk_pci_addr pci_addr2 = {};
1420 : :
1421 : : /* Normalize PCI addresses before comparing */
1422 [ + - - + ]: 2434 : if (spdk_pci_addr_parse(&pci_addr1, trid1->traddr) < 0 ||
1423 : 1217 : spdk_pci_addr_parse(&pci_addr2, trid2->traddr) < 0) {
1424 : 0 : return -1;
1425 : : }
1426 : :
1427 : : /* PCIe transport ID only uses trtype and traddr */
1428 : 1217 : return spdk_pci_addr_compare(&pci_addr1, &pci_addr2);
1429 : : }
1430 : :
1431 [ - + - + ]: 12884 : cmp = strcasecmp(trid1->traddr, trid2->traddr);
1432 [ + + ]: 12884 : if (cmp) {
1433 : 297 : return cmp;
1434 : : }
1435 : :
1436 : 12587 : cmp = cmp_int(trid1->adrfam, trid2->adrfam);
1437 [ + + ]: 12587 : if (cmp) {
1438 : 4 : return cmp;
1439 : : }
1440 : :
1441 [ - + - + ]: 12583 : cmp = strcasecmp(trid1->trsvcid, trid2->trsvcid);
1442 [ + + ]: 12583 : if (cmp) {
1443 : 1157 : return cmp;
1444 : : }
1445 : :
1446 [ - + - + ]: 11426 : cmp = strcmp(trid1->subnqn, trid2->subnqn);
1447 [ + + ]: 11426 : if (cmp) {
1448 : 494 : return cmp;
1449 : : }
1450 : :
1451 : 10932 : return 0;
1452 : : }
1453 : :
1454 : : int
1455 : 16 : spdk_nvme_prchk_flags_parse(uint32_t *prchk_flags, const char *str)
1456 : : {
1457 : : size_t val_len;
1458 : 16 : char key[32];
1459 : 16 : char val[1024];
1460 : :
1461 [ + + - + ]: 16 : if (prchk_flags == NULL || str == NULL) {
1462 : 4 : return -EINVAL;
1463 : : }
1464 : :
1465 [ + + ]: 24 : while (*str != '\0') {
1466 : 12 : val_len = parse_next_key(&str, key, val, sizeof(key), sizeof(val));
1467 : :
1468 [ - + ]: 12 : if (val_len == 0) {
1469 : 0 : SPDK_ERRLOG("Failed to parse prchk\n");
1470 : 0 : return -EINVAL;
1471 : : }
1472 : :
1473 [ + - ]: 12 : if (strcasecmp(key, "prchk") == 0) {
1474 [ + + ]: 12 : if (strcasestr(val, "reftag") != NULL) {
1475 : 8 : *prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_REFTAG;
1476 : : }
1477 [ + + ]: 12 : if (strcasestr(val, "guard") != NULL) {
1478 : 8 : *prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_GUARD;
1479 : : }
1480 : : } else {
1481 : 0 : SPDK_ERRLOG("Unknown key '%s'\n", key);
1482 : 0 : return -EINVAL;
1483 : : }
1484 : : }
1485 : :
1486 : 12 : return 0;
1487 : : }
1488 : :
1489 : : const char *
1490 : 12 : spdk_nvme_prchk_flags_str(uint32_t prchk_flags)
1491 : : {
1492 [ + + ]: 12 : if (prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_REFTAG) {
1493 [ + + ]: 8 : if (prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_GUARD) {
1494 : 4 : return "prchk:reftag|guard";
1495 : : } else {
1496 : 4 : return "prchk:reftag";
1497 : : }
1498 : : } else {
1499 [ + - ]: 4 : if (prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_GUARD) {
1500 : 4 : return "prchk:guard";
1501 : : } else {
1502 : 0 : return NULL;
1503 : : }
1504 : : }
1505 : : }
1506 : :
1507 : : struct spdk_nvme_probe_ctx *
1508 : 86487 : spdk_nvme_probe_async(const struct spdk_nvme_transport_id *trid,
1509 : : void *cb_ctx,
1510 : : spdk_nvme_probe_cb probe_cb,
1511 : : spdk_nvme_attach_cb attach_cb,
1512 : : spdk_nvme_remove_cb remove_cb)
1513 : : {
1514 : : int rc;
1515 : : struct spdk_nvme_probe_ctx *probe_ctx;
1516 : :
1517 : 86487 : rc = nvme_driver_init();
1518 [ + + ]: 86487 : if (rc != 0) {
1519 : 4 : return NULL;
1520 : : }
1521 : :
1522 : 86483 : probe_ctx = calloc(1, sizeof(*probe_ctx));
1523 [ - + ]: 86483 : if (!probe_ctx) {
1524 : 0 : return NULL;
1525 : : }
1526 : :
1527 : 86483 : nvme_probe_ctx_init(probe_ctx, trid, NULL, cb_ctx, probe_cb, attach_cb, remove_cb);
1528 : 86483 : rc = nvme_probe_internal(probe_ctx, false);
1529 [ + + ]: 86483 : if (rc != 0) {
1530 : 6 : free(probe_ctx);
1531 : 6 : return NULL;
1532 : : }
1533 : :
1534 : 86477 : return probe_ctx;
1535 : : }
1536 : :
1537 : : int
1538 : 120784867 : spdk_nvme_probe_poll_async(struct spdk_nvme_probe_ctx *probe_ctx)
1539 : : {
1540 : : struct spdk_nvme_ctrlr *ctrlr, *ctrlr_tmp;
1541 : :
1542 [ + + + - ]: 120784867 : if (!spdk_process_is_primary() && probe_ctx->trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
1543 : 178 : free(probe_ctx);
1544 : 178 : return 0;
1545 : : }
1546 : :
1547 [ + + ]: 241484840 : TAILQ_FOREACH_SAFE(ctrlr, &probe_ctx->init_ctrlrs, tailq, ctrlr_tmp) {
1548 : 120700151 : nvme_ctrlr_poll_internal(ctrlr, probe_ctx);
1549 : : }
1550 : :
1551 [ + + ]: 120784689 : if (TAILQ_EMPTY(&probe_ctx->init_ctrlrs)) {
1552 : 88293 : nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
1553 : 88293 : g_spdk_nvme_driver->initialized = true;
1554 : 88293 : nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
1555 : 88293 : free(probe_ctx);
1556 : 88293 : return 0;
1557 : : }
1558 : :
1559 : 120696396 : return -EAGAIN;
1560 : : }
1561 : :
1562 : : struct spdk_nvme_probe_ctx *
1563 : 1996 : spdk_nvme_connect_async(const struct spdk_nvme_transport_id *trid,
1564 : : const struct spdk_nvme_ctrlr_opts *opts,
1565 : : spdk_nvme_attach_cb attach_cb)
1566 : : {
1567 : : int rc;
1568 : 1996 : spdk_nvme_probe_cb probe_cb = NULL;
1569 : : struct spdk_nvme_probe_ctx *probe_ctx;
1570 : :
1571 : 1996 : rc = nvme_driver_init();
1572 [ - + ]: 1996 : if (rc != 0) {
1573 : 0 : return NULL;
1574 : : }
1575 : :
1576 : 1996 : probe_ctx = calloc(1, sizeof(*probe_ctx));
1577 [ - + ]: 1996 : if (!probe_ctx) {
1578 : 0 : return NULL;
1579 : : }
1580 : :
1581 [ + + ]: 1996 : if (opts) {
1582 : 1595 : probe_cb = nvme_connect_probe_cb;
1583 : : }
1584 : :
1585 : 1996 : nvme_probe_ctx_init(probe_ctx, trid, opts, (void *)opts, probe_cb, attach_cb, NULL);
1586 : 1996 : rc = nvme_probe_internal(probe_ctx, true);
1587 [ + + ]: 1996 : if (rc != 0) {
1588 : 13 : free(probe_ctx);
1589 : 13 : return NULL;
1590 : : }
1591 : :
1592 : 1983 : return probe_ctx;
1593 : : }
1594 : :
1595 : : int
1596 : 25488 : nvme_parse_addr(struct sockaddr_storage *sa, int family, const char *addr, const char *service,
1597 : : long int *port)
1598 : : {
1599 : 104 : struct addrinfo *res;
1600 : 104 : struct addrinfo hints;
1601 : : int ret;
1602 : :
1603 [ - + ]: 25488 : memset(&hints, 0, sizeof(hints));
1604 : 25488 : hints.ai_family = family;
1605 : 25488 : hints.ai_socktype = SOCK_STREAM;
1606 : 25488 : hints.ai_protocol = 0;
1607 : :
1608 [ + + - + ]: 25488 : if (addr == NULL || service == NULL) {
1609 : 4 : SPDK_ERRLOG("addr and service must both be non-NULL\n");
1610 : 4 : return -EINVAL;
1611 : : }
1612 : :
1613 : 25484 : *port = spdk_strtol(service, 10);
1614 [ + - - + ]: 25484 : if (*port <= 0 || *port >= 65536) {
1615 : 0 : SPDK_ERRLOG("Invalid port: %s\n", service);
1616 : 0 : return -EINVAL;
1617 : : }
1618 : :
1619 : 25484 : ret = getaddrinfo(addr, service, &hints, &res);
1620 [ - + ]: 25484 : if (ret) {
1621 : 0 : SPDK_ERRLOG("getaddrinfo failed: %s (%d)\n", gai_strerror(ret), ret);
1622 : 0 : return -(abs(ret));
1623 : : }
1624 : :
1625 [ - + ]: 25484 : if (res->ai_addrlen > sizeof(*sa)) {
1626 : 0 : SPDK_ERRLOG("getaddrinfo() ai_addrlen %zu too large\n", (size_t)res->ai_addrlen);
1627 : 0 : ret = -EINVAL;
1628 : : } else {
1629 [ - + - + ]: 25484 : memcpy(sa, res->ai_addr, res->ai_addrlen);
1630 : : }
1631 : :
1632 : 25484 : freeaddrinfo(res);
1633 : 25484 : return ret;
1634 : : }
1635 : :
1636 : : int
1637 : 4554 : nvme_get_default_hostnqn(char *buf, int len)
1638 : : {
1639 : 963 : char uuid[SPDK_UUID_STRING_LEN];
1640 : : int rc;
1641 : :
1642 : 4554 : spdk_uuid_fmt_lower(uuid, sizeof(uuid), &g_spdk_nvme_driver->default_extended_host_id);
1643 [ - + ]: 4554 : rc = snprintf(buf, len, "nqn.2014-08.org.nvmexpress:uuid:%s", uuid);
1644 [ + - - + ]: 4554 : if (rc < 0 || rc >= len) {
1645 : 0 : return -EINVAL;
1646 : : }
1647 : :
1648 : 4554 : return 0;
1649 : : }
1650 : :
1651 : 2705 : SPDK_LOG_REGISTER_COMPONENT(nvme)
|