4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 #include "spdk/nvmf_spec.h"
35 #include "nvme_internal.h"
37 #define SPDK_NVME_DRIVER_NAME "spdk_nvme_driver"
39 struct nvme_driver
*g_spdk_nvme_driver
;
40 pid_t g_spdk_nvme_pid
;
42 int32_t spdk_nvme_retry_count
;
44 /* gross timeout of 180 seconds in milliseconds */
45 static int g_nvme_driver_timeout_ms
= 3 * 60 * 1000;
47 static TAILQ_HEAD(, spdk_nvme_ctrlr
) g_nvme_init_ctrlrs
=
48 TAILQ_HEAD_INITIALIZER(g_nvme_init_ctrlrs
);
50 /* Per-process attached controller list */
51 static TAILQ_HEAD(, spdk_nvme_ctrlr
) g_nvme_attached_ctrlrs
=
52 TAILQ_HEAD_INITIALIZER(g_nvme_attached_ctrlrs
);
54 /* Returns true if ctrlr should be stored on the multi-process shared_attached_ctrlrs list */
56 nvme_ctrlr_shared(const struct spdk_nvme_ctrlr
*ctrlr
)
58 return ctrlr
->trid
.trtype
== SPDK_NVME_TRANSPORT_PCIE
;
61 /* Caller must hold g_spdk_nvme_driver->lock */
63 nvme_ctrlr_connected(struct spdk_nvme_ctrlr
*ctrlr
)
65 TAILQ_INSERT_TAIL(&g_nvme_init_ctrlrs
, ctrlr
, tailq
);
69 spdk_nvme_detach(struct spdk_nvme_ctrlr
*ctrlr
)
71 nvme_robust_mutex_lock(&g_spdk_nvme_driver
->lock
);
73 nvme_ctrlr_proc_put_ref(ctrlr
);
75 if (nvme_ctrlr_get_ref_count(ctrlr
) == 0) {
76 if (nvme_ctrlr_shared(ctrlr
)) {
77 TAILQ_REMOVE(&g_spdk_nvme_driver
->shared_attached_ctrlrs
, ctrlr
, tailq
);
79 TAILQ_REMOVE(&g_nvme_attached_ctrlrs
, ctrlr
, tailq
);
81 nvme_ctrlr_destruct(ctrlr
);
84 nvme_robust_mutex_unlock(&g_spdk_nvme_driver
->lock
);
89 nvme_completion_poll_cb(void *arg
, const struct spdk_nvme_cpl
*cpl
)
91 struct nvme_completion_poll_status
*status
= arg
;
94 * Copy status into the argument passed by the caller, so that
95 * the caller can check the status to determine if the
96 * the request passed or failed.
98 memcpy(&status
->cpl
, cpl
, sizeof(*cpl
));
103 * Poll qpair for completions until a command completes.
105 * \param qpair queue to poll
106 * \param status completion status
107 * \param robust_mutex optional robust mutex to lock while polling qpair
109 * \return 0 if command completed without error, negative errno on failure
111 * The command to wait upon must be submitted with nvme_completion_poll_cb as the callback
112 * and status as the callback argument.
115 spdk_nvme_wait_for_completion_robust_lock(
116 struct spdk_nvme_qpair
*qpair
,
117 struct nvme_completion_poll_status
*status
,
118 pthread_mutex_t
*robust_mutex
)
120 memset(&status
->cpl
, 0, sizeof(status
->cpl
));
121 status
->done
= false;
123 while (status
->done
== false) {
125 nvme_robust_mutex_lock(robust_mutex
);
128 spdk_nvme_qpair_process_completions(qpair
, 0);
131 nvme_robust_mutex_unlock(robust_mutex
);
135 return spdk_nvme_cpl_is_error(&status
->cpl
) ? -EIO
: 0;
139 spdk_nvme_wait_for_completion(struct spdk_nvme_qpair
*qpair
,
140 struct nvme_completion_poll_status
*status
)
142 return spdk_nvme_wait_for_completion_robust_lock(qpair
, status
, NULL
);
146 nvme_user_copy_cmd_complete(void *arg
, const struct spdk_nvme_cpl
*cpl
)
148 struct nvme_request
*req
= arg
;
149 enum spdk_nvme_data_transfer xfer
;
151 if (req
->user_buffer
&& req
->payload_size
) {
152 /* Copy back to the user buffer and free the contig buffer */
153 assert(nvme_payload_type(&req
->payload
) == NVME_PAYLOAD_TYPE_CONTIG
);
154 xfer
= spdk_nvme_opc_get_data_transfer(req
->cmd
.opc
);
155 if (xfer
== SPDK_NVME_DATA_CONTROLLER_TO_HOST
||
156 xfer
== SPDK_NVME_DATA_BIDIRECTIONAL
) {
157 assert(req
->pid
== getpid());
158 memcpy(req
->user_buffer
, req
->payload
.contig_or_cb_arg
, req
->payload_size
);
161 spdk_dma_free(req
->payload
.contig_or_cb_arg
);
164 /* Call the user's original callback now that the buffer has been copied */
165 req
->user_cb_fn(req
->user_cb_arg
, cpl
);
169 * Allocate a request as well as a DMA-capable buffer to copy to/from the user's buffer.
171 * This is intended for use in non-fast-path functions (admin commands, reservations, etc.)
172 * where the overhead of a copy is not a problem.
174 struct nvme_request
*
175 nvme_allocate_request_user_copy(struct spdk_nvme_qpair
*qpair
,
176 void *buffer
, uint32_t payload_size
, spdk_nvme_cmd_cb cb_fn
,
177 void *cb_arg
, bool host_to_controller
)
179 struct nvme_request
*req
;
180 void *dma_buffer
= NULL
;
183 if (buffer
&& payload_size
) {
184 dma_buffer
= spdk_zmalloc(payload_size
, 4096, &phys_addr
,
185 SPDK_ENV_SOCKET_ID_ANY
, SPDK_MALLOC_DMA
);
190 if (host_to_controller
) {
191 memcpy(dma_buffer
, buffer
, payload_size
);
195 req
= nvme_allocate_request_contig(qpair
, dma_buffer
, payload_size
, nvme_user_copy_cmd_complete
,
198 spdk_free(dma_buffer
);
202 req
->user_cb_fn
= cb_fn
;
203 req
->user_cb_arg
= cb_arg
;
204 req
->user_buffer
= buffer
;
211 * Check if a request has exceeded the controller timeout.
213 * \param req request to check for timeout.
214 * \param cid command ID for command submitted by req (will be passed to timeout_cb_fn)
215 * \param active_proc per-process data for the controller associated with req
216 * \param now_tick current time from spdk_get_ticks()
217 * \return 0 if requests submitted more recently than req should still be checked for timeouts, or
218 * 1 if requests newer than req need not be checked.
220 * The request's timeout callback will be called if needed; the caller is only responsible for
221 * calling this function on each outstanding request.
224 nvme_request_check_timeout(struct nvme_request
*req
, uint16_t cid
,
225 struct spdk_nvme_ctrlr_process
*active_proc
,
228 struct spdk_nvme_qpair
*qpair
= req
->qpair
;
229 struct spdk_nvme_ctrlr
*ctrlr
= qpair
->ctrlr
;
231 assert(active_proc
->timeout_cb_fn
!= NULL
);
233 if (req
->timed_out
|| req
->submit_tick
== 0) {
237 if (req
->pid
!= g_spdk_nvme_pid
) {
241 if (nvme_qpair_is_admin_queue(qpair
) &&
242 req
->cmd
.opc
== SPDK_NVME_OPC_ASYNC_EVENT_REQUEST
) {
246 if (req
->submit_tick
+ active_proc
->timeout_ticks
> now_tick
) {
250 req
->timed_out
= true;
253 * We don't want to expose the admin queue to the user,
254 * so when we're timing out admin commands set the
257 active_proc
->timeout_cb_fn(active_proc
->timeout_cb_arg
, ctrlr
,
258 nvme_qpair_is_admin_queue(qpair
) ? NULL
: qpair
,
264 nvme_robust_mutex_init_shared(pthread_mutex_t
*mtx
)
269 pthread_mutex_init(mtx
, NULL
);
271 pthread_mutexattr_t attr
;
273 if (pthread_mutexattr_init(&attr
)) {
276 if (pthread_mutexattr_setpshared(&attr
, PTHREAD_PROCESS_SHARED
) ||
277 pthread_mutexattr_setrobust(&attr
, PTHREAD_MUTEX_ROBUST
) ||
278 pthread_mutex_init(mtx
, &attr
)) {
281 pthread_mutexattr_destroy(&attr
);
288 nvme_driver_init(void)
294 /* Each process needs its own pid. */
295 g_spdk_nvme_pid
= getpid();
298 * Only one thread from one process will do this driver init work.
299 * The primary process will reserve the shared memory and do the
301 * The secondary process will lookup the existing reserved memory.
303 if (spdk_process_is_primary()) {
304 /* The unique named memzone already reserved. */
305 if (g_spdk_nvme_driver
!= NULL
) {
308 g_spdk_nvme_driver
= spdk_memzone_reserve(SPDK_NVME_DRIVER_NAME
,
309 sizeof(struct nvme_driver
), socket_id
,
310 SPDK_MEMZONE_NO_IOVA_CONTIG
);
313 if (g_spdk_nvme_driver
== NULL
) {
314 SPDK_ERRLOG("primary process failed to reserve memory\n");
319 g_spdk_nvme_driver
= spdk_memzone_lookup(SPDK_NVME_DRIVER_NAME
);
321 /* The unique named memzone already reserved by the primary process. */
322 if (g_spdk_nvme_driver
!= NULL
) {
325 /* Wait the nvme driver to get initialized. */
326 while ((g_spdk_nvme_driver
->initialized
== false) &&
327 (ms_waited
< g_nvme_driver_timeout_ms
)) {
329 nvme_delay(1000); /* delay 1ms */
331 if (g_spdk_nvme_driver
->initialized
== false) {
332 SPDK_ERRLOG("timeout waiting for primary process to init\n");
337 SPDK_ERRLOG("primary process is not started yet\n");
346 * At this moment, only one thread from the primary process will do
347 * the g_spdk_nvme_driver initialization
349 assert(spdk_process_is_primary());
351 ret
= nvme_robust_mutex_init_shared(&g_spdk_nvme_driver
->lock
);
353 SPDK_ERRLOG("failed to initialize mutex\n");
354 spdk_memzone_free(SPDK_NVME_DRIVER_NAME
);
358 nvme_robust_mutex_lock(&g_spdk_nvme_driver
->lock
);
360 g_spdk_nvme_driver
->initialized
= false;
362 TAILQ_INIT(&g_spdk_nvme_driver
->shared_attached_ctrlrs
);
364 spdk_uuid_generate(&g_spdk_nvme_driver
->default_extended_host_id
);
366 nvme_robust_mutex_unlock(&g_spdk_nvme_driver
->lock
);
372 nvme_ctrlr_probe(const struct spdk_nvme_transport_id
*trid
, void *devhandle
,
373 spdk_nvme_probe_cb probe_cb
, void *cb_ctx
)
375 struct spdk_nvme_ctrlr
*ctrlr
;
376 struct spdk_nvme_ctrlr_opts opts
;
378 assert(trid
!= NULL
);
380 spdk_nvme_ctrlr_get_default_ctrlr_opts(&opts
, sizeof(opts
));
382 if (!probe_cb
|| probe_cb(cb_ctx
, trid
, &opts
)) {
383 ctrlr
= nvme_transport_ctrlr_construct(trid
, &opts
, devhandle
);
385 SPDK_ERRLOG("Failed to construct NVMe controller for SSD: %s\n", trid
->traddr
);
389 TAILQ_INSERT_TAIL(&g_nvme_init_ctrlrs
, ctrlr
, tailq
);
397 nvme_init_controllers(void *cb_ctx
, spdk_nvme_attach_cb attach_cb
)
401 struct spdk_nvme_ctrlr
*ctrlr
, *ctrlr_tmp
;
403 nvme_robust_mutex_lock(&g_spdk_nvme_driver
->lock
);
405 /* Initialize all new controllers in the g_nvme_init_ctrlrs list in parallel. */
406 while (!TAILQ_EMPTY(&g_nvme_init_ctrlrs
)) {
407 TAILQ_FOREACH_SAFE(ctrlr
, &g_nvme_init_ctrlrs
, tailq
, ctrlr_tmp
) {
408 /* Drop the driver lock while calling nvme_ctrlr_process_init()
409 * since it needs to acquire the driver lock internally when initializing
412 * TODO: Rethink the locking - maybe reset should take the lock so that start() and
413 * the functions it calls (in particular nvme_ctrlr_set_num_qpairs())
414 * can assume it is held.
416 nvme_robust_mutex_unlock(&g_spdk_nvme_driver
->lock
);
417 start_rc
= nvme_ctrlr_process_init(ctrlr
);
418 nvme_robust_mutex_lock(&g_spdk_nvme_driver
->lock
);
421 /* Controller failed to initialize. */
422 TAILQ_REMOVE(&g_nvme_init_ctrlrs
, ctrlr
, tailq
);
423 SPDK_ERRLOG("Failed to initialize SSD: %s\n", ctrlr
->trid
.traddr
);
424 nvme_ctrlr_destruct(ctrlr
);
429 if (ctrlr
->state
== NVME_CTRLR_STATE_READY
) {
431 * Controller has been initialized.
432 * Move it to the attached_ctrlrs list.
434 TAILQ_REMOVE(&g_nvme_init_ctrlrs
, ctrlr
, tailq
);
435 if (nvme_ctrlr_shared(ctrlr
)) {
436 TAILQ_INSERT_TAIL(&g_spdk_nvme_driver
->shared_attached_ctrlrs
, ctrlr
, tailq
);
438 TAILQ_INSERT_TAIL(&g_nvme_attached_ctrlrs
, ctrlr
, tailq
);
442 * Increase the ref count before calling attach_cb() as the user may
443 * call nvme_detach() immediately.
445 nvme_ctrlr_proc_get_ref(ctrlr
);
448 * Unlock while calling attach_cb() so the user can call other functions
449 * that may take the driver lock, like nvme_detach().
452 nvme_robust_mutex_unlock(&g_spdk_nvme_driver
->lock
);
453 attach_cb(cb_ctx
, &ctrlr
->trid
, ctrlr
, &ctrlr
->opts
);
454 nvme_robust_mutex_lock(&g_spdk_nvme_driver
->lock
);
462 g_spdk_nvme_driver
->initialized
= true;
464 nvme_robust_mutex_unlock(&g_spdk_nvme_driver
->lock
);
468 /* This function must not be called while holding g_spdk_nvme_driver->lock */
469 static struct spdk_nvme_ctrlr
*
470 spdk_nvme_get_ctrlr_by_trid(const struct spdk_nvme_transport_id
*trid
)
472 struct spdk_nvme_ctrlr
*ctrlr
;
474 nvme_robust_mutex_lock(&g_spdk_nvme_driver
->lock
);
475 ctrlr
= spdk_nvme_get_ctrlr_by_trid_unsafe(trid
);
476 nvme_robust_mutex_unlock(&g_spdk_nvme_driver
->lock
);
481 /* This function must be called while holding g_spdk_nvme_driver->lock */
482 struct spdk_nvme_ctrlr
*
483 spdk_nvme_get_ctrlr_by_trid_unsafe(const struct spdk_nvme_transport_id
*trid
)
485 struct spdk_nvme_ctrlr
*ctrlr
;
487 /* Search per-process list */
488 TAILQ_FOREACH(ctrlr
, &g_nvme_attached_ctrlrs
, tailq
) {
489 if (spdk_nvme_transport_id_compare(&ctrlr
->trid
, trid
) == 0) {
494 /* Search multi-process shared list */
495 TAILQ_FOREACH(ctrlr
, &g_spdk_nvme_driver
->shared_attached_ctrlrs
, tailq
) {
496 if (spdk_nvme_transport_id_compare(&ctrlr
->trid
, trid
) == 0) {
504 /* This function must only be called while holding g_spdk_nvme_driver->lock */
506 spdk_nvme_probe_internal(const struct spdk_nvme_transport_id
*trid
, void *cb_ctx
,
507 spdk_nvme_probe_cb probe_cb
, spdk_nvme_attach_cb attach_cb
,
508 spdk_nvme_remove_cb remove_cb
, struct spdk_nvme_ctrlr
**connected_ctrlr
)
511 struct spdk_nvme_ctrlr
*ctrlr
;
512 bool direct_connect
= (connected_ctrlr
!= NULL
);
514 if (!spdk_nvme_transport_available(trid
->trtype
)) {
515 SPDK_ERRLOG("NVMe trtype %u not available\n", trid
->trtype
);
519 nvme_robust_mutex_lock(&g_spdk_nvme_driver
->lock
);
521 nvme_transport_ctrlr_scan(trid
, cb_ctx
, probe_cb
, remove_cb
, direct_connect
);
524 * Probe controllers on the shared_attached_ctrlrs list
526 if (!spdk_process_is_primary() && (trid
->trtype
== SPDK_NVME_TRANSPORT_PCIE
)) {
527 TAILQ_FOREACH(ctrlr
, &g_spdk_nvme_driver
->shared_attached_ctrlrs
, tailq
) {
528 /* Do not attach other ctrlrs if user specify a valid trid */
529 if ((strlen(trid
->traddr
) != 0) &&
530 (spdk_nvme_transport_id_compare(trid
, &ctrlr
->trid
))) {
534 nvme_ctrlr_proc_get_ref(ctrlr
);
537 * Unlock while calling attach_cb() so the user can call other functions
538 * that may take the driver lock, like nvme_detach().
541 nvme_robust_mutex_unlock(&g_spdk_nvme_driver
->lock
);
542 attach_cb(cb_ctx
, &ctrlr
->trid
, ctrlr
, &ctrlr
->opts
);
543 nvme_robust_mutex_lock(&g_spdk_nvme_driver
->lock
);
547 nvme_robust_mutex_unlock(&g_spdk_nvme_driver
->lock
);
554 nvme_robust_mutex_unlock(&g_spdk_nvme_driver
->lock
);
556 * Keep going even if one or more nvme_attach() calls failed,
557 * but maintain the value of rc to signal errors when we return.
560 rc
= nvme_init_controllers(cb_ctx
, attach_cb
);
563 if (connected_ctrlr
) {
564 *connected_ctrlr
= spdk_nvme_get_ctrlr_by_trid(trid
);
571 spdk_nvme_probe(const struct spdk_nvme_transport_id
*trid
, void *cb_ctx
,
572 spdk_nvme_probe_cb probe_cb
, spdk_nvme_attach_cb attach_cb
,
573 spdk_nvme_remove_cb remove_cb
)
576 struct spdk_nvme_transport_id trid_pcie
;
578 rc
= nvme_driver_init();
584 memset(&trid_pcie
, 0, sizeof(trid_pcie
));
585 trid_pcie
.trtype
= SPDK_NVME_TRANSPORT_PCIE
;
589 return spdk_nvme_probe_internal(trid
, cb_ctx
, probe_cb
, attach_cb
, remove_cb
, NULL
);
593 spdk_nvme_connect_probe_cb(void *cb_ctx
, const struct spdk_nvme_transport_id
*trid
,
594 struct spdk_nvme_ctrlr_opts
*opts
)
596 struct spdk_nvme_ctrlr_connect_opts
*requested_opts
= cb_ctx
;
598 assert(requested_opts
->opts
);
600 assert(requested_opts
->opts_size
!= 0);
602 memcpy(opts
, requested_opts
->opts
, spdk_min(sizeof(*opts
), requested_opts
->opts_size
));
607 struct spdk_nvme_ctrlr
*
608 spdk_nvme_connect(const struct spdk_nvme_transport_id
*trid
,
609 const struct spdk_nvme_ctrlr_opts
*opts
, size_t opts_size
)
612 struct spdk_nvme_ctrlr_connect_opts connect_opts
= {};
613 struct spdk_nvme_ctrlr_connect_opts
*user_connect_opts
= NULL
;
614 struct spdk_nvme_ctrlr
*ctrlr
= NULL
;
615 spdk_nvme_probe_cb probe_cb
= NULL
;
618 SPDK_ERRLOG("No transport ID specified\n");
622 rc
= nvme_driver_init();
627 if (opts
&& opts_size
> 0) {
628 connect_opts
.opts
= opts
;
629 connect_opts
.opts_size
= opts_size
;
630 user_connect_opts
= &connect_opts
;
631 probe_cb
= spdk_nvme_connect_probe_cb
;
634 spdk_nvme_probe_internal(trid
, user_connect_opts
, probe_cb
, NULL
, NULL
, &ctrlr
);
640 spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type
*trtype
, const char *str
)
642 if (trtype
== NULL
|| str
== NULL
) {
646 if (strcasecmp(str
, "PCIe") == 0) {
647 *trtype
= SPDK_NVME_TRANSPORT_PCIE
;
648 } else if (strcasecmp(str
, "RDMA") == 0) {
649 *trtype
= SPDK_NVME_TRANSPORT_RDMA
;
650 } else if (strcasecmp(str
, "FC") == 0) {
651 *trtype
= SPDK_NVME_TRANSPORT_FC
;
659 spdk_nvme_transport_id_trtype_str(enum spdk_nvme_transport_type trtype
)
662 case SPDK_NVME_TRANSPORT_PCIE
:
664 case SPDK_NVME_TRANSPORT_RDMA
:
666 case SPDK_NVME_TRANSPORT_FC
:
674 spdk_nvme_transport_id_parse_adrfam(enum spdk_nvmf_adrfam
*adrfam
, const char *str
)
676 if (adrfam
== NULL
|| str
== NULL
) {
680 if (strcasecmp(str
, "IPv4") == 0) {
681 *adrfam
= SPDK_NVMF_ADRFAM_IPV4
;
682 } else if (strcasecmp(str
, "IPv6") == 0) {
683 *adrfam
= SPDK_NVMF_ADRFAM_IPV6
;
684 } else if (strcasecmp(str
, "IB") == 0) {
685 *adrfam
= SPDK_NVMF_ADRFAM_IB
;
686 } else if (strcasecmp(str
, "FC") == 0) {
687 *adrfam
= SPDK_NVMF_ADRFAM_FC
;
695 spdk_nvme_transport_id_adrfam_str(enum spdk_nvmf_adrfam adrfam
)
698 case SPDK_NVMF_ADRFAM_IPV4
:
700 case SPDK_NVMF_ADRFAM_IPV6
:
702 case SPDK_NVMF_ADRFAM_IB
:
704 case SPDK_NVMF_ADRFAM_FC
:
712 spdk_nvme_transport_id_parse(struct spdk_nvme_transport_id
*trid
, const char *str
)
714 const char *sep
, *sep1
;
715 const char *whitespace
= " \t\n";
716 size_t key_len
, val_len
;
720 if (trid
== NULL
|| str
== NULL
) {
724 while (*str
!= '\0') {
725 str
+= strspn(str
, whitespace
);
727 sep
= strchr(str
, ':');
729 sep
= strchr(str
, '=');
731 SPDK_ERRLOG("Key without ':' or '=' separator\n");
735 sep1
= strchr(str
, '=');
736 if ((sep1
!= NULL
) && (sep1
< sep
)) {
742 if (key_len
>= sizeof(key
)) {
743 SPDK_ERRLOG("Transport key length %zu greater than maximum allowed %zu\n",
744 key_len
, sizeof(key
) - 1);
748 memcpy(key
, str
, key_len
);
751 str
+= key_len
+ 1; /* Skip key: */
752 val_len
= strcspn(str
, whitespace
);
754 SPDK_ERRLOG("Key without value\n");
758 if (val_len
>= sizeof(val
)) {
759 SPDK_ERRLOG("Transport value length %zu greater than maximum allowed %zu\n",
760 val_len
, sizeof(val
) - 1);
764 memcpy(val
, str
, val_len
);
769 if (strcasecmp(key
, "trtype") == 0) {
770 if (spdk_nvme_transport_id_parse_trtype(&trid
->trtype
, val
) != 0) {
771 SPDK_ERRLOG("Unknown trtype '%s'\n", val
);
774 } else if (strcasecmp(key
, "adrfam") == 0) {
775 if (spdk_nvme_transport_id_parse_adrfam(&trid
->adrfam
, val
) != 0) {
776 SPDK_ERRLOG("Unknown adrfam '%s'\n", val
);
779 } else if (strcasecmp(key
, "traddr") == 0) {
780 if (val_len
> SPDK_NVMF_TRADDR_MAX_LEN
) {
781 SPDK_ERRLOG("traddr length %zu greater than maximum allowed %u\n",
782 val_len
, SPDK_NVMF_TRADDR_MAX_LEN
);
785 memcpy(trid
->traddr
, val
, val_len
+ 1);
786 } else if (strcasecmp(key
, "trsvcid") == 0) {
787 if (val_len
> SPDK_NVMF_TRSVCID_MAX_LEN
) {
788 SPDK_ERRLOG("trsvcid length %zu greater than maximum allowed %u\n",
789 val_len
, SPDK_NVMF_TRSVCID_MAX_LEN
);
792 memcpy(trid
->trsvcid
, val
, val_len
+ 1);
793 } else if (strcasecmp(key
, "subnqn") == 0) {
794 if (val_len
> SPDK_NVMF_NQN_MAX_LEN
) {
795 SPDK_ERRLOG("subnqn length %zu greater than maximum allowed %u\n",
796 val_len
, SPDK_NVMF_NQN_MAX_LEN
);
799 memcpy(trid
->subnqn
, val
, val_len
+ 1);
801 SPDK_ERRLOG("Unknown transport ID key '%s'\n", key
);
809 cmp_int(int a
, int b
)
815 spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id
*trid1
,
816 const struct spdk_nvme_transport_id
*trid2
)
820 cmp
= cmp_int(trid1
->trtype
, trid2
->trtype
);
825 if (trid1
->trtype
== SPDK_NVME_TRANSPORT_PCIE
) {
826 struct spdk_pci_addr pci_addr1
;
827 struct spdk_pci_addr pci_addr2
;
829 /* Normalize PCI addresses before comparing */
830 if (spdk_pci_addr_parse(&pci_addr1
, trid1
->traddr
) < 0 ||
831 spdk_pci_addr_parse(&pci_addr2
, trid2
->traddr
) < 0) {
835 /* PCIe transport ID only uses trtype and traddr */
836 return spdk_pci_addr_compare(&pci_addr1
, &pci_addr2
);
839 cmp
= strcasecmp(trid1
->traddr
, trid2
->traddr
);
844 cmp
= cmp_int(trid1
->adrfam
, trid2
->adrfam
);
849 cmp
= strcasecmp(trid1
->trsvcid
, trid2
->trsvcid
);
854 cmp
= strcmp(trid1
->subnqn
, trid2
->subnqn
);
862 SPDK_LOG_REGISTER_COMPONENT("nvme", SPDK_LOG_NVME
)