]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/nvme/nvme.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / lib / nvme / nvme.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include "spdk/nvmf_spec.h"
35 #include "nvme_internal.h"
36
37 #define SPDK_NVME_DRIVER_NAME "spdk_nvme_driver"
38
39 struct nvme_driver *g_spdk_nvme_driver;
40 pid_t g_spdk_nvme_pid;
41
42 int32_t spdk_nvme_retry_count;
43
44 /* gross timeout of 180 seconds in milliseconds */
45 static int g_nvme_driver_timeout_ms = 3 * 60 * 1000;
46
47 /* Per-process attached controller list */
48 static TAILQ_HEAD(, spdk_nvme_ctrlr) g_nvme_attached_ctrlrs =
49 TAILQ_HEAD_INITIALIZER(g_nvme_attached_ctrlrs);
50
51 /* Returns true if ctrlr should be stored on the multi-process shared_attached_ctrlrs list */
52 static bool
53 nvme_ctrlr_shared(const struct spdk_nvme_ctrlr *ctrlr)
54 {
55 return ctrlr->trid.trtype == SPDK_NVME_TRANSPORT_PCIE;
56 }
57
58 void
59 nvme_ctrlr_connected(struct spdk_nvme_probe_ctx *probe_ctx,
60 struct spdk_nvme_ctrlr *ctrlr)
61 {
62 TAILQ_INSERT_TAIL(&probe_ctx->init_ctrlrs, ctrlr, tailq);
63 }
64
65 int
66 spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr)
67 {
68 nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
69
70 nvme_ctrlr_proc_put_ref(ctrlr);
71
72 if (nvme_ctrlr_get_ref_count(ctrlr) == 0) {
73 if (nvme_ctrlr_shared(ctrlr)) {
74 TAILQ_REMOVE(&g_spdk_nvme_driver->shared_attached_ctrlrs, ctrlr, tailq);
75 } else {
76 TAILQ_REMOVE(&g_nvme_attached_ctrlrs, ctrlr, tailq);
77 }
78 nvme_ctrlr_destruct(ctrlr);
79 }
80
81 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
82 return 0;
83 }
84
85 void
86 nvme_completion_poll_cb(void *arg, const struct spdk_nvme_cpl *cpl)
87 {
88 struct nvme_completion_poll_status *status = arg;
89
90 /*
91 * Copy status into the argument passed by the caller, so that
92 * the caller can check the status to determine if the
93 * the request passed or failed.
94 */
95 memcpy(&status->cpl, cpl, sizeof(*cpl));
96 status->done = true;
97 }
98
99 /**
100 * Poll qpair for completions until a command completes.
101 *
102 * \param qpair queue to poll
103 * \param status completion status
104 * \param robust_mutex optional robust mutex to lock while polling qpair
105 *
106 * \return 0 if command completed without error, negative errno on failure
107 *
108 * The command to wait upon must be submitted with nvme_completion_poll_cb as the callback
109 * and status as the callback argument.
110 */
111 int
112 spdk_nvme_wait_for_completion_robust_lock(
113 struct spdk_nvme_qpair *qpair,
114 struct nvme_completion_poll_status *status,
115 pthread_mutex_t *robust_mutex)
116 {
117 memset(&status->cpl, 0, sizeof(status->cpl));
118 status->done = false;
119
120 while (status->done == false) {
121 if (robust_mutex) {
122 nvme_robust_mutex_lock(robust_mutex);
123 }
124
125 spdk_nvme_qpair_process_completions(qpair, 0);
126
127 if (robust_mutex) {
128 nvme_robust_mutex_unlock(robust_mutex);
129 }
130 }
131
132 return spdk_nvme_cpl_is_error(&status->cpl) ? -EIO : 0;
133 }
134
135 int
136 spdk_nvme_wait_for_completion(struct spdk_nvme_qpair *qpair,
137 struct nvme_completion_poll_status *status)
138 {
139 return spdk_nvme_wait_for_completion_robust_lock(qpair, status, NULL);
140 }
141
142 int
143 spdk_nvme_wait_for_completion_timeout(struct spdk_nvme_qpair *qpair,
144 struct nvme_completion_poll_status *status,
145 uint64_t timeout_in_secs)
146 {
147 uint64_t timeout_tsc = 0;
148
149 memset(&status->cpl, 0, sizeof(status->cpl));
150 status->done = false;
151 if (timeout_in_secs) {
152 timeout_tsc = spdk_get_ticks() + timeout_in_secs * spdk_get_ticks_hz();
153 }
154
155 while (status->done == false) {
156 spdk_nvme_qpair_process_completions(qpair, 0);
157 if (timeout_tsc && spdk_get_ticks() > timeout_tsc) {
158 break;
159 }
160 }
161
162 if (status->done == false) {
163 return -EIO;
164 }
165
166 return spdk_nvme_cpl_is_error(&status->cpl) ? -EIO : 0;
167 }
168
169 static void
170 nvme_user_copy_cmd_complete(void *arg, const struct spdk_nvme_cpl *cpl)
171 {
172 struct nvme_request *req = arg;
173 enum spdk_nvme_data_transfer xfer;
174
175 if (req->user_buffer && req->payload_size) {
176 /* Copy back to the user buffer and free the contig buffer */
177 assert(nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_CONTIG);
178 xfer = spdk_nvme_opc_get_data_transfer(req->cmd.opc);
179 if (xfer == SPDK_NVME_DATA_CONTROLLER_TO_HOST ||
180 xfer == SPDK_NVME_DATA_BIDIRECTIONAL) {
181 assert(req->pid == getpid());
182 memcpy(req->user_buffer, req->payload.contig_or_cb_arg, req->payload_size);
183 }
184
185 spdk_dma_free(req->payload.contig_or_cb_arg);
186 }
187
188 /* Call the user's original callback now that the buffer has been copied */
189 req->user_cb_fn(req->user_cb_arg, cpl);
190 }
191
192 /**
193 * Allocate a request as well as a DMA-capable buffer to copy to/from the user's buffer.
194 *
195 * This is intended for use in non-fast-path functions (admin commands, reservations, etc.)
196 * where the overhead of a copy is not a problem.
197 */
198 struct nvme_request *
199 nvme_allocate_request_user_copy(struct spdk_nvme_qpair *qpair,
200 void *buffer, uint32_t payload_size, spdk_nvme_cmd_cb cb_fn,
201 void *cb_arg, bool host_to_controller)
202 {
203 struct nvme_request *req;
204 void *dma_buffer = NULL;
205
206 if (buffer && payload_size) {
207 dma_buffer = spdk_zmalloc(payload_size, 4096, NULL,
208 SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
209 if (!dma_buffer) {
210 return NULL;
211 }
212
213 if (host_to_controller) {
214 memcpy(dma_buffer, buffer, payload_size);
215 }
216 }
217
218 req = nvme_allocate_request_contig(qpair, dma_buffer, payload_size, nvme_user_copy_cmd_complete,
219 NULL);
220 if (!req) {
221 spdk_free(dma_buffer);
222 return NULL;
223 }
224
225 req->user_cb_fn = cb_fn;
226 req->user_cb_arg = cb_arg;
227 req->user_buffer = buffer;
228 req->cb_arg = req;
229
230 return req;
231 }
232
233 /**
234 * Check if a request has exceeded the controller timeout.
235 *
236 * \param req request to check for timeout.
237 * \param cid command ID for command submitted by req (will be passed to timeout_cb_fn)
238 * \param active_proc per-process data for the controller associated with req
239 * \param now_tick current time from spdk_get_ticks()
240 * \return 0 if requests submitted more recently than req should still be checked for timeouts, or
241 * 1 if requests newer than req need not be checked.
242 *
243 * The request's timeout callback will be called if needed; the caller is only responsible for
244 * calling this function on each outstanding request.
245 */
246 int
247 nvme_request_check_timeout(struct nvme_request *req, uint16_t cid,
248 struct spdk_nvme_ctrlr_process *active_proc,
249 uint64_t now_tick)
250 {
251 struct spdk_nvme_qpair *qpair = req->qpair;
252 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
253
254 assert(active_proc->timeout_cb_fn != NULL);
255
256 if (req->timed_out || req->submit_tick == 0) {
257 return 0;
258 }
259
260 if (req->pid != g_spdk_nvme_pid) {
261 return 0;
262 }
263
264 if (nvme_qpair_is_admin_queue(qpair) &&
265 req->cmd.opc == SPDK_NVME_OPC_ASYNC_EVENT_REQUEST) {
266 return 0;
267 }
268
269 if (req->submit_tick + active_proc->timeout_ticks > now_tick) {
270 return 1;
271 }
272
273 req->timed_out = true;
274
275 /*
276 * We don't want to expose the admin queue to the user,
277 * so when we're timing out admin commands set the
278 * qpair to NULL.
279 */
280 active_proc->timeout_cb_fn(active_proc->timeout_cb_arg, ctrlr,
281 nvme_qpair_is_admin_queue(qpair) ? NULL : qpair,
282 cid);
283 return 0;
284 }
285
286 int
287 nvme_robust_mutex_init_shared(pthread_mutex_t *mtx)
288 {
289 int rc = 0;
290
291 #ifdef __FreeBSD__
292 pthread_mutex_init(mtx, NULL);
293 #else
294 pthread_mutexattr_t attr;
295
296 if (pthread_mutexattr_init(&attr)) {
297 return -1;
298 }
299 if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) ||
300 pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST) ||
301 pthread_mutex_init(mtx, &attr)) {
302 rc = -1;
303 }
304 pthread_mutexattr_destroy(&attr);
305 #endif
306
307 return rc;
308 }
309
310 int
311 nvme_driver_init(void)
312 {
313 int ret = 0;
314 /* Any socket ID */
315 int socket_id = -1;
316
317 /* Each process needs its own pid. */
318 g_spdk_nvme_pid = getpid();
319
320 /*
321 * Only one thread from one process will do this driver init work.
322 * The primary process will reserve the shared memory and do the
323 * initialization.
324 * The secondary process will lookup the existing reserved memory.
325 */
326 if (spdk_process_is_primary()) {
327 /* The unique named memzone already reserved. */
328 if (g_spdk_nvme_driver != NULL) {
329 return 0;
330 } else {
331 g_spdk_nvme_driver = spdk_memzone_reserve(SPDK_NVME_DRIVER_NAME,
332 sizeof(struct nvme_driver), socket_id,
333 SPDK_MEMZONE_NO_IOVA_CONTIG);
334 }
335
336 if (g_spdk_nvme_driver == NULL) {
337 SPDK_ERRLOG("primary process failed to reserve memory\n");
338
339 return -1;
340 }
341 } else {
342 g_spdk_nvme_driver = spdk_memzone_lookup(SPDK_NVME_DRIVER_NAME);
343
344 /* The unique named memzone already reserved by the primary process. */
345 if (g_spdk_nvme_driver != NULL) {
346 int ms_waited = 0;
347
348 /* Wait the nvme driver to get initialized. */
349 while ((g_spdk_nvme_driver->initialized == false) &&
350 (ms_waited < g_nvme_driver_timeout_ms)) {
351 ms_waited++;
352 nvme_delay(1000); /* delay 1ms */
353 }
354 if (g_spdk_nvme_driver->initialized == false) {
355 SPDK_ERRLOG("timeout waiting for primary process to init\n");
356
357 return -1;
358 }
359 } else {
360 SPDK_ERRLOG("primary process is not started yet\n");
361
362 return -1;
363 }
364
365 return 0;
366 }
367
368 /*
369 * At this moment, only one thread from the primary process will do
370 * the g_spdk_nvme_driver initialization
371 */
372 assert(spdk_process_is_primary());
373
374 ret = nvme_robust_mutex_init_shared(&g_spdk_nvme_driver->lock);
375 if (ret != 0) {
376 SPDK_ERRLOG("failed to initialize mutex\n");
377 spdk_memzone_free(SPDK_NVME_DRIVER_NAME);
378 return ret;
379 }
380
381 nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
382
383 g_spdk_nvme_driver->initialized = false;
384
385 TAILQ_INIT(&g_spdk_nvme_driver->shared_attached_ctrlrs);
386
387 spdk_uuid_generate(&g_spdk_nvme_driver->default_extended_host_id);
388
389 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
390
391 return ret;
392 }
393
394 /* This function must only be called while holding g_spdk_nvme_driver->lock */
395 int
396 nvme_ctrlr_probe(const struct spdk_nvme_transport_id *trid,
397 struct spdk_nvme_probe_ctx *probe_ctx, void *devhandle)
398 {
399 struct spdk_nvme_ctrlr *ctrlr;
400 struct spdk_nvme_ctrlr_opts opts;
401
402 assert(trid != NULL);
403
404 spdk_nvme_ctrlr_get_default_ctrlr_opts(&opts, sizeof(opts));
405
406 if (!probe_ctx->probe_cb || probe_ctx->probe_cb(probe_ctx->cb_ctx, trid, &opts)) {
407 ctrlr = spdk_nvme_get_ctrlr_by_trid_unsafe(trid);
408 if (ctrlr) {
409 /* This ctrlr already exists.
410 * Increase the ref count before calling attach_cb() as the user may
411 * call nvme_detach() immediately. */
412 nvme_ctrlr_proc_get_ref(ctrlr);
413
414 if (probe_ctx->attach_cb) {
415 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
416 probe_ctx->attach_cb(probe_ctx->cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts);
417 nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
418 }
419 return 0;
420 }
421
422 ctrlr = nvme_transport_ctrlr_construct(trid, &opts, devhandle);
423 if (ctrlr == NULL) {
424 SPDK_ERRLOG("Failed to construct NVMe controller for SSD: %s\n", trid->traddr);
425 return -1;
426 }
427
428 TAILQ_INSERT_TAIL(&probe_ctx->init_ctrlrs, ctrlr, tailq);
429 return 0;
430 }
431
432 return 1;
433 }
434
435 static int
436 nvme_ctrlr_poll_internal(struct spdk_nvme_ctrlr *ctrlr,
437 struct spdk_nvme_probe_ctx *probe_ctx)
438 {
439 int rc = 0;
440
441 rc = nvme_ctrlr_process_init(ctrlr);
442
443 if (rc) {
444 /* Controller failed to initialize. */
445 TAILQ_REMOVE(&probe_ctx->init_ctrlrs, ctrlr, tailq);
446 SPDK_ERRLOG("Failed to initialize SSD: %s\n", ctrlr->trid.traddr);
447 nvme_ctrlr_destruct(ctrlr);
448 return rc;
449 }
450
451 if (ctrlr->state != NVME_CTRLR_STATE_READY) {
452 return 0;
453 }
454
455 /*
456 * Controller has been initialized.
457 * Move it to the attached_ctrlrs list.
458 */
459 TAILQ_REMOVE(&probe_ctx->init_ctrlrs, ctrlr, tailq);
460
461 nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
462 if (nvme_ctrlr_shared(ctrlr)) {
463 TAILQ_INSERT_TAIL(&g_spdk_nvme_driver->shared_attached_ctrlrs, ctrlr, tailq);
464 } else {
465 TAILQ_INSERT_TAIL(&g_nvme_attached_ctrlrs, ctrlr, tailq);
466 }
467
468 /*
469 * Increase the ref count before calling attach_cb() as the user may
470 * call nvme_detach() immediately.
471 */
472 nvme_ctrlr_proc_get_ref(ctrlr);
473 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
474
475 if (probe_ctx->attach_cb) {
476 probe_ctx->attach_cb(probe_ctx->cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts);
477 return 0;
478 }
479
480 return 0;
481 }
482
483 static int
484 nvme_init_controllers(struct spdk_nvme_probe_ctx *probe_ctx)
485 {
486 int rc = 0;
487
488 while (true) {
489 rc = spdk_nvme_probe_poll_async(probe_ctx);
490 if (rc != -EAGAIN) {
491 return rc;
492 }
493 }
494
495 return rc;
496 }
497
498 /* This function must not be called while holding g_spdk_nvme_driver->lock */
499 static struct spdk_nvme_ctrlr *
500 spdk_nvme_get_ctrlr_by_trid(const struct spdk_nvme_transport_id *trid)
501 {
502 struct spdk_nvme_ctrlr *ctrlr;
503
504 nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
505 ctrlr = spdk_nvme_get_ctrlr_by_trid_unsafe(trid);
506 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
507
508 return ctrlr;
509 }
510
511 /* This function must be called while holding g_spdk_nvme_driver->lock */
512 struct spdk_nvme_ctrlr *
513 spdk_nvme_get_ctrlr_by_trid_unsafe(const struct spdk_nvme_transport_id *trid)
514 {
515 struct spdk_nvme_ctrlr *ctrlr;
516
517 /* Search per-process list */
518 TAILQ_FOREACH(ctrlr, &g_nvme_attached_ctrlrs, tailq) {
519 if (spdk_nvme_transport_id_compare(&ctrlr->trid, trid) == 0) {
520 return ctrlr;
521 }
522 }
523
524 /* Search multi-process shared list */
525 TAILQ_FOREACH(ctrlr, &g_spdk_nvme_driver->shared_attached_ctrlrs, tailq) {
526 if (spdk_nvme_transport_id_compare(&ctrlr->trid, trid) == 0) {
527 return ctrlr;
528 }
529 }
530
531 return NULL;
532 }
533
534 /* This function must only be called while holding g_spdk_nvme_driver->lock */
535 static int
536 spdk_nvme_probe_internal(struct spdk_nvme_probe_ctx *probe_ctx,
537 bool direct_connect)
538 {
539 int rc;
540 struct spdk_nvme_ctrlr *ctrlr;
541
542 if (!spdk_nvme_transport_available(probe_ctx->trid.trtype)) {
543 SPDK_ERRLOG("NVMe trtype %u not available\n", probe_ctx->trid.trtype);
544 return -1;
545 }
546
547 nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
548
549 rc = nvme_transport_ctrlr_scan(probe_ctx, direct_connect);
550 if (rc != 0) {
551 SPDK_ERRLOG("NVMe ctrlr scan failed\n");
552 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
553 return -1;
554 }
555
556 /*
557 * Probe controllers on the shared_attached_ctrlrs list
558 */
559 if (!spdk_process_is_primary() && (probe_ctx->trid.trtype == SPDK_NVME_TRANSPORT_PCIE)) {
560 TAILQ_FOREACH(ctrlr, &g_spdk_nvme_driver->shared_attached_ctrlrs, tailq) {
561 /* Do not attach other ctrlrs if user specify a valid trid */
562 if ((strlen(probe_ctx->trid.traddr) != 0) &&
563 (spdk_nvme_transport_id_compare(&probe_ctx->trid, &ctrlr->trid))) {
564 continue;
565 }
566
567 /* Do not attach if we failed to initialize it in this process */
568 if (spdk_nvme_ctrlr_get_current_process(ctrlr) == NULL) {
569 continue;
570 }
571
572 nvme_ctrlr_proc_get_ref(ctrlr);
573
574 /*
575 * Unlock while calling attach_cb() so the user can call other functions
576 * that may take the driver lock, like nvme_detach().
577 */
578 if (probe_ctx->attach_cb) {
579 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
580 probe_ctx->attach_cb(probe_ctx->cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts);
581 nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
582 }
583 }
584 }
585
586 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
587
588 return 0;
589 }
590
591 static void
592 spdk_nvme_probe_ctx_init(struct spdk_nvme_probe_ctx *probe_ctx,
593 const struct spdk_nvme_transport_id *trid,
594 void *cb_ctx,
595 spdk_nvme_probe_cb probe_cb,
596 spdk_nvme_attach_cb attach_cb,
597 spdk_nvme_remove_cb remove_cb)
598 {
599 probe_ctx->trid = *trid;
600 probe_ctx->cb_ctx = cb_ctx;
601 probe_ctx->probe_cb = probe_cb;
602 probe_ctx->attach_cb = attach_cb;
603 probe_ctx->remove_cb = remove_cb;
604 TAILQ_INIT(&probe_ctx->init_ctrlrs);
605 }
606
607 int
608 spdk_nvme_probe(const struct spdk_nvme_transport_id *trid, void *cb_ctx,
609 spdk_nvme_probe_cb probe_cb, spdk_nvme_attach_cb attach_cb,
610 spdk_nvme_remove_cb remove_cb)
611 {
612 struct spdk_nvme_transport_id trid_pcie;
613 struct spdk_nvme_probe_ctx *probe_ctx;
614
615 if (trid == NULL) {
616 memset(&trid_pcie, 0, sizeof(trid_pcie));
617 trid_pcie.trtype = SPDK_NVME_TRANSPORT_PCIE;
618 trid = &trid_pcie;
619 }
620
621 probe_ctx = spdk_nvme_probe_async(trid, cb_ctx, probe_cb,
622 attach_cb, remove_cb);
623 if (!probe_ctx) {
624 SPDK_ERRLOG("Create probe context failed\n");
625 return -1;
626 }
627
628 /*
629 * Keep going even if one or more nvme_attach() calls failed,
630 * but maintain the value of rc to signal errors when we return.
631 */
632 return nvme_init_controllers(probe_ctx);
633 }
634
635 static bool
636 spdk_nvme_connect_probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
637 struct spdk_nvme_ctrlr_opts *opts)
638 {
639 struct spdk_nvme_ctrlr_opts *requested_opts = cb_ctx;
640
641 assert(requested_opts);
642 memcpy(opts, requested_opts, sizeof(*opts));
643
644 return true;
645 }
646
647 struct spdk_nvme_ctrlr *
648 spdk_nvme_connect(const struct spdk_nvme_transport_id *trid,
649 const struct spdk_nvme_ctrlr_opts *opts, size_t opts_size)
650 {
651 int rc;
652 struct spdk_nvme_ctrlr *ctrlr = NULL;
653 struct spdk_nvme_probe_ctx *probe_ctx;
654
655 if (trid == NULL) {
656 SPDK_ERRLOG("No transport ID specified\n");
657 return NULL;
658 }
659
660 if (opts && (opts_size != sizeof(*opts))) {
661 SPDK_ERRLOG("Invalid opts size\n");
662 return NULL;
663 }
664
665 probe_ctx = spdk_nvme_connect_async(trid, opts, NULL);
666 if (!probe_ctx) {
667 SPDK_ERRLOG("Create probe context failed\n");
668 return NULL;
669 }
670
671 rc = nvme_init_controllers(probe_ctx);
672 if (rc != 0) {
673 return NULL;
674 }
675
676 ctrlr = spdk_nvme_get_ctrlr_by_trid(trid);
677
678 return ctrlr;
679 }
680
681 int
682 spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str)
683 {
684 if (trtype == NULL || str == NULL) {
685 return -EINVAL;
686 }
687
688 if (strcasecmp(str, "PCIe") == 0) {
689 *trtype = SPDK_NVME_TRANSPORT_PCIE;
690 } else if (strcasecmp(str, "RDMA") == 0) {
691 *trtype = SPDK_NVME_TRANSPORT_RDMA;
692 } else if (strcasecmp(str, "FC") == 0) {
693 *trtype = SPDK_NVME_TRANSPORT_FC;
694 } else if (strcasecmp(str, "TCP") == 0) {
695 *trtype = SPDK_NVME_TRANSPORT_TCP;
696 } else {
697 return -ENOENT;
698 }
699 return 0;
700 }
701
702 const char *
703 spdk_nvme_transport_id_trtype_str(enum spdk_nvme_transport_type trtype)
704 {
705 switch (trtype) {
706 case SPDK_NVME_TRANSPORT_PCIE:
707 return "PCIe";
708 case SPDK_NVME_TRANSPORT_RDMA:
709 return "RDMA";
710 case SPDK_NVME_TRANSPORT_FC:
711 return "FC";
712 case SPDK_NVME_TRANSPORT_TCP:
713 return "TCP";
714 default:
715 return NULL;
716 }
717 }
718
719 int
720 spdk_nvme_transport_id_parse_adrfam(enum spdk_nvmf_adrfam *adrfam, const char *str)
721 {
722 if (adrfam == NULL || str == NULL) {
723 return -EINVAL;
724 }
725
726 if (strcasecmp(str, "IPv4") == 0) {
727 *adrfam = SPDK_NVMF_ADRFAM_IPV4;
728 } else if (strcasecmp(str, "IPv6") == 0) {
729 *adrfam = SPDK_NVMF_ADRFAM_IPV6;
730 } else if (strcasecmp(str, "IB") == 0) {
731 *adrfam = SPDK_NVMF_ADRFAM_IB;
732 } else if (strcasecmp(str, "FC") == 0) {
733 *adrfam = SPDK_NVMF_ADRFAM_FC;
734 } else {
735 return -ENOENT;
736 }
737 return 0;
738 }
739
740 const char *
741 spdk_nvme_transport_id_adrfam_str(enum spdk_nvmf_adrfam adrfam)
742 {
743 switch (adrfam) {
744 case SPDK_NVMF_ADRFAM_IPV4:
745 return "IPv4";
746 case SPDK_NVMF_ADRFAM_IPV6:
747 return "IPv6";
748 case SPDK_NVMF_ADRFAM_IB:
749 return "IB";
750 case SPDK_NVMF_ADRFAM_FC:
751 return "FC";
752 default:
753 return NULL;
754 }
755 }
756
757 static size_t
758 parse_next_key(const char **str, char *key, char *val, size_t key_buf_size, size_t val_buf_size)
759 {
760
761 const char *sep, *sep1;
762 const char *whitespace = " \t\n";
763 size_t key_len, val_len;
764
765 *str += strspn(*str, whitespace);
766
767 sep = strchr(*str, ':');
768 if (!sep) {
769 sep = strchr(*str, '=');
770 if (!sep) {
771 SPDK_ERRLOG("Key without ':' or '=' separator\n");
772 return 0;
773 }
774 } else {
775 sep1 = strchr(*str, '=');
776 if ((sep1 != NULL) && (sep1 < sep)) {
777 sep = sep1;
778 }
779 }
780
781 key_len = sep - *str;
782 if (key_len >= key_buf_size) {
783 SPDK_ERRLOG("Key length %zu greater than maximum allowed %zu\n",
784 key_len, key_buf_size - 1);
785 return 0;
786 }
787
788 memcpy(key, *str, key_len);
789 key[key_len] = '\0';
790
791 *str += key_len + 1; /* Skip key: */
792 val_len = strcspn(*str, whitespace);
793 if (val_len == 0) {
794 SPDK_ERRLOG("Key without value\n");
795 return 0;
796 }
797
798 if (val_len >= val_buf_size) {
799 SPDK_ERRLOG("Value length %zu greater than maximum allowed %zu\n",
800 val_len, val_buf_size - 1);
801 return 0;
802 }
803
804 memcpy(val, *str, val_len);
805 val[val_len] = '\0';
806
807 *str += val_len;
808
809 return val_len;
810 }
811
812 int
813 spdk_nvme_transport_id_parse(struct spdk_nvme_transport_id *trid, const char *str)
814 {
815 size_t val_len;
816 char key[32];
817 char val[1024];
818
819 if (trid == NULL || str == NULL) {
820 return -EINVAL;
821 }
822
823 while (*str != '\0') {
824
825 val_len = parse_next_key(&str, key, val, sizeof(key), sizeof(val));
826
827 if (val_len == 0) {
828 SPDK_ERRLOG("Failed to parse transport ID\n");
829 return -EINVAL;
830 }
831
832 if (strcasecmp(key, "trtype") == 0) {
833 if (spdk_nvme_transport_id_parse_trtype(&trid->trtype, val) != 0) {
834 SPDK_ERRLOG("Unknown trtype '%s'\n", val);
835 return -EINVAL;
836 }
837 } else if (strcasecmp(key, "adrfam") == 0) {
838 if (spdk_nvme_transport_id_parse_adrfam(&trid->adrfam, val) != 0) {
839 SPDK_ERRLOG("Unknown adrfam '%s'\n", val);
840 return -EINVAL;
841 }
842 } else if (strcasecmp(key, "traddr") == 0) {
843 if (val_len > SPDK_NVMF_TRADDR_MAX_LEN) {
844 SPDK_ERRLOG("traddr length %zu greater than maximum allowed %u\n",
845 val_len, SPDK_NVMF_TRADDR_MAX_LEN);
846 return -EINVAL;
847 }
848 memcpy(trid->traddr, val, val_len + 1);
849 } else if (strcasecmp(key, "trsvcid") == 0) {
850 if (val_len > SPDK_NVMF_TRSVCID_MAX_LEN) {
851 SPDK_ERRLOG("trsvcid length %zu greater than maximum allowed %u\n",
852 val_len, SPDK_NVMF_TRSVCID_MAX_LEN);
853 return -EINVAL;
854 }
855 memcpy(trid->trsvcid, val, val_len + 1);
856 } else if (strcasecmp(key, "subnqn") == 0) {
857 if (val_len > SPDK_NVMF_NQN_MAX_LEN) {
858 SPDK_ERRLOG("subnqn length %zu greater than maximum allowed %u\n",
859 val_len, SPDK_NVMF_NQN_MAX_LEN);
860 return -EINVAL;
861 }
862 memcpy(trid->subnqn, val, val_len + 1);
863 } else if (strcasecmp(key, "hostaddr") == 0) {
864 continue;
865 } else if (strcasecmp(key, "hostsvcid") == 0) {
866 continue;
867 } else if (strcasecmp(key, "ns") == 0) {
868 /*
869 * Special case. The namespace id parameter may
870 * optionally be passed in the transport id string
871 * for an SPDK application (e.g. nvme/perf)
872 * and additionally parsed therein to limit
873 * targeting a specific namespace. For this
874 * scenario, just silently ignore this key
875 * rather than letting it default to logging
876 * it as an invalid key.
877 */
878 continue;
879 } else {
880 SPDK_ERRLOG("Unknown transport ID key '%s'\n", key);
881 }
882 }
883
884 return 0;
885 }
886
887 int
888 spdk_nvme_host_id_parse(struct spdk_nvme_host_id *hostid, const char *str)
889 {
890
891 size_t key_size = 32;
892 size_t val_size = 1024;
893 size_t val_len;
894 char key[key_size];
895 char val[val_size];
896
897 if (hostid == NULL || str == NULL) {
898 return -EINVAL;
899 }
900
901 while (*str != '\0') {
902
903 val_len = parse_next_key(&str, key, val, key_size, val_size);
904
905 if (val_len == 0) {
906 SPDK_ERRLOG("Failed to parse host ID\n");
907 return val_len;
908 }
909
910 /* Ignore the rest of the options from the transport ID. */
911 if (strcasecmp(key, "trtype") == 0) {
912 continue;
913 } else if (strcasecmp(key, "adrfam") == 0) {
914 continue;
915 } else if (strcasecmp(key, "traddr") == 0) {
916 continue;
917 } else if (strcasecmp(key, "trsvcid") == 0) {
918 continue;
919 } else if (strcasecmp(key, "subnqn") == 0) {
920 continue;
921 } else if (strcasecmp(key, "ns") == 0) {
922 continue;
923 } else if (strcasecmp(key, "hostaddr") == 0) {
924 if (val_len > SPDK_NVMF_TRADDR_MAX_LEN) {
925 SPDK_ERRLOG("hostaddr length %zu greater than maximum allowed %u\n",
926 val_len, SPDK_NVMF_TRADDR_MAX_LEN);
927 return -EINVAL;
928 }
929 memcpy(hostid->hostaddr, val, val_len + 1);
930
931 } else if (strcasecmp(key, "hostsvcid") == 0) {
932 if (val_len > SPDK_NVMF_TRSVCID_MAX_LEN) {
933 SPDK_ERRLOG("trsvcid length %zu greater than maximum allowed %u\n",
934 val_len, SPDK_NVMF_TRSVCID_MAX_LEN);
935 return -EINVAL;
936 }
937 memcpy(hostid->hostsvcid, val, val_len + 1);
938 } else {
939 SPDK_ERRLOG("Unknown transport ID key '%s'\n", key);
940 }
941 }
942
943 return 0;
944 }
945
946 static int
947 cmp_int(int a, int b)
948 {
949 return a - b;
950 }
951
952 int
953 spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1,
954 const struct spdk_nvme_transport_id *trid2)
955 {
956 int cmp;
957
958 cmp = cmp_int(trid1->trtype, trid2->trtype);
959 if (cmp) {
960 return cmp;
961 }
962
963 if (trid1->trtype == SPDK_NVME_TRANSPORT_PCIE) {
964 struct spdk_pci_addr pci_addr1;
965 struct spdk_pci_addr pci_addr2;
966
967 /* Normalize PCI addresses before comparing */
968 if (spdk_pci_addr_parse(&pci_addr1, trid1->traddr) < 0 ||
969 spdk_pci_addr_parse(&pci_addr2, trid2->traddr) < 0) {
970 return -1;
971 }
972
973 /* PCIe transport ID only uses trtype and traddr */
974 return spdk_pci_addr_compare(&pci_addr1, &pci_addr2);
975 }
976
977 cmp = strcasecmp(trid1->traddr, trid2->traddr);
978 if (cmp) {
979 return cmp;
980 }
981
982 cmp = cmp_int(trid1->adrfam, trid2->adrfam);
983 if (cmp) {
984 return cmp;
985 }
986
987 cmp = strcasecmp(trid1->trsvcid, trid2->trsvcid);
988 if (cmp) {
989 return cmp;
990 }
991
992 cmp = strcmp(trid1->subnqn, trid2->subnqn);
993 if (cmp) {
994 return cmp;
995 }
996
997 return 0;
998 }
999
1000 int
1001 spdk_nvme_prchk_flags_parse(uint32_t *prchk_flags, const char *str)
1002 {
1003 size_t val_len;
1004 char key[32];
1005 char val[1024];
1006
1007 if (prchk_flags == NULL || str == NULL) {
1008 return -EINVAL;
1009 }
1010
1011 while (*str != '\0') {
1012 val_len = parse_next_key(&str, key, val, sizeof(key), sizeof(val));
1013
1014 if (val_len == 0) {
1015 SPDK_ERRLOG("Failed to parse prchk\n");
1016 return -EINVAL;
1017 }
1018
1019 if (strcasecmp(key, "prchk") == 0) {
1020 if (strcasestr(val, "reftag") != NULL) {
1021 *prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_REFTAG;
1022 }
1023 if (strcasestr(val, "guard") != NULL) {
1024 *prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_GUARD;
1025 }
1026 } else {
1027 SPDK_ERRLOG("Unknown key '%s'\n", key);
1028 return -EINVAL;
1029 }
1030 }
1031
1032 return 0;
1033 }
1034
1035 const char *
1036 spdk_nvme_prchk_flags_str(uint32_t prchk_flags)
1037 {
1038 if (prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_REFTAG) {
1039 if (prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_GUARD) {
1040 return "prchk:reftag|guard";
1041 } else {
1042 return "prchk:reftag";
1043 }
1044 } else {
1045 if (prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_GUARD) {
1046 return "prchk:guard";
1047 } else {
1048 return NULL;
1049 }
1050 }
1051 }
1052
1053 struct spdk_nvme_probe_ctx *
1054 spdk_nvme_probe_async(const struct spdk_nvme_transport_id *trid,
1055 void *cb_ctx,
1056 spdk_nvme_probe_cb probe_cb,
1057 spdk_nvme_attach_cb attach_cb,
1058 spdk_nvme_remove_cb remove_cb)
1059 {
1060 int rc;
1061 struct spdk_nvme_probe_ctx *probe_ctx;
1062
1063 rc = nvme_driver_init();
1064 if (rc != 0) {
1065 return NULL;
1066 }
1067
1068 probe_ctx = calloc(1, sizeof(*probe_ctx));
1069 if (!probe_ctx) {
1070 return NULL;
1071 }
1072
1073 spdk_nvme_probe_ctx_init(probe_ctx, trid, cb_ctx, probe_cb, attach_cb, remove_cb);
1074 rc = spdk_nvme_probe_internal(probe_ctx, false);
1075 if (rc != 0) {
1076 free(probe_ctx);
1077 return NULL;
1078 }
1079
1080 return probe_ctx;
1081 }
1082
1083 int
1084 spdk_nvme_probe_poll_async(struct spdk_nvme_probe_ctx *probe_ctx)
1085 {
1086 int rc = 0;
1087 struct spdk_nvme_ctrlr *ctrlr, *ctrlr_tmp;
1088
1089 if (!spdk_process_is_primary() && probe_ctx->trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
1090 free(probe_ctx);
1091 return 0;
1092 }
1093
1094 TAILQ_FOREACH_SAFE(ctrlr, &probe_ctx->init_ctrlrs, tailq, ctrlr_tmp) {
1095 rc = nvme_ctrlr_poll_internal(ctrlr, probe_ctx);
1096 if (rc != 0) {
1097 rc = -EIO;
1098 break;
1099 }
1100 }
1101
1102 if (rc != 0 || TAILQ_EMPTY(&probe_ctx->init_ctrlrs)) {
1103 nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
1104 g_spdk_nvme_driver->initialized = true;
1105 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
1106 free(probe_ctx);
1107 return rc;
1108 }
1109
1110 return -EAGAIN;
1111 }
1112
1113 struct spdk_nvme_probe_ctx *
1114 spdk_nvme_connect_async(const struct spdk_nvme_transport_id *trid,
1115 const struct spdk_nvme_ctrlr_opts *opts,
1116 spdk_nvme_attach_cb attach_cb)
1117 {
1118 int rc;
1119 spdk_nvme_probe_cb probe_cb = NULL;
1120 struct spdk_nvme_probe_ctx *probe_ctx;
1121
1122 rc = nvme_driver_init();
1123 if (rc != 0) {
1124 return NULL;
1125 }
1126
1127 probe_ctx = calloc(1, sizeof(*probe_ctx));
1128 if (!probe_ctx) {
1129 return NULL;
1130 }
1131
1132 if (opts) {
1133 probe_cb = spdk_nvme_connect_probe_cb;
1134 }
1135
1136 spdk_nvme_probe_ctx_init(probe_ctx, trid, (void *)opts, probe_cb, attach_cb, NULL);
1137 rc = spdk_nvme_probe_internal(probe_ctx, true);
1138 if (rc != 0) {
1139 free(probe_ctx);
1140 return NULL;
1141 }
1142
1143 return probe_ctx;
1144 }
1145
1146 SPDK_LOG_REGISTER_COMPONENT("nvme", SPDK_LOG_NVME)