Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2016 Intel Corporation.
3 : : * All rights reserved.
4 : : * Copyright (c) 2021 Mellanox Technologies LTD. All rights reserved.
5 : : * Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
6 : : */
7 : :
8 : : /*
9 : : * NVMe transport abstraction
10 : : */
11 : :
12 : : #include "nvme_internal.h"
13 : : #include "spdk/queue.h"
14 : :
15 : : #define SPDK_MAX_NUM_OF_TRANSPORTS 16
16 : :
17 : : struct spdk_nvme_transport {
18 : : struct spdk_nvme_transport_ops ops;
19 : : TAILQ_ENTRY(spdk_nvme_transport) link;
20 : : };
21 : :
22 : : TAILQ_HEAD(nvme_transport_list, spdk_nvme_transport) g_spdk_nvme_transports =
23 : : TAILQ_HEAD_INITIALIZER(g_spdk_nvme_transports);
24 : :
25 : : struct spdk_nvme_transport g_spdk_transports[SPDK_MAX_NUM_OF_TRANSPORTS] = {};
26 : : int g_current_transport_index = 0;
27 : :
28 : : struct spdk_nvme_transport_opts g_spdk_nvme_transport_opts = {
29 : : .rdma_srq_size = 0,
30 : : .rdma_max_cq_size = 0,
31 : : .rdma_cm_event_timeout_ms = 1000
32 : : };
33 : :
34 : : const struct spdk_nvme_transport *
35 : 2132 : nvme_get_first_transport(void)
36 : : {
37 : 2132 : return TAILQ_FIRST(&g_spdk_nvme_transports);
38 : : }
39 : :
40 : : const struct spdk_nvme_transport *
41 : 1161 : nvme_get_next_transport(const struct spdk_nvme_transport *transport)
42 : : {
43 : 1161 : return TAILQ_NEXT(transport, link);
44 : : }
45 : :
46 : : /*
47 : : * Unfortunately, due to NVMe PCIe multiprocess support, we cannot store the
48 : : * transport object in either the controller struct or the admin qpair. This means
49 : : * that a lot of admin related transport calls will have to call nvme_get_transport
50 : : * in order to know which functions to call.
51 : : * In the I/O path, we have the ability to store the transport struct in the I/O
52 : : * qpairs to avoid taking a performance hit.
53 : : */
54 : : const struct spdk_nvme_transport *
55 : 48510111 : nvme_get_transport(const char *transport_name)
56 : : {
57 : : struct spdk_nvme_transport *registered_transport;
58 : :
59 [ + + ]: 61910272 : TAILQ_FOREACH(registered_transport, &g_spdk_nvme_transports, link) {
60 [ + + - + : 61901936 : if (strcasecmp(transport_name, registered_transport->ops.name) == 0) {
+ + ]
61 : 48501785 : return registered_transport;
62 : : }
63 : : }
64 : :
65 : 8330 : return NULL;
66 : : }
67 : :
68 : : bool
69 : 0 : spdk_nvme_transport_available(enum spdk_nvme_transport_type trtype)
70 : : {
71 : 0 : return nvme_get_transport(spdk_nvme_transport_id_trtype_str(trtype)) == NULL ? false : true;
72 : : }
73 : :
74 : : bool
75 : 86262 : spdk_nvme_transport_available_by_name(const char *transport_name)
76 : : {
77 : 86262 : return nvme_get_transport(transport_name) == NULL ? false : true;
78 : : }
79 : :
80 : : void
81 : 8326 : spdk_nvme_transport_register(const struct spdk_nvme_transport_ops *ops)
82 : : {
83 : : struct spdk_nvme_transport *new_transport;
84 : :
85 [ - + ]: 8326 : if (nvme_get_transport(ops->name)) {
86 : 0 : SPDK_ERRLOG("Double registering NVMe transport %s is prohibited.\n", ops->name);
87 : 0 : assert(false);
88 : : }
89 : :
90 [ - + ]: 8326 : if (g_current_transport_index == SPDK_MAX_NUM_OF_TRANSPORTS) {
91 : 0 : SPDK_ERRLOG("Unable to register new NVMe transport.\n");
92 : 0 : assert(false);
93 : : return;
94 : : }
95 : 8326 : new_transport = &g_spdk_transports[g_current_transport_index++];
96 : :
97 : 8326 : new_transport->ops = *ops;
98 : 8326 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, new_transport, link);
99 : : }
100 : :
101 : 2261 : struct spdk_nvme_ctrlr *nvme_transport_ctrlr_construct(const struct spdk_nvme_transport_id *trid,
102 : : const struct spdk_nvme_ctrlr_opts *opts,
103 : : void *devhandle)
104 : : {
105 : 2261 : const struct spdk_nvme_transport *transport = nvme_get_transport(trid->trstring);
106 : : struct spdk_nvme_ctrlr *ctrlr;
107 : :
108 [ - + ]: 2261 : if (transport == NULL) {
109 : 0 : SPDK_ERRLOG("Transport %s doesn't exist.", trid->trstring);
110 : 0 : return NULL;
111 : : }
112 : :
113 : 2261 : ctrlr = transport->ops.ctrlr_construct(trid, opts, devhandle);
114 : :
115 : 2261 : return ctrlr;
116 : : }
117 : :
118 : : int
119 : 86211 : nvme_transport_ctrlr_scan(struct spdk_nvme_probe_ctx *probe_ctx,
120 : : bool direct_connect)
121 : : {
122 : 86211 : const struct spdk_nvme_transport *transport = nvme_get_transport(probe_ctx->trid.trstring);
123 : :
124 [ - + ]: 86211 : if (transport == NULL) {
125 : 0 : SPDK_ERRLOG("Transport %s doesn't exist.", probe_ctx->trid.trstring);
126 : 0 : return -ENOENT;
127 : : }
128 : :
129 : 86211 : return transport->ops.ctrlr_scan(probe_ctx, direct_connect);
130 : : }
131 : :
132 : : int
133 : 2243 : nvme_transport_ctrlr_destruct(struct spdk_nvme_ctrlr *ctrlr)
134 : : {
135 : 2243 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
136 : :
137 [ - + ]: 2243 : assert(transport != NULL);
138 : 2243 : return transport->ops.ctrlr_destruct(ctrlr);
139 : : }
140 : :
141 : : int
142 : 2316 : nvme_transport_ctrlr_enable(struct spdk_nvme_ctrlr *ctrlr)
143 : : {
144 : 2316 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
145 : :
146 [ - + ]: 2316 : assert(transport != NULL);
147 : 2316 : return transport->ops.ctrlr_enable(ctrlr);
148 : : }
149 : :
150 : : int
151 : 2224 : nvme_transport_ctrlr_ready(struct spdk_nvme_ctrlr *ctrlr)
152 : : {
153 : 2224 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
154 : :
155 [ - + ]: 2224 : assert(transport != NULL);
156 [ - + ]: 2224 : if (transport->ops.ctrlr_ready) {
157 : 0 : return transport->ops.ctrlr_ready(ctrlr);
158 : : }
159 : :
160 : 2224 : return 0;
161 : : }
162 : :
163 : : int
164 : 0 : nvme_transport_ctrlr_set_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t value)
165 : : {
166 : 0 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
167 : :
168 [ # # ]: 0 : assert(transport != NULL);
169 : 0 : return transport->ops.ctrlr_set_reg_4(ctrlr, offset, value);
170 : : }
171 : :
172 : : int
173 : 0 : nvme_transport_ctrlr_set_reg_8(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint64_t value)
174 : : {
175 : 0 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
176 : :
177 [ # # ]: 0 : assert(transport != NULL);
178 : 0 : return transport->ops.ctrlr_set_reg_8(ctrlr, offset, value);
179 : : }
180 : :
181 : : int
182 : 25324 : nvme_transport_ctrlr_get_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t *value)
183 : : {
184 : 25324 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
185 : :
186 [ - + ]: 25324 : assert(transport != NULL);
187 : 25324 : return transport->ops.ctrlr_get_reg_4(ctrlr, offset, value);
188 : : }
189 : :
190 : : int
191 : 746 : nvme_transport_ctrlr_get_reg_8(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint64_t *value)
192 : : {
193 : 746 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
194 : :
195 [ - + ]: 746 : assert(transport != NULL);
196 : 746 : return transport->ops.ctrlr_get_reg_8(ctrlr, offset, value);
197 : : }
198 : :
199 : : static int
200 : 5719740 : nvme_queue_register_operation_completion(struct spdk_nvme_ctrlr *ctrlr, uint64_t value,
201 : : spdk_nvme_reg_cb cb_fn, void *cb_ctx)
202 : : {
203 : : struct nvme_register_completion *ctx;
204 : :
205 : 5719740 : ctx = spdk_zmalloc(sizeof(*ctx), 0, NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_SHARE);
206 [ - + ]: 5719740 : if (ctx == NULL) {
207 : 0 : return -ENOMEM;
208 : : }
209 : :
210 : 5719740 : ctx->cpl.status.sct = SPDK_NVME_SCT_GENERIC;
211 : 5719740 : ctx->cpl.status.sc = SPDK_NVME_SC_SUCCESS;
212 : 5719740 : ctx->cb_fn = cb_fn;
213 : 5719740 : ctx->cb_ctx = cb_ctx;
214 : 5719740 : ctx->value = value;
215 : 5719740 : ctx->pid = getpid();
216 : :
217 : 5719740 : nvme_ctrlr_lock(ctrlr);
218 : 5719740 : STAILQ_INSERT_TAIL(&ctrlr->register_operations, ctx, stailq);
219 : 5719740 : nvme_ctrlr_unlock(ctrlr);
220 : :
221 : 5719740 : return 0;
222 : : }
223 : :
224 : : int
225 : 5076 : nvme_transport_ctrlr_set_reg_4_async(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t value,
226 : : spdk_nvme_reg_cb cb_fn, void *cb_arg)
227 : : {
228 : 5076 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
229 : : int rc;
230 : :
231 [ - + ]: 5076 : assert(transport != NULL);
232 [ + + ]: 5076 : if (transport->ops.ctrlr_set_reg_4_async == NULL) {
233 : 2172 : rc = transport->ops.ctrlr_set_reg_4(ctrlr, offset, value);
234 [ - + ]: 2172 : if (rc != 0) {
235 : 0 : return rc;
236 : : }
237 : :
238 : 2172 : return nvme_queue_register_operation_completion(ctrlr, value, cb_fn, cb_arg);
239 : : }
240 : :
241 : 2904 : return transport->ops.ctrlr_set_reg_4_async(ctrlr, offset, value, cb_fn, cb_arg);
242 : : }
243 : :
244 : : int
245 : 0 : nvme_transport_ctrlr_set_reg_8_async(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint64_t value,
246 : : spdk_nvme_reg_cb cb_fn, void *cb_arg)
247 : :
248 : : {
249 : 0 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
250 : : int rc;
251 : :
252 [ # # ]: 0 : assert(transport != NULL);
253 [ # # ]: 0 : if (transport->ops.ctrlr_set_reg_8_async == NULL) {
254 : 0 : rc = transport->ops.ctrlr_set_reg_8(ctrlr, offset, value);
255 [ # # ]: 0 : if (rc != 0) {
256 : 0 : return rc;
257 : : }
258 : :
259 : 0 : return nvme_queue_register_operation_completion(ctrlr, value, cb_fn, cb_arg);
260 : : }
261 : :
262 : 0 : return transport->ops.ctrlr_set_reg_8_async(ctrlr, offset, value, cb_fn, cb_arg);
263 : : }
264 : :
265 : : int
266 : 5764614 : nvme_transport_ctrlr_get_reg_4_async(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset,
267 : : spdk_nvme_reg_cb cb_fn, void *cb_arg)
268 : : {
269 : 5764614 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
270 : 213712 : uint32_t value;
271 : : int rc;
272 : :
273 [ - + ]: 5764614 : assert(transport != NULL);
274 [ + + ]: 5764614 : if (transport->ops.ctrlr_get_reg_4_async == NULL) {
275 : 5716738 : rc = transport->ops.ctrlr_get_reg_4(ctrlr, offset, &value);
276 [ - + ]: 5716738 : if (rc != 0) {
277 : 0 : return rc;
278 : : }
279 : :
280 : 5716738 : return nvme_queue_register_operation_completion(ctrlr, value, cb_fn, cb_arg);
281 : : }
282 : :
283 : 47876 : return transport->ops.ctrlr_get_reg_4_async(ctrlr, offset, cb_fn, cb_arg);
284 : : }
285 : :
286 : : int
287 : 2316 : nvme_transport_ctrlr_get_reg_8_async(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset,
288 : : spdk_nvme_reg_cb cb_fn, void *cb_arg)
289 : : {
290 : 2316 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
291 : 474 : uint64_t value;
292 : : int rc;
293 : :
294 [ - + ]: 2316 : assert(transport != NULL);
295 [ + + ]: 2316 : if (transport->ops.ctrlr_get_reg_8_async == NULL) {
296 : 830 : rc = transport->ops.ctrlr_get_reg_8(ctrlr, offset, &value);
297 [ - + ]: 830 : if (rc != 0) {
298 : 0 : return rc;
299 : : }
300 : :
301 : 830 : return nvme_queue_register_operation_completion(ctrlr, value, cb_fn, cb_arg);
302 : : }
303 : :
304 : 1486 : return transport->ops.ctrlr_get_reg_8_async(ctrlr, offset, cb_fn, cb_arg);
305 : : }
306 : :
307 : : uint32_t
308 : 2316 : nvme_transport_ctrlr_get_max_xfer_size(struct spdk_nvme_ctrlr *ctrlr)
309 : : {
310 : 2316 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
311 : :
312 [ - + ]: 2316 : assert(transport != NULL);
313 : 2316 : return transport->ops.ctrlr_get_max_xfer_size(ctrlr);
314 : : }
315 : :
316 : : uint16_t
317 : 2209 : nvme_transport_ctrlr_get_max_sges(struct spdk_nvme_ctrlr *ctrlr)
318 : : {
319 : 2209 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
320 : :
321 [ - + ]: 2209 : assert(transport != NULL);
322 : 2209 : return transport->ops.ctrlr_get_max_sges(ctrlr);
323 : : }
324 : :
325 : : int
326 : 0 : nvme_transport_ctrlr_reserve_cmb(struct spdk_nvme_ctrlr *ctrlr)
327 : : {
328 : 0 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
329 : :
330 [ # # ]: 0 : assert(transport != NULL);
331 [ # # ]: 0 : if (transport->ops.ctrlr_reserve_cmb != NULL) {
332 : 0 : return transport->ops.ctrlr_reserve_cmb(ctrlr);
333 : : }
334 : :
335 : 0 : return -ENOTSUP;
336 : : }
337 : :
338 : : void *
339 : 16 : nvme_transport_ctrlr_map_cmb(struct spdk_nvme_ctrlr *ctrlr, size_t *size)
340 : : {
341 : 16 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
342 : :
343 [ - + ]: 16 : assert(transport != NULL);
344 [ + + ]: 16 : if (transport->ops.ctrlr_map_cmb != NULL) {
345 : 14 : return transport->ops.ctrlr_map_cmb(ctrlr, size);
346 : : }
347 : :
348 : 2 : return NULL;
349 : : }
350 : :
351 : : int
352 : 2 : nvme_transport_ctrlr_unmap_cmb(struct spdk_nvme_ctrlr *ctrlr)
353 : : {
354 : 2 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
355 : :
356 [ - + ]: 2 : assert(transport != NULL);
357 [ + - ]: 2 : if (transport->ops.ctrlr_unmap_cmb != NULL) {
358 : 2 : return transport->ops.ctrlr_unmap_cmb(ctrlr);
359 : : }
360 : :
361 : 0 : return 0;
362 : : }
363 : :
364 : : int
365 : 44 : nvme_transport_ctrlr_enable_pmr(struct spdk_nvme_ctrlr *ctrlr)
366 : : {
367 : 44 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
368 : :
369 [ - + ]: 44 : assert(transport != NULL);
370 [ + - ]: 44 : if (transport->ops.ctrlr_enable_pmr != NULL) {
371 : 44 : return transport->ops.ctrlr_enable_pmr(ctrlr);
372 : : }
373 : :
374 : 0 : return -ENOSYS;
375 : : }
376 : :
377 : : int
378 : 44 : nvme_transport_ctrlr_disable_pmr(struct spdk_nvme_ctrlr *ctrlr)
379 : : {
380 : 44 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
381 : :
382 [ - + ]: 44 : assert(transport != NULL);
383 [ + - ]: 44 : if (transport->ops.ctrlr_disable_pmr != NULL) {
384 : 44 : return transport->ops.ctrlr_disable_pmr(ctrlr);
385 : : }
386 : :
387 : 0 : return -ENOSYS;
388 : : }
389 : :
390 : : void *
391 : 44 : nvme_transport_ctrlr_map_pmr(struct spdk_nvme_ctrlr *ctrlr, size_t *size)
392 : : {
393 : 44 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
394 : :
395 [ - + ]: 44 : assert(transport != NULL);
396 [ + - ]: 44 : if (transport->ops.ctrlr_map_pmr != NULL) {
397 : 44 : return transport->ops.ctrlr_map_pmr(ctrlr, size);
398 : : }
399 : :
400 : 0 : return NULL;
401 : : }
402 : :
403 : : int
404 : 44 : nvme_transport_ctrlr_unmap_pmr(struct spdk_nvme_ctrlr *ctrlr)
405 : : {
406 : 44 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
407 : :
408 [ - + ]: 44 : assert(transport != NULL);
409 [ + - ]: 44 : if (transport->ops.ctrlr_unmap_pmr != NULL) {
410 : 44 : return transport->ops.ctrlr_unmap_pmr(ctrlr);
411 : : }
412 : :
413 : 0 : return -ENOSYS;
414 : : }
415 : :
416 : : struct spdk_nvme_qpair *
417 : 4520 : nvme_transport_ctrlr_create_io_qpair(struct spdk_nvme_ctrlr *ctrlr, uint16_t qid,
418 : : const struct spdk_nvme_io_qpair_opts *opts)
419 : : {
420 : : struct spdk_nvme_qpair *qpair;
421 : 4520 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
422 : :
423 [ - + ]: 4520 : assert(transport != NULL);
424 : 4520 : qpair = transport->ops.ctrlr_create_io_qpair(ctrlr, qid, opts);
425 [ + - + - ]: 4520 : if (qpair != NULL && !nvme_qpair_is_admin_queue(qpair)) {
426 : 4520 : qpair->transport = transport;
427 : : }
428 : :
429 : 4520 : return qpair;
430 : : }
431 : :
432 : : void
433 : 4520 : nvme_transport_ctrlr_delete_io_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair)
434 : : {
435 : 4520 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
436 : : int rc;
437 : :
438 [ - + ]: 4520 : assert(transport != NULL);
439 : :
440 : : /* Do not rely on qpair->transport. For multi-process cases, a foreign process may delete
441 : : * the IO qpair, in which case the transport object would be invalid (each process has their
442 : : * own unique transport objects since they contain function pointers). So we look up the
443 : : * transport object in the delete_io_qpair case.
444 : : */
445 : 4520 : rc = transport->ops.ctrlr_delete_io_qpair(ctrlr, qpair);
446 [ - + ]: 4520 : if (rc != 0) {
447 : 0 : SPDK_ERRLOG("transport %s returned non-zero for ctrlr_delete_io_qpair op\n",
448 : : transport->ops.name);
449 : 0 : assert(false);
450 : : }
451 : 4520 : }
452 : :
453 : : static void
454 : 13595 : nvme_transport_connect_qpair_fail(struct spdk_nvme_qpair *qpair, void *unused)
455 : : {
456 : 13595 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
457 : :
458 : : /* If the qpair was unable to reconnect, restore the original failure reason */
459 : 13595 : qpair->transport_failure_reason = qpair->last_transport_failure_reason;
460 : 13595 : nvme_transport_ctrlr_disconnect_qpair(ctrlr, qpair);
461 : 13595 : }
462 : :
463 : : int
464 : 20520 : nvme_transport_ctrlr_connect_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair)
465 : : {
466 : 20520 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
467 : : int rc;
468 : :
469 [ - + ]: 20520 : assert(transport != NULL);
470 [ + + - + ]: 20520 : if (!nvme_qpair_is_admin_queue(qpair) && qpair->transport == NULL) {
471 : 0 : qpair->transport = transport;
472 : : }
473 : :
474 : 20520 : qpair->last_transport_failure_reason = qpair->transport_failure_reason;
475 : 20520 : qpair->transport_failure_reason = SPDK_NVME_QPAIR_FAILURE_NONE;
476 : :
477 : 20520 : nvme_qpair_set_state(qpair, NVME_QPAIR_CONNECTING);
478 : 20520 : rc = transport->ops.ctrlr_connect_qpair(ctrlr, qpair);
479 [ + + ]: 20520 : if (rc != 0) {
480 : 12736 : goto err;
481 : : }
482 : :
483 [ + + ]: 7784 : if (qpair->poll_group) {
484 : 2322 : rc = nvme_poll_group_connect_qpair(qpair);
485 [ - + ]: 2322 : if (rc) {
486 : 0 : goto err;
487 : : }
488 : : }
489 : :
490 [ + + ]: 7784 : if (!qpair->async) {
491 : : /* Busy wait until the qpair exits the connecting state */
492 [ + + ]: 10939774 : while (nvme_qpair_get_state(qpair) == NVME_QPAIR_CONNECTING) {
493 [ - + - - ]: 10936715 : if (qpair->poll_group && spdk_nvme_ctrlr_is_fabrics(ctrlr)) {
494 : 0 : rc = spdk_nvme_poll_group_process_completions(
495 : 0 : qpair->poll_group->group, 0,
496 : : nvme_transport_connect_qpair_fail);
497 : : } else {
498 : 10936715 : rc = spdk_nvme_qpair_process_completions(qpair, 0);
499 : : }
500 : :
501 [ + + ]: 10936715 : if (rc < 0) {
502 : 859 : goto err;
503 : : }
504 : : }
505 : : }
506 : :
507 : 6925 : return 0;
508 : 13595 : err:
509 : 13595 : nvme_transport_connect_qpair_fail(qpair, NULL);
510 [ + + ]: 13595 : if (nvme_qpair_get_state(qpair) == NVME_QPAIR_DISCONNECTING) {
511 [ - + ]: 327 : assert(qpair->async == true);
512 : : /* Let the caller to poll the qpair until it is actually disconnected. */
513 : 327 : return 0;
514 : : }
515 : :
516 : 13268 : return rc;
517 : : }
518 : :
519 : : void
520 : 47129 : nvme_transport_ctrlr_disconnect_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair)
521 : : {
522 : 47129 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
523 : :
524 [ + + + + ]: 71506 : if (nvme_qpair_get_state(qpair) == NVME_QPAIR_DISCONNECTING ||
525 : 24377 : nvme_qpair_get_state(qpair) == NVME_QPAIR_DISCONNECTED) {
526 : 26570 : return;
527 : : }
528 : :
529 : 20559 : nvme_qpair_set_state(qpair, NVME_QPAIR_DISCONNECTING);
530 [ - + ]: 20559 : assert(transport != NULL);
531 : :
532 [ + + + - ]: 20559 : if (qpair->poll_group && (qpair->active_proc == nvme_ctrlr_get_current_process(ctrlr))) {
533 : 2322 : nvme_poll_group_disconnect_qpair(qpair);
534 : : }
535 : :
536 : 20559 : transport->ops.ctrlr_disconnect_qpair(ctrlr, qpair);
537 : : }
538 : :
539 : : void
540 : 19379 : nvme_transport_ctrlr_disconnect_qpair_done(struct spdk_nvme_qpair *qpair)
541 : : {
542 [ + + + - ]: 21031 : if (qpair->active_proc == nvme_ctrlr_get_current_process(qpair->ctrlr) ||
543 : 1652 : nvme_qpair_is_admin_queue(qpair)) {
544 : 19379 : nvme_qpair_abort_all_queued_reqs(qpair);
545 : : }
546 : 19379 : nvme_qpair_set_state(qpair, NVME_QPAIR_DISCONNECTED);
547 : 19379 : }
548 : :
549 : : int
550 : 10251 : nvme_transport_ctrlr_get_memory_domains(const struct spdk_nvme_ctrlr *ctrlr,
551 : : struct spdk_memory_domain **domains, int array_size)
552 : : {
553 : 10251 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
554 : :
555 [ - + ]: 10251 : assert(transport != NULL);
556 [ + + ]: 10251 : if (transport->ops.ctrlr_get_memory_domains) {
557 : 3874 : return transport->ops.ctrlr_get_memory_domains(ctrlr, domains, array_size);
558 : : }
559 : :
560 : 6377 : return 0;
561 : : }
562 : :
563 : : void
564 : 838 : nvme_transport_qpair_abort_reqs(struct spdk_nvme_qpair *qpair)
565 : : {
566 : : const struct spdk_nvme_transport *transport;
567 : :
568 [ + + ]: 838 : if (spdk_likely(!nvme_qpair_is_admin_queue(qpair))) {
569 : 53 : qpair->transport->ops.qpair_abort_reqs(qpair, qpair->abort_dnr);
570 : : } else {
571 : 785 : transport = nvme_get_transport(qpair->ctrlr->trid.trstring);
572 [ - + ]: 785 : assert(transport != NULL);
573 : 785 : transport->ops.qpair_abort_reqs(qpair, qpair->abort_dnr);
574 : : }
575 : 838 : }
576 : :
577 : : int
578 : 2316 : nvme_transport_qpair_reset(struct spdk_nvme_qpair *qpair)
579 : : {
580 : : const struct spdk_nvme_transport *transport;
581 : :
582 [ - + ]: 2316 : if (spdk_likely(!nvme_qpair_is_admin_queue(qpair))) {
583 : 0 : return qpair->transport->ops.qpair_reset(qpair);
584 : : }
585 : :
586 : 2316 : transport = nvme_get_transport(qpair->ctrlr->trid.trstring);
587 [ - + ]: 2316 : assert(transport != NULL);
588 : 2316 : return transport->ops.qpair_reset(qpair);
589 : : }
590 : :
591 : : int
592 : 42701647 : nvme_transport_qpair_submit_request(struct spdk_nvme_qpair *qpair, struct nvme_request *req)
593 : : {
594 : : const struct spdk_nvme_transport *transport;
595 : :
596 [ + + ]: 42701647 : if (spdk_likely(!nvme_qpair_is_admin_queue(qpair))) {
597 : 41643094 : return qpair->transport->ops.qpair_submit_request(qpair, req);
598 : : }
599 : :
600 : 1058552 : transport = nvme_get_transport(qpair->ctrlr->trid.trstring);
601 [ - + ]: 1058552 : assert(transport != NULL);
602 : 1058552 : return transport->ops.qpair_submit_request(qpair, req);
603 : : }
604 : :
605 : : int32_t
606 : 427156233 : nvme_transport_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions)
607 : : {
608 : : const struct spdk_nvme_transport *transport;
609 : :
610 [ + + ]: 427156233 : if (spdk_likely(!nvme_qpair_is_admin_queue(qpair))) {
611 : 385790042 : return qpair->transport->ops.qpair_process_completions(qpair, max_completions);
612 : : }
613 : :
614 : 41366161 : transport = nvme_get_transport(qpair->ctrlr->trid.trstring);
615 [ - + ]: 41366161 : assert(transport != NULL);
616 : 41366161 : return transport->ops.qpair_process_completions(qpair, max_completions);
617 : : }
618 : :
619 : : int
620 : 390263 : nvme_transport_qpair_iterate_requests(struct spdk_nvme_qpair *qpair,
621 : : int (*iter_fn)(struct nvme_request *req, void *arg),
622 : : void *arg)
623 : : {
624 : : const struct spdk_nvme_transport *transport;
625 : :
626 [ + - ]: 390263 : if (spdk_likely(!nvme_qpair_is_admin_queue(qpair))) {
627 : 390263 : return qpair->transport->ops.qpair_iterate_requests(qpair, iter_fn, arg);
628 : : }
629 : :
630 : 0 : transport = nvme_get_transport(qpair->ctrlr->trid.trstring);
631 [ # # ]: 0 : assert(transport != NULL);
632 : 0 : return transport->ops.qpair_iterate_requests(qpair, iter_fn, arg);
633 : : }
634 : :
635 : : void
636 : 2704 : nvme_transport_admin_qpair_abort_aers(struct spdk_nvme_qpair *qpair)
637 : : {
638 : 2704 : const struct spdk_nvme_transport *transport = nvme_get_transport(qpair->ctrlr->trid.trstring);
639 : :
640 [ - + ]: 2704 : assert(transport != NULL);
641 : 2704 : transport->ops.admin_qpair_abort_aers(qpair);
642 : 2704 : }
643 : :
644 : : struct spdk_nvme_transport_poll_group *
645 : 2132 : nvme_transport_poll_group_create(const struct spdk_nvme_transport *transport)
646 : : {
647 : 2132 : struct spdk_nvme_transport_poll_group *group = NULL;
648 : :
649 : 2132 : group = transport->ops.poll_group_create();
650 [ + - ]: 2132 : if (group) {
651 : 2132 : group->transport = transport;
652 : 2132 : STAILQ_INIT(&group->connected_qpairs);
653 : 2132 : STAILQ_INIT(&group->disconnected_qpairs);
654 : 2132 : group->num_connected_qpairs = 0;
655 : : }
656 : :
657 : 2132 : return group;
658 : : }
659 : :
660 : : struct spdk_nvme_transport_poll_group *
661 : 0 : nvme_transport_qpair_get_optimal_poll_group(const struct spdk_nvme_transport *transport,
662 : : struct spdk_nvme_qpair *qpair)
663 : : {
664 [ # # ]: 0 : if (transport->ops.qpair_get_optimal_poll_group) {
665 : 0 : return transport->ops.qpair_get_optimal_poll_group(qpair);
666 : : } else {
667 : 0 : return NULL;
668 : : }
669 : : }
670 : :
671 : : int
672 : 2326 : nvme_transport_poll_group_add(struct spdk_nvme_transport_poll_group *tgroup,
673 : : struct spdk_nvme_qpair *qpair)
674 : : {
675 : : int rc;
676 : :
677 : 2326 : rc = tgroup->transport->ops.poll_group_add(tgroup, qpair);
678 [ + - ]: 2326 : if (rc == 0) {
679 : 2326 : qpair->poll_group = tgroup;
680 [ - + ]: 2326 : assert(nvme_qpair_get_state(qpair) < NVME_QPAIR_CONNECTED);
681 : 2326 : qpair->poll_group_tailq_head = &tgroup->disconnected_qpairs;
682 : 2326 : STAILQ_INSERT_TAIL(&tgroup->disconnected_qpairs, qpair, poll_group_stailq);
683 : : }
684 : :
685 : 2326 : return rc;
686 : : }
687 : :
688 : : int
689 : 2334 : nvme_transport_poll_group_remove(struct spdk_nvme_transport_poll_group *tgroup,
690 : : struct spdk_nvme_qpair *qpair)
691 : : {
692 : : int rc __attribute__((unused));
693 : :
694 [ + + ]: 2334 : if (qpair->poll_group_tailq_head == &tgroup->connected_qpairs) {
695 : 4 : return -EINVAL;
696 [ + + ]: 2330 : } else if (qpair->poll_group_tailq_head != &tgroup->disconnected_qpairs) {
697 : 4 : return -ENOENT;
698 : : }
699 : :
700 : 2326 : rc = tgroup->transport->ops.poll_group_remove(tgroup, qpair);
701 [ - + ]: 2326 : assert(rc == 0);
702 : :
703 [ + + + + : 2328 : STAILQ_REMOVE(&tgroup->disconnected_qpairs, qpair, spdk_nvme_qpair, poll_group_stailq);
+ + + + ]
704 : :
705 : 2326 : qpair->poll_group = NULL;
706 : 2326 : qpair->poll_group_tailq_head = NULL;
707 : :
708 : 2326 : return 0;
709 : : }
710 : :
711 : : int64_t
712 : 547077307 : nvme_transport_poll_group_process_completions(struct spdk_nvme_transport_poll_group *tgroup,
713 : : uint32_t completions_per_qpair, spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb)
714 : : {
715 : 547077307 : return tgroup->transport->ops.poll_group_process_completions(tgroup, completions_per_qpair,
716 : : disconnected_qpair_cb);
717 : : }
718 : :
719 : : int
720 : 2132 : nvme_transport_poll_group_destroy(struct spdk_nvme_transport_poll_group *tgroup)
721 : : {
722 : 2132 : return tgroup->transport->ops.poll_group_destroy(tgroup);
723 : : }
724 : :
725 : : int
726 : 2334 : nvme_transport_poll_group_disconnect_qpair(struct spdk_nvme_qpair *qpair)
727 : : {
728 : : struct spdk_nvme_transport_poll_group *tgroup;
729 : : int rc __attribute__((unused));
730 : :
731 : 2334 : tgroup = qpair->poll_group;
732 : :
733 [ + + ]: 2334 : if (qpair->poll_group_tailq_head == &tgroup->disconnected_qpairs) {
734 : 4 : return 0;
735 : : }
736 : :
737 [ + + ]: 2330 : if (qpair->poll_group_tailq_head == &tgroup->connected_qpairs) {
738 : 2326 : rc = tgroup->transport->ops.poll_group_disconnect_qpair(qpair);
739 [ - + ]: 2326 : assert(rc == 0);
740 : :
741 : 2326 : qpair->poll_group_tailq_head = &tgroup->disconnected_qpairs;
742 [ + + + + : 2345 : STAILQ_REMOVE(&tgroup->connected_qpairs, qpair, spdk_nvme_qpair, poll_group_stailq);
+ + + + ]
743 [ - + ]: 2326 : assert(tgroup->num_connected_qpairs > 0);
744 : 2326 : tgroup->num_connected_qpairs--;
745 : 2326 : STAILQ_INSERT_TAIL(&tgroup->disconnected_qpairs, qpair, poll_group_stailq);
746 : :
747 : 2326 : return 0;
748 : : }
749 : :
750 : 4 : return -EINVAL;
751 : : }
752 : :
753 : : int
754 : 3190 : nvme_transport_poll_group_connect_qpair(struct spdk_nvme_qpair *qpair)
755 : : {
756 : : struct spdk_nvme_transport_poll_group *tgroup;
757 : : int rc;
758 : :
759 : 3190 : tgroup = qpair->poll_group;
760 : :
761 [ + + ]: 3190 : if (qpair->poll_group_tailq_head == &tgroup->connected_qpairs) {
762 : 860 : return 0;
763 : : }
764 : :
765 [ + + ]: 2330 : if (qpair->poll_group_tailq_head == &tgroup->disconnected_qpairs) {
766 : 2326 : rc = tgroup->transport->ops.poll_group_connect_qpair(qpair);
767 [ + - ]: 2326 : if (rc == 0) {
768 : 2326 : qpair->poll_group_tailq_head = &tgroup->connected_qpairs;
769 [ + + + - : 2326 : STAILQ_REMOVE(&tgroup->disconnected_qpairs, qpair, spdk_nvme_qpair, poll_group_stailq);
- + + - ]
770 : 2326 : STAILQ_INSERT_TAIL(&tgroup->connected_qpairs, qpair, poll_group_stailq);
771 : 2326 : tgroup->num_connected_qpairs++;
772 : : }
773 : :
774 [ + - ]: 2326 : return rc == -EINPROGRESS ? 0 : rc;
775 : : }
776 : :
777 : :
778 : 4 : return -EINVAL;
779 : : }
780 : :
781 : : int
782 : 8 : nvme_transport_poll_group_get_stats(struct spdk_nvme_transport_poll_group *tgroup,
783 : : struct spdk_nvme_transport_poll_group_stat **stats)
784 : : {
785 [ + - ]: 8 : if (tgroup->transport->ops.poll_group_get_stats) {
786 : 8 : return tgroup->transport->ops.poll_group_get_stats(tgroup, stats);
787 : : }
788 : 0 : return -ENOTSUP;
789 : : }
790 : :
791 : : void
792 : 8 : nvme_transport_poll_group_free_stats(struct spdk_nvme_transport_poll_group *tgroup,
793 : : struct spdk_nvme_transport_poll_group_stat *stats)
794 : : {
795 [ + - ]: 8 : if (tgroup->transport->ops.poll_group_free_stats) {
796 : 8 : tgroup->transport->ops.poll_group_free_stats(tgroup, stats);
797 : : }
798 : 8 : }
799 : :
800 : : spdk_nvme_transport_type_t
801 : 8 : nvme_transport_get_trtype(const struct spdk_nvme_transport *transport)
802 : : {
803 : 8 : return transport->ops.type;
804 : : }
805 : :
806 : : void
807 : 0 : spdk_nvme_transport_get_opts(struct spdk_nvme_transport_opts *opts, size_t opts_size)
808 : : {
809 [ # # ]: 0 : if (opts == NULL) {
810 : 0 : SPDK_ERRLOG("opts should not be NULL.\n");
811 : 0 : return;
812 : : }
813 : :
814 [ # # ]: 0 : if (opts_size == 0) {
815 : 0 : SPDK_ERRLOG("opts_size should not be zero.\n");
816 : 0 : return;
817 : : }
818 : :
819 : 0 : opts->opts_size = opts_size;
820 : :
821 : : #define SET_FIELD(field) \
822 : : if (offsetof(struct spdk_nvme_transport_opts, field) + sizeof(opts->field) <= opts_size) { \
823 : : opts->field = g_spdk_nvme_transport_opts.field; \
824 : : } \
825 : :
826 [ # # ]: 0 : SET_FIELD(rdma_srq_size);
827 [ # # ]: 0 : SET_FIELD(rdma_max_cq_size);
828 [ # # ]: 0 : SET_FIELD(rdma_cm_event_timeout_ms);
829 : :
830 : : /* Do not remove this statement, you should always update this statement when you adding a new field,
831 : : * and do not forget to add the SET_FIELD statement for your added field. */
832 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_transport_opts) == 24, "Incorrect size");
833 : :
834 : : #undef SET_FIELD
835 : : }
836 : :
837 : : int
838 : 0 : spdk_nvme_transport_set_opts(const struct spdk_nvme_transport_opts *opts, size_t opts_size)
839 : : {
840 [ # # ]: 0 : if (opts == NULL) {
841 : 0 : SPDK_ERRLOG("opts should not be NULL.\n");
842 : 0 : return -EINVAL;
843 : : }
844 : :
845 [ # # ]: 0 : if (opts_size == 0) {
846 : 0 : SPDK_ERRLOG("opts_size should not be zero.\n");
847 : 0 : return -EINVAL;
848 : : }
849 : :
850 : : #define SET_FIELD(field) \
851 : : if (offsetof(struct spdk_nvme_transport_opts, field) + sizeof(opts->field) <= opts->opts_size) { \
852 : : g_spdk_nvme_transport_opts.field = opts->field; \
853 : : } \
854 : :
855 [ # # ]: 0 : SET_FIELD(rdma_srq_size);
856 [ # # ]: 0 : SET_FIELD(rdma_max_cq_size);
857 [ # # ]: 0 : SET_FIELD(rdma_cm_event_timeout_ms);
858 : :
859 : 0 : g_spdk_nvme_transport_opts.opts_size = opts->opts_size;
860 : :
861 : : #undef SET_FIELD
862 : :
863 : 0 : return 0;
864 : : }
865 : :
866 : : volatile struct spdk_nvme_registers *
867 : 10 : spdk_nvme_ctrlr_get_registers(struct spdk_nvme_ctrlr *ctrlr)
868 : : {
869 : 10 : const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring);
870 : :
871 [ - + ]: 10 : if (transport == NULL) {
872 : : /* Transport does not exist. */
873 : 0 : return NULL;
874 : : }
875 : :
876 [ + - ]: 10 : if (transport->ops.ctrlr_get_registers) {
877 : 10 : return transport->ops.ctrlr_get_registers(ctrlr);
878 : : }
879 : :
880 : 0 : return NULL;
881 : : }
|