Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2016 Intel Corporation. All rights reserved.
3 : : * Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
4 : : * Copyright (c) 2021, 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : : * Copyright (c) 2022 Dell Inc, or its subsidiaries. All rights reserved.
6 : : */
7 : :
8 : : #include "spdk/stdinc.h"
9 : :
10 : : #include "bdev_nvme.h"
11 : :
12 : : #include "spdk/accel.h"
13 : : #include "spdk/config.h"
14 : : #include "spdk/endian.h"
15 : : #include "spdk/bdev.h"
16 : : #include "spdk/json.h"
17 : : #include "spdk/likely.h"
18 : : #include "spdk/nvme.h"
19 : : #include "spdk/nvme_ocssd.h"
20 : : #include "spdk/nvme_zns.h"
21 : : #include "spdk/opal.h"
22 : : #include "spdk/thread.h"
23 : : #include "spdk/trace.h"
24 : : #include "spdk/string.h"
25 : : #include "spdk/util.h"
26 : : #include "spdk/uuid.h"
27 : :
28 : : #include "spdk/bdev_module.h"
29 : : #include "spdk/log.h"
30 : :
31 : : #include "spdk_internal/usdt.h"
32 : : #include "spdk_internal/trace_defs.h"
33 : :
34 : : #define SPDK_BDEV_NVME_DEFAULT_DELAY_CMD_SUBMIT true
35 : : #define SPDK_BDEV_NVME_DEFAULT_KEEP_ALIVE_TIMEOUT_IN_MS (10000)
36 : :
37 : : #define NSID_STR_LEN 10
38 : :
39 : : static int bdev_nvme_config_json(struct spdk_json_write_ctx *w);
40 : :
41 : : struct nvme_bdev_io {
42 : : /** array of iovecs to transfer. */
43 : : struct iovec *iovs;
44 : :
45 : : /** Number of iovecs in iovs array. */
46 : : int iovcnt;
47 : :
48 : : /** Current iovec position. */
49 : : int iovpos;
50 : :
51 : : /** Offset in current iovec. */
52 : : uint32_t iov_offset;
53 : :
54 : : /** I/O path the current I/O or admin passthrough is submitted on, or the I/O path
55 : : * being reset in a reset I/O.
56 : : */
57 : : struct nvme_io_path *io_path;
58 : :
59 : : /** array of iovecs to transfer. */
60 : : struct iovec *fused_iovs;
61 : :
62 : : /** Number of iovecs in iovs array. */
63 : : int fused_iovcnt;
64 : :
65 : : /** Current iovec position. */
66 : : int fused_iovpos;
67 : :
68 : : /** Offset in current iovec. */
69 : : uint32_t fused_iov_offset;
70 : :
71 : : /** Saved status for admin passthru completion event, PI error verification, or intermediate compare-and-write status */
72 : : struct spdk_nvme_cpl cpl;
73 : :
74 : : /** Extended IO opts passed by the user to bdev layer and mapped to NVME format */
75 : : struct spdk_nvme_ns_cmd_ext_io_opts ext_opts;
76 : :
77 : : /** Keeps track if first of fused commands was submitted */
78 : : bool first_fused_submitted;
79 : :
80 : : /** Keeps track if first of fused commands was completed */
81 : : bool first_fused_completed;
82 : :
83 : : /** Temporary pointer to zone report buffer */
84 : : struct spdk_nvme_zns_zone_report *zone_report_buf;
85 : :
86 : : /** Keep track of how many zones that have been copied to the spdk_bdev_zone_info struct */
87 : : uint64_t handled_zones;
88 : :
89 : : /** Expiration value in ticks to retry the current I/O. */
90 : : uint64_t retry_ticks;
91 : :
92 : : /* How many times the current I/O was retried. */
93 : : int32_t retry_count;
94 : :
95 : : /* Current tsc at submit time. */
96 : : uint64_t submit_tsc;
97 : : };
98 : :
99 : : struct nvme_probe_skip_entry {
100 : : struct spdk_nvme_transport_id trid;
101 : : TAILQ_ENTRY(nvme_probe_skip_entry) tailq;
102 : : };
103 : : /* All the controllers deleted by users via RPC are skipped by hotplug monitor */
104 : : static TAILQ_HEAD(, nvme_probe_skip_entry) g_skipped_nvme_ctrlrs = TAILQ_HEAD_INITIALIZER(
105 : : g_skipped_nvme_ctrlrs);
106 : :
107 : : static struct spdk_bdev_nvme_opts g_opts = {
108 : : .action_on_timeout = SPDK_BDEV_NVME_TIMEOUT_ACTION_NONE,
109 : : .timeout_us = 0,
110 : : .timeout_admin_us = 0,
111 : : .keep_alive_timeout_ms = SPDK_BDEV_NVME_DEFAULT_KEEP_ALIVE_TIMEOUT_IN_MS,
112 : : .transport_retry_count = 4,
113 : : .arbitration_burst = 0,
114 : : .low_priority_weight = 0,
115 : : .medium_priority_weight = 0,
116 : : .high_priority_weight = 0,
117 : : .nvme_adminq_poll_period_us = 10000ULL,
118 : : .nvme_ioq_poll_period_us = 0,
119 : : .io_queue_requests = 0,
120 : : .delay_cmd_submit = SPDK_BDEV_NVME_DEFAULT_DELAY_CMD_SUBMIT,
121 : : .bdev_retry_count = 3,
122 : : .transport_ack_timeout = 0,
123 : : .ctrlr_loss_timeout_sec = 0,
124 : : .reconnect_delay_sec = 0,
125 : : .fast_io_fail_timeout_sec = 0,
126 : : .disable_auto_failback = false,
127 : : .generate_uuids = false,
128 : : .transport_tos = 0,
129 : : .nvme_error_stat = false,
130 : : .io_path_stat = false,
131 : : .allow_accel_sequence = false,
132 : : };
133 : :
134 : : #define NVME_HOTPLUG_POLL_PERIOD_MAX 10000000ULL
135 : : #define NVME_HOTPLUG_POLL_PERIOD_DEFAULT 100000ULL
136 : :
137 : : static int g_hot_insert_nvme_controller_index = 0;
138 : : static uint64_t g_nvme_hotplug_poll_period_us = NVME_HOTPLUG_POLL_PERIOD_DEFAULT;
139 : : static bool g_nvme_hotplug_enabled = false;
140 : : struct spdk_thread *g_bdev_nvme_init_thread;
141 : : static struct spdk_poller *g_hotplug_poller;
142 : : static struct spdk_poller *g_hotplug_probe_poller;
143 : : static struct spdk_nvme_probe_ctx *g_hotplug_probe_ctx;
144 : :
145 : : static void nvme_ctrlr_populate_namespaces(struct nvme_ctrlr *nvme_ctrlr,
146 : : struct nvme_async_probe_ctx *ctx);
147 : : static void nvme_ctrlr_populate_namespaces_done(struct nvme_ctrlr *nvme_ctrlr,
148 : : struct nvme_async_probe_ctx *ctx);
149 : : static int bdev_nvme_library_init(void);
150 : : static void bdev_nvme_library_fini(void);
151 : : static void _bdev_nvme_submit_request(struct nvme_bdev_channel *nbdev_ch,
152 : : struct spdk_bdev_io *bdev_io);
153 : : static void bdev_nvme_submit_request(struct spdk_io_channel *ch,
154 : : struct spdk_bdev_io *bdev_io);
155 : : static int bdev_nvme_readv(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
156 : : void *md, uint64_t lba_count, uint64_t lba,
157 : : uint32_t flags, struct spdk_memory_domain *domain, void *domain_ctx,
158 : : struct spdk_accel_sequence *seq);
159 : : static int bdev_nvme_no_pi_readv(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
160 : : void *md, uint64_t lba_count, uint64_t lba);
161 : : static int bdev_nvme_writev(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
162 : : void *md, uint64_t lba_count, uint64_t lba,
163 : : uint32_t flags, struct spdk_memory_domain *domain, void *domain_ctx,
164 : : struct spdk_accel_sequence *seq);
165 : : static int bdev_nvme_zone_appendv(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
166 : : void *md, uint64_t lba_count,
167 : : uint64_t zslba, uint32_t flags);
168 : : static int bdev_nvme_comparev(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
169 : : void *md, uint64_t lba_count, uint64_t lba,
170 : : uint32_t flags);
171 : : static int bdev_nvme_comparev_and_writev(struct nvme_bdev_io *bio,
172 : : struct iovec *cmp_iov, int cmp_iovcnt, struct iovec *write_iov,
173 : : int write_iovcnt, void *md, uint64_t lba_count, uint64_t lba,
174 : : uint32_t flags);
175 : : static int bdev_nvme_get_zone_info(struct nvme_bdev_io *bio, uint64_t zone_id,
176 : : uint32_t num_zones, struct spdk_bdev_zone_info *info);
177 : : static int bdev_nvme_zone_management(struct nvme_bdev_io *bio, uint64_t zone_id,
178 : : enum spdk_bdev_zone_action action);
179 : : static void bdev_nvme_admin_passthru(struct nvme_bdev_channel *nbdev_ch,
180 : : struct nvme_bdev_io *bio,
181 : : struct spdk_nvme_cmd *cmd, void *buf, size_t nbytes);
182 : : static int bdev_nvme_io_passthru(struct nvme_bdev_io *bio, struct spdk_nvme_cmd *cmd,
183 : : void *buf, size_t nbytes);
184 : : static int bdev_nvme_io_passthru_md(struct nvme_bdev_io *bio, struct spdk_nvme_cmd *cmd,
185 : : void *buf, size_t nbytes, void *md_buf, size_t md_len);
186 : : static int bdev_nvme_iov_passthru_md(struct nvme_bdev_io *bio, struct spdk_nvme_cmd *cmd,
187 : : struct iovec *iov, int iovcnt, size_t nbytes,
188 : : void *md_buf, size_t md_len);
189 : : static void bdev_nvme_abort(struct nvme_bdev_channel *nbdev_ch,
190 : : struct nvme_bdev_io *bio, struct nvme_bdev_io *bio_to_abort);
191 : : static void bdev_nvme_reset_io(struct nvme_bdev_channel *nbdev_ch, struct nvme_bdev_io *bio);
192 : : static int bdev_nvme_reset_ctrlr(struct nvme_ctrlr *nvme_ctrlr);
193 : : static int bdev_nvme_failover_ctrlr(struct nvme_ctrlr *nvme_ctrlr);
194 : : static void remove_cb(void *cb_ctx, struct spdk_nvme_ctrlr *ctrlr);
195 : : static int nvme_ctrlr_read_ana_log_page(struct nvme_ctrlr *nvme_ctrlr);
196 : :
197 : : static struct nvme_ns *nvme_ns_alloc(void);
198 : : static void nvme_ns_free(struct nvme_ns *ns);
199 : :
200 : : static int
201 : 1908 : nvme_ns_cmp(struct nvme_ns *ns1, struct nvme_ns *ns2)
202 : : {
203 [ + + ]: 1908 : return ns1->id < ns2->id ? -1 : ns1->id > ns2->id;
204 : : }
205 : :
206 [ + + + + : 15963 : RB_GENERATE_STATIC(nvme_ns_tree, nvme_ns, node, nvme_ns_cmp);
+ + + + +
+ + + + +
+ + + + -
+ + - - -
- + + + +
+ + - - -
+ - - - -
- - + + +
- + + + -
- - - - -
- - - - -
- - + ]
207 : :
208 : : struct spdk_nvme_qpair *
209 : 4 : bdev_nvme_get_io_qpair(struct spdk_io_channel *ctrlr_io_ch)
210 : : {
211 : : struct nvme_ctrlr_channel *ctrlr_ch;
212 : :
213 [ - + ]: 4 : assert(ctrlr_io_ch != NULL);
214 : :
215 : 4 : ctrlr_ch = spdk_io_channel_get_ctx(ctrlr_io_ch);
216 : :
217 : 4 : return ctrlr_ch->qpair->qpair;
218 : : }
219 : :
220 : : static int
221 : 1890 : bdev_nvme_get_ctx_size(void)
222 : : {
223 : 1890 : return sizeof(struct nvme_bdev_io);
224 : : }
225 : :
226 : : static struct spdk_bdev_module nvme_if = {
227 : : .name = "nvme",
228 : : .async_fini = true,
229 : : .module_init = bdev_nvme_library_init,
230 : : .module_fini = bdev_nvme_library_fini,
231 : : .config_json = bdev_nvme_config_json,
232 : : .get_ctx_size = bdev_nvme_get_ctx_size,
233 : :
234 : : };
235 : 2042 : SPDK_BDEV_MODULE_REGISTER(nvme, &nvme_if)
236 : :
237 : : struct nvme_bdev_ctrlrs g_nvme_bdev_ctrlrs = TAILQ_HEAD_INITIALIZER(g_nvme_bdev_ctrlrs);
238 : : pthread_mutex_t g_bdev_nvme_mutex = PTHREAD_MUTEX_INITIALIZER;
239 : : bool g_bdev_nvme_module_finish;
240 : :
241 : : struct nvme_bdev_ctrlr *
242 : 33846 : nvme_bdev_ctrlr_get_by_name(const char *name)
243 : : {
244 : : struct nvme_bdev_ctrlr *nbdev_ctrlr;
245 : :
246 [ + + ]: 35125 : TAILQ_FOREACH(nbdev_ctrlr, &g_nvme_bdev_ctrlrs, tailq) {
247 [ + + - + : 32184 : if (strcmp(name, nbdev_ctrlr->name) == 0) {
+ + ]
248 : 30905 : break;
249 : : }
250 : : }
251 : :
252 : 33846 : return nbdev_ctrlr;
253 : : }
254 : :
255 : : static struct nvme_ctrlr *
256 : 676 : nvme_bdev_ctrlr_get_ctrlr(struct nvme_bdev_ctrlr *nbdev_ctrlr,
257 : : const struct spdk_nvme_transport_id *trid)
258 : : {
259 : : struct nvme_ctrlr *nvme_ctrlr;
260 : :
261 [ + + ]: 1284 : TAILQ_FOREACH(nvme_ctrlr, &nbdev_ctrlr->ctrlrs, tailq) {
262 [ + + ]: 740 : if (spdk_nvme_transport_id_compare(trid, &nvme_ctrlr->active_path_id->trid) == 0) {
263 : 132 : break;
264 : : }
265 : : }
266 : :
267 : 676 : return nvme_ctrlr;
268 : : }
269 : :
270 : : struct nvme_ctrlr *
271 : 0 : nvme_bdev_ctrlr_get_ctrlr_by_id(struct nvme_bdev_ctrlr *nbdev_ctrlr,
272 : : uint16_t cntlid)
273 : : {
274 : : struct nvme_ctrlr *nvme_ctrlr;
275 : : const struct spdk_nvme_ctrlr_data *cdata;
276 : :
277 [ # # ]: 0 : TAILQ_FOREACH(nvme_ctrlr, &nbdev_ctrlr->ctrlrs, tailq) {
278 : 0 : cdata = spdk_nvme_ctrlr_get_data(nvme_ctrlr->ctrlr);
279 [ # # ]: 0 : if (cdata->cntlid == cntlid) {
280 : 0 : break;
281 : : }
282 : : }
283 : :
284 : 0 : return nvme_ctrlr;
285 : : }
286 : :
287 : : static struct nvme_bdev *
288 : 1221 : nvme_bdev_ctrlr_get_bdev(struct nvme_bdev_ctrlr *nbdev_ctrlr, uint32_t nsid)
289 : : {
290 : : struct nvme_bdev *bdev;
291 : :
292 [ - + ]: 1221 : pthread_mutex_lock(&g_bdev_nvme_mutex);
293 [ + + ]: 1521 : TAILQ_FOREACH(bdev, &nbdev_ctrlr->bdevs, tailq) {
294 [ + + ]: 448 : if (bdev->nsid == nsid) {
295 : 148 : break;
296 : : }
297 : : }
298 [ - + ]: 1221 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
299 : :
300 : 1221 : return bdev;
301 : : }
302 : :
303 : : struct nvme_ns *
304 : 2436 : nvme_ctrlr_get_ns(struct nvme_ctrlr *nvme_ctrlr, uint32_t nsid)
305 : : {
306 : 1273 : struct nvme_ns ns;
307 : :
308 [ - + ]: 2436 : assert(nsid > 0);
309 : :
310 : 2436 : ns.id = nsid;
311 : 2436 : return RB_FIND(nvme_ns_tree, &nvme_ctrlr->namespaces, &ns);
312 : : }
313 : :
314 : : struct nvme_ns *
315 : 2295 : nvme_ctrlr_get_first_active_ns(struct nvme_ctrlr *nvme_ctrlr)
316 : : {
317 : 2295 : return RB_MIN(nvme_ns_tree, &nvme_ctrlr->namespaces);
318 : : }
319 : :
320 : : struct nvme_ns *
321 : 1223 : nvme_ctrlr_get_next_active_ns(struct nvme_ctrlr *nvme_ctrlr, struct nvme_ns *ns)
322 : : {
323 [ - + ]: 1223 : if (ns == NULL) {
324 : 0 : return NULL;
325 : : }
326 : :
327 : 1223 : return RB_NEXT(nvme_ns_tree, &nvme_ctrlr->namespaces, ns);
328 : : }
329 : :
330 : : static struct nvme_ctrlr *
331 : 1032 : nvme_ctrlr_get(const struct spdk_nvme_transport_id *trid)
332 : : {
333 : : struct nvme_bdev_ctrlr *nbdev_ctrlr;
334 : 1032 : struct nvme_ctrlr *nvme_ctrlr = NULL;
335 : :
336 [ - + ]: 1032 : pthread_mutex_lock(&g_bdev_nvme_mutex);
337 [ + + ]: 1552 : TAILQ_FOREACH(nbdev_ctrlr, &g_nvme_bdev_ctrlrs, tailq) {
338 : 520 : nvme_ctrlr = nvme_bdev_ctrlr_get_ctrlr(nbdev_ctrlr, trid);
339 [ - + ]: 520 : if (nvme_ctrlr != NULL) {
340 : 0 : break;
341 : : }
342 : : }
343 [ - + ]: 1032 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
344 : :
345 : 1032 : return nvme_ctrlr;
346 : : }
347 : :
348 : : struct nvme_ctrlr *
349 : 1132 : nvme_ctrlr_get_by_name(const char *name)
350 : : {
351 : : struct nvme_bdev_ctrlr *nbdev_ctrlr;
352 : 1132 : struct nvme_ctrlr *nvme_ctrlr = NULL;
353 : :
354 [ - + ]: 1132 : if (name == NULL) {
355 : 0 : return NULL;
356 : : }
357 : :
358 [ - + ]: 1132 : pthread_mutex_lock(&g_bdev_nvme_mutex);
359 : 1132 : nbdev_ctrlr = nvme_bdev_ctrlr_get_by_name(name);
360 [ + + ]: 1132 : if (nbdev_ctrlr != NULL) {
361 : 241 : nvme_ctrlr = TAILQ_FIRST(&nbdev_ctrlr->ctrlrs);
362 : : }
363 [ - + ]: 1132 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
364 : :
365 : 1132 : return nvme_ctrlr;
366 : : }
367 : :
368 : : void
369 : 86 : nvme_bdev_ctrlr_for_each(nvme_bdev_ctrlr_for_each_fn fn, void *ctx)
370 : : {
371 : : struct nvme_bdev_ctrlr *nbdev_ctrlr;
372 : :
373 [ - + ]: 86 : pthread_mutex_lock(&g_bdev_nvme_mutex);
374 [ + + ]: 153 : TAILQ_FOREACH(nbdev_ctrlr, &g_nvme_bdev_ctrlrs, tailq) {
375 : 67 : fn(nbdev_ctrlr, ctx);
376 : : }
377 [ - + ]: 86 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
378 : 86 : }
379 : :
380 : : void
381 : 1395 : nvme_bdev_dump_trid_json(const struct spdk_nvme_transport_id *trid, struct spdk_json_write_ctx *w)
382 : : {
383 : : const char *trtype_str;
384 : : const char *adrfam_str;
385 : :
386 : 1395 : trtype_str = spdk_nvme_transport_id_trtype_str(trid->trtype);
387 [ + - ]: 1395 : if (trtype_str) {
388 : 1395 : spdk_json_write_named_string(w, "trtype", trtype_str);
389 : : }
390 : :
391 : 1395 : adrfam_str = spdk_nvme_transport_id_adrfam_str(trid->adrfam);
392 [ + + ]: 1395 : if (adrfam_str) {
393 : 477 : spdk_json_write_named_string(w, "adrfam", adrfam_str);
394 : : }
395 : :
396 [ + - ]: 1395 : if (trid->traddr[0] != '\0') {
397 : 1395 : spdk_json_write_named_string(w, "traddr", trid->traddr);
398 : : }
399 : :
400 [ + + ]: 1395 : if (trid->trsvcid[0] != '\0') {
401 : 477 : spdk_json_write_named_string(w, "trsvcid", trid->trsvcid);
402 : : }
403 : :
404 [ + + ]: 1395 : if (trid->subnqn[0] != '\0') {
405 : 477 : spdk_json_write_named_string(w, "subnqn", trid->subnqn);
406 : : }
407 : 1395 : }
408 : :
409 : : static void
410 : 1054 : nvme_bdev_ctrlr_delete(struct nvme_bdev_ctrlr *nbdev_ctrlr,
411 : : struct nvme_ctrlr *nvme_ctrlr)
412 : : {
413 : 159 : SPDK_DTRACE_PROBE1(bdev_nvme_ctrlr_delete, nvme_ctrlr->nbdev_ctrlr->name);
414 [ - + ]: 1054 : pthread_mutex_lock(&g_bdev_nvme_mutex);
415 : :
416 [ + + ]: 1054 : TAILQ_REMOVE(&nbdev_ctrlr->ctrlrs, nvme_ctrlr, tailq);
417 [ + + ]: 1054 : if (!TAILQ_EMPTY(&nbdev_ctrlr->ctrlrs)) {
418 [ - + ]: 67 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
419 : :
420 : 67 : return;
421 : : }
422 [ + + ]: 987 : TAILQ_REMOVE(&g_nvme_bdev_ctrlrs, nbdev_ctrlr, tailq);
423 : :
424 [ - + ]: 987 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
425 : :
426 [ - + ]: 987 : assert(TAILQ_EMPTY(&nbdev_ctrlr->bdevs));
427 : :
428 : 987 : free(nbdev_ctrlr->name);
429 : 987 : free(nbdev_ctrlr);
430 : : }
431 : :
432 : : static void
433 : 1058 : _nvme_ctrlr_delete(struct nvme_ctrlr *nvme_ctrlr)
434 : : {
435 : : struct nvme_path_id *path_id, *tmp_path;
436 : : struct nvme_ns *ns, *tmp_ns;
437 : :
438 : 1058 : free(nvme_ctrlr->copied_ana_desc);
439 : 1058 : spdk_free(nvme_ctrlr->ana_log_page);
440 : :
441 [ + + ]: 1058 : if (nvme_ctrlr->opal_dev) {
442 : 36 : spdk_opal_dev_destruct(nvme_ctrlr->opal_dev);
443 : 36 : nvme_ctrlr->opal_dev = NULL;
444 : : }
445 : :
446 [ + + ]: 1058 : if (nvme_ctrlr->nbdev_ctrlr) {
447 : 1054 : nvme_bdev_ctrlr_delete(nvme_ctrlr->nbdev_ctrlr, nvme_ctrlr);
448 : : }
449 : :
450 [ - + - - ]: 1058 : RB_FOREACH_SAFE(ns, nvme_ns_tree, &nvme_ctrlr->namespaces, tmp_ns) {
451 : 0 : RB_REMOVE(nvme_ns_tree, &nvme_ctrlr->namespaces, ns);
452 : 0 : nvme_ns_free(ns);
453 : : }
454 : :
455 [ + + ]: 2126 : TAILQ_FOREACH_SAFE(path_id, &nvme_ctrlr->trids, link, tmp_path) {
456 [ + + ]: 1068 : TAILQ_REMOVE(&nvme_ctrlr->trids, path_id, link);
457 : 1068 : free(path_id);
458 : : }
459 : :
460 [ - + ]: 1058 : pthread_mutex_destroy(&nvme_ctrlr->mutex);
461 : :
462 : 1058 : free(nvme_ctrlr);
463 : :
464 [ - + ]: 1058 : pthread_mutex_lock(&g_bdev_nvme_mutex);
465 [ + + + + : 1058 : if (g_bdev_nvme_module_finish && TAILQ_EMPTY(&g_nvme_bdev_ctrlrs)) {
+ + ]
466 [ - + ]: 510 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
467 : 510 : spdk_io_device_unregister(&g_nvme_bdev_ctrlrs, NULL);
468 : 510 : spdk_bdev_module_fini_done();
469 : 510 : return;
470 : : }
471 [ - + ]: 548 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
472 : : }
473 : :
474 : : static int
475 : 125249 : nvme_detach_poller(void *arg)
476 : : {
477 : 125249 : struct nvme_ctrlr *nvme_ctrlr = arg;
478 : : int rc;
479 : :
480 : 125249 : rc = spdk_nvme_detach_poll_async(nvme_ctrlr->detach_ctx);
481 [ + + ]: 125249 : if (rc != -EAGAIN) {
482 : 1058 : spdk_poller_unregister(&nvme_ctrlr->reset_detach_poller);
483 : 1058 : _nvme_ctrlr_delete(nvme_ctrlr);
484 : : }
485 : :
486 : 125249 : return SPDK_POLLER_BUSY;
487 : : }
488 : :
489 : : static void
490 : 1058 : nvme_ctrlr_delete(struct nvme_ctrlr *nvme_ctrlr)
491 : : {
492 : : int rc;
493 : :
494 : 1058 : spdk_poller_unregister(&nvme_ctrlr->reconnect_delay_timer);
495 : :
496 : : /* First, unregister the adminq poller, as the driver will poll adminq if necessary */
497 : 1058 : spdk_poller_unregister(&nvme_ctrlr->adminq_timer_poller);
498 : :
499 : : /* If we got here, the reset/detach poller cannot be active */
500 [ - + ]: 1058 : assert(nvme_ctrlr->reset_detach_poller == NULL);
501 : 1058 : nvme_ctrlr->reset_detach_poller = SPDK_POLLER_REGISTER(nvme_detach_poller,
502 : : nvme_ctrlr, 1000);
503 [ - + ]: 1058 : if (nvme_ctrlr->reset_detach_poller == NULL) {
504 : 0 : SPDK_ERRLOG("Failed to register detach poller\n");
505 : 0 : goto error;
506 : : }
507 : :
508 : 1058 : rc = spdk_nvme_detach_async(nvme_ctrlr->ctrlr, &nvme_ctrlr->detach_ctx);
509 [ - + ]: 1058 : if (rc != 0) {
510 : 0 : SPDK_ERRLOG("Failed to detach the NVMe controller\n");
511 : 0 : goto error;
512 : : }
513 : :
514 : 1058 : return;
515 : 0 : error:
516 : : /* We don't have a good way to handle errors here, so just do what we can and delete the
517 : : * controller without detaching the underlying NVMe device.
518 : : */
519 : 0 : spdk_poller_unregister(&nvme_ctrlr->reset_detach_poller);
520 : 0 : _nvme_ctrlr_delete(nvme_ctrlr);
521 : : }
522 : :
523 : : static void
524 : 1054 : nvme_ctrlr_unregister_cb(void *io_device)
525 : : {
526 : 1054 : struct nvme_ctrlr *nvme_ctrlr = io_device;
527 : :
528 : 1054 : nvme_ctrlr_delete(nvme_ctrlr);
529 : 1054 : }
530 : :
531 : : static void
532 : 1054 : nvme_ctrlr_unregister(void *ctx)
533 : : {
534 : 1054 : struct nvme_ctrlr *nvme_ctrlr = ctx;
535 : :
536 : 1054 : spdk_io_device_unregister(nvme_ctrlr, nvme_ctrlr_unregister_cb);
537 : 1054 : }
538 : :
539 : : static bool
540 : 5627 : nvme_ctrlr_can_be_unregistered(struct nvme_ctrlr *nvme_ctrlr)
541 : : {
542 [ + + ]: 5627 : if (!nvme_ctrlr->destruct) {
543 : 3356 : return false;
544 : : }
545 : :
546 [ + + ]: 2271 : if (nvme_ctrlr->ref > 0) {
547 : 1213 : return false;
548 : : }
549 : :
550 [ + + ]: 1058 : if (nvme_ctrlr->resetting) {
551 : 4 : return false;
552 : : }
553 : :
554 [ - + ]: 1054 : if (nvme_ctrlr->ana_log_page_updating) {
555 : 0 : return false;
556 : : }
557 : :
558 [ - + ]: 1054 : if (nvme_ctrlr->io_path_cache_clearing) {
559 : 0 : return false;
560 : : }
561 : :
562 : 1054 : return true;
563 : : }
564 : :
565 : : static void
566 : 4219 : nvme_ctrlr_release(struct nvme_ctrlr *nvme_ctrlr)
567 : : {
568 [ - + ]: 4219 : pthread_mutex_lock(&nvme_ctrlr->mutex);
569 : 731 : SPDK_DTRACE_PROBE2(bdev_nvme_ctrlr_release, nvme_ctrlr->nbdev_ctrlr->name, nvme_ctrlr->ref);
570 : :
571 [ - + ]: 4219 : assert(nvme_ctrlr->ref > 0);
572 : 4219 : nvme_ctrlr->ref--;
573 : :
574 [ + + ]: 4219 : if (!nvme_ctrlr_can_be_unregistered(nvme_ctrlr)) {
575 [ - + ]: 3169 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
576 : 3169 : return;
577 : : }
578 : :
579 [ - + ]: 1050 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
580 : :
581 : 1050 : spdk_thread_exec_msg(nvme_ctrlr->thread, nvme_ctrlr_unregister, nvme_ctrlr);
582 : : }
583 : :
584 : : static void
585 : 632308 : bdev_nvme_clear_current_io_path(struct nvme_bdev_channel *nbdev_ch)
586 : : {
587 : 632308 : nbdev_ch->current_io_path = NULL;
588 : 632308 : nbdev_ch->rr_counter = 0;
589 : 632308 : }
590 : :
591 : : static struct nvme_io_path *
592 : 32 : _bdev_nvme_get_io_path(struct nvme_bdev_channel *nbdev_ch, struct nvme_ns *nvme_ns)
593 : : {
594 : : struct nvme_io_path *io_path;
595 : :
596 [ + + ]: 64 : STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
597 [ + + ]: 60 : if (io_path->nvme_ns == nvme_ns) {
598 : 28 : break;
599 : : }
600 : : }
601 : :
602 : 32 : return io_path;
603 : : }
604 : :
605 : : static struct nvme_io_path *
606 : 2072 : nvme_io_path_alloc(void)
607 : : {
608 : : struct nvme_io_path *io_path;
609 : :
610 : 2072 : io_path = calloc(1, sizeof(*io_path));
611 [ - + ]: 2072 : if (io_path == NULL) {
612 : 0 : SPDK_ERRLOG("Failed to alloc io_path.\n");
613 : 0 : return NULL;
614 : : }
615 : :
616 [ - + - + ]: 2072 : if (g_opts.io_path_stat) {
617 : 0 : io_path->stat = calloc(1, sizeof(struct spdk_bdev_io_stat));
618 [ # # ]: 0 : if (io_path->stat == NULL) {
619 : 0 : free(io_path);
620 : 0 : SPDK_ERRLOG("Failed to alloc io_path stat.\n");
621 : 0 : return NULL;
622 : : }
623 : 0 : spdk_bdev_reset_io_stat(io_path->stat, SPDK_BDEV_RESET_STAT_MAXMIN);
624 : : }
625 : :
626 : 2072 : return io_path;
627 : : }
628 : :
629 : : static void
630 : 2072 : nvme_io_path_free(struct nvme_io_path *io_path)
631 : : {
632 : 2072 : free(io_path->stat);
633 : 2072 : free(io_path);
634 : 2072 : }
635 : :
636 : : static int
637 : 2072 : _bdev_nvme_add_io_path(struct nvme_bdev_channel *nbdev_ch, struct nvme_ns *nvme_ns)
638 : : {
639 : : struct nvme_io_path *io_path;
640 : : struct spdk_io_channel *ch;
641 : : struct nvme_ctrlr_channel *ctrlr_ch;
642 : : struct nvme_qpair *nvme_qpair;
643 : :
644 : 2072 : io_path = nvme_io_path_alloc();
645 [ - + ]: 2072 : if (io_path == NULL) {
646 : 0 : return -ENOMEM;
647 : : }
648 : :
649 : 2072 : io_path->nvme_ns = nvme_ns;
650 : :
651 : 2072 : ch = spdk_get_io_channel(nvme_ns->ctrlr);
652 [ - + ]: 2072 : if (ch == NULL) {
653 : 0 : nvme_io_path_free(io_path);
654 : 0 : SPDK_ERRLOG("Failed to alloc io_channel.\n");
655 : 0 : return -ENOMEM;
656 : : }
657 : :
658 : 2072 : ctrlr_ch = spdk_io_channel_get_ctx(ch);
659 : :
660 : 2072 : nvme_qpair = ctrlr_ch->qpair;
661 [ - + ]: 2072 : assert(nvme_qpair != NULL);
662 : :
663 : 2072 : io_path->qpair = nvme_qpair;
664 : 2072 : TAILQ_INSERT_TAIL(&nvme_qpair->io_path_list, io_path, tailq);
665 : :
666 : 2072 : io_path->nbdev_ch = nbdev_ch;
667 : 2072 : STAILQ_INSERT_TAIL(&nbdev_ch->io_path_list, io_path, stailq);
668 : :
669 : 2072 : bdev_nvme_clear_current_io_path(nbdev_ch);
670 : :
671 : 2072 : return 0;
672 : : }
673 : :
674 : : static void
675 : 2072 : bdev_nvme_clear_retry_io_path(struct nvme_bdev_channel *nbdev_ch,
676 : : struct nvme_io_path *io_path)
677 : : {
678 : : struct spdk_bdev_io *bdev_io;
679 : : struct nvme_bdev_io *bio;
680 : :
681 [ + + ]: 2076 : TAILQ_FOREACH(bdev_io, &nbdev_ch->retry_io_list, module_link) {
682 : 4 : bio = (struct nvme_bdev_io *)bdev_io->driver_ctx;
683 [ + - ]: 4 : if (bio->io_path == io_path) {
684 : 4 : bio->io_path = NULL;
685 : : }
686 : : }
687 : 2072 : }
688 : :
689 : : static void
690 : 2072 : _bdev_nvme_delete_io_path(struct nvme_bdev_channel *nbdev_ch, struct nvme_io_path *io_path)
691 : : {
692 : : struct spdk_io_channel *ch;
693 : : struct nvme_qpair *nvme_qpair;
694 : : struct nvme_ctrlr_channel *ctrlr_ch;
695 : : struct nvme_bdev *nbdev;
696 : :
697 : 2072 : nbdev = spdk_io_channel_get_io_device(spdk_io_channel_from_ctx(nbdev_ch));
698 : :
699 : : /* Add the statistics to nvme_ns before this path is destroyed. */
700 [ - + ]: 2072 : pthread_mutex_lock(&nbdev->mutex);
701 [ + + - + : 2072 : if (nbdev->ref != 0 && io_path->nvme_ns->stat != NULL && io_path->stat != NULL) {
- - ]
702 : 0 : spdk_bdev_add_io_stat(io_path->nvme_ns->stat, io_path->stat);
703 : : }
704 [ - + ]: 2072 : pthread_mutex_unlock(&nbdev->mutex);
705 : :
706 : 2072 : bdev_nvme_clear_current_io_path(nbdev_ch);
707 : 2072 : bdev_nvme_clear_retry_io_path(nbdev_ch, io_path);
708 : :
709 [ + + + + : 2072 : STAILQ_REMOVE(&nbdev_ch->io_path_list, io_path, nvme_io_path, stailq);
- + + + ]
710 : 2072 : io_path->nbdev_ch = NULL;
711 : :
712 : 2072 : nvme_qpair = io_path->qpair;
713 [ - + ]: 2072 : assert(nvme_qpair != NULL);
714 : :
715 : 2072 : ctrlr_ch = nvme_qpair->ctrlr_ch;
716 [ - + ]: 2072 : assert(ctrlr_ch != NULL);
717 : :
718 : 2072 : ch = spdk_io_channel_from_ctx(ctrlr_ch);
719 : 2072 : spdk_put_io_channel(ch);
720 : :
721 : : /* After an io_path is removed, I/Os submitted to it may complete and update statistics
722 : : * of the io_path. To avoid heap-use-after-free error from this case, do not free the
723 : : * io_path here but free the io_path when the associated qpair is freed. It is ensured
724 : : * that all I/Os submitted to the io_path are completed when the associated qpair is freed.
725 : : */
726 : 2072 : }
727 : :
728 : : static void
729 : 2018 : _bdev_nvme_delete_io_paths(struct nvme_bdev_channel *nbdev_ch)
730 : : {
731 : : struct nvme_io_path *io_path, *tmp_io_path;
732 : :
733 [ + + ]: 4082 : STAILQ_FOREACH_SAFE(io_path, &nbdev_ch->io_path_list, stailq, tmp_io_path) {
734 : 2064 : _bdev_nvme_delete_io_path(nbdev_ch, io_path);
735 : : }
736 : 2018 : }
737 : :
738 : : static int
739 : 2018 : bdev_nvme_create_bdev_channel_cb(void *io_device, void *ctx_buf)
740 : : {
741 : 2018 : struct nvme_bdev_channel *nbdev_ch = ctx_buf;
742 : 2018 : struct nvme_bdev *nbdev = io_device;
743 : : struct nvme_ns *nvme_ns;
744 : : int rc;
745 : :
746 : 2018 : STAILQ_INIT(&nbdev_ch->io_path_list);
747 : 2018 : TAILQ_INIT(&nbdev_ch->retry_io_list);
748 : :
749 [ - + ]: 2018 : pthread_mutex_lock(&nbdev->mutex);
750 : :
751 : 2018 : nbdev_ch->mp_policy = nbdev->mp_policy;
752 : 2018 : nbdev_ch->mp_selector = nbdev->mp_selector;
753 : 2018 : nbdev_ch->rr_min_io = nbdev->rr_min_io;
754 : :
755 [ + + ]: 4082 : TAILQ_FOREACH(nvme_ns, &nbdev->nvme_ns_list, tailq) {
756 : 2064 : rc = _bdev_nvme_add_io_path(nbdev_ch, nvme_ns);
757 [ - + ]: 2064 : if (rc != 0) {
758 [ # # ]: 0 : pthread_mutex_unlock(&nbdev->mutex);
759 : :
760 : 0 : _bdev_nvme_delete_io_paths(nbdev_ch);
761 : 0 : return rc;
762 : : }
763 : : }
764 [ - + ]: 2018 : pthread_mutex_unlock(&nbdev->mutex);
765 : :
766 : 2018 : return 0;
767 : : }
768 : :
769 : : /* If cpl != NULL, complete the bdev_io with nvme status based on 'cpl'.
770 : : * If cpl == NULL, complete the bdev_io with bdev status based on 'status'.
771 : : */
772 : : static inline void
773 : 38135826 : __bdev_nvme_io_complete(struct spdk_bdev_io *bdev_io, enum spdk_bdev_io_status status,
774 : : const struct spdk_nvme_cpl *cpl)
775 : : {
776 [ + + + + ]: 38135826 : spdk_trace_record(TRACE_BDEV_NVME_IO_DONE, 0, 0, (uintptr_t)bdev_io->driver_ctx,
777 : : (uintptr_t)bdev_io);
778 [ + + ]: 38135826 : if (cpl) {
779 : 35567580 : spdk_bdev_io_complete_nvme_status(bdev_io, cpl->cdw0, cpl->status.sct, cpl->status.sc);
780 : : } else {
781 : 2568246 : spdk_bdev_io_complete(bdev_io, status);
782 : : }
783 : 38135826 : }
784 : :
785 : : static void bdev_nvme_abort_retry_ios(struct nvme_bdev_channel *nbdev_ch);
786 : :
787 : : static void
788 : 2018 : bdev_nvme_destroy_bdev_channel_cb(void *io_device, void *ctx_buf)
789 : : {
790 : 2018 : struct nvme_bdev_channel *nbdev_ch = ctx_buf;
791 : :
792 : 2018 : bdev_nvme_abort_retry_ios(nbdev_ch);
793 : 2018 : _bdev_nvme_delete_io_paths(nbdev_ch);
794 : 2018 : }
795 : :
796 : : static inline bool
797 : 38765182 : bdev_nvme_io_type_is_admin(enum spdk_bdev_io_type io_type)
798 : : {
799 [ + + ]: 38765182 : switch (io_type) {
800 : 50 : case SPDK_BDEV_IO_TYPE_RESET:
801 : : case SPDK_BDEV_IO_TYPE_NVME_ADMIN:
802 : : case SPDK_BDEV_IO_TYPE_ABORT:
803 : 50 : return true;
804 : 38765132 : default:
805 : 38765132 : break;
806 : : }
807 : :
808 : 38765132 : return false;
809 : : }
810 : :
811 : : static inline bool
812 : 4212372 : nvme_ns_is_active(struct nvme_ns *nvme_ns)
813 : : {
814 [ + + + + ]: 4212372 : if (spdk_unlikely(nvme_ns->ana_state_updating)) {
815 : 1316 : return false;
816 : : }
817 : :
818 [ - + ]: 4211056 : if (spdk_unlikely(nvme_ns->ns == NULL)) {
819 : 0 : return false;
820 : : }
821 : :
822 : 4211056 : return true;
823 : : }
824 : :
825 : : static inline bool
826 : 3403730 : nvme_ns_is_accessible(struct nvme_ns *nvme_ns)
827 : : {
828 [ - + ]: 3403730 : if (spdk_unlikely(!nvme_ns_is_active(nvme_ns))) {
829 : 0 : return false;
830 : : }
831 : :
832 [ + - ]: 3403730 : switch (nvme_ns->ana_state) {
833 : 3403730 : case SPDK_NVME_ANA_OPTIMIZED_STATE:
834 : : case SPDK_NVME_ANA_NON_OPTIMIZED_STATE:
835 : 3403730 : return true;
836 : 0 : default:
837 : 0 : break;
838 : : }
839 : :
840 : 0 : return false;
841 : : }
842 : :
843 : : static inline bool
844 : 5796924 : nvme_qpair_is_connected(struct nvme_qpair *nvme_qpair)
845 : : {
846 [ + + ]: 5796924 : if (spdk_unlikely(nvme_qpair->qpair == NULL)) {
847 : 1560439 : return false;
848 : : }
849 : :
850 [ + + ]: 4236485 : if (spdk_unlikely(spdk_nvme_qpair_get_failure_reason(nvme_qpair->qpair) !=
851 : : SPDK_NVME_QPAIR_FAILURE_NONE)) {
852 : 3584 : return false;
853 : : }
854 : :
855 [ + + ]: 4232901 : if (spdk_unlikely(nvme_qpair->ctrlr_ch->reset_iter != NULL)) {
856 : 16993 : return false;
857 : : }
858 : :
859 : 4215908 : return true;
860 : : }
861 : :
862 : : static inline bool
863 : 3403730 : nvme_io_path_is_available(struct nvme_io_path *io_path)
864 : : {
865 [ - + ]: 3403730 : if (spdk_unlikely(!nvme_qpair_is_connected(io_path->qpair))) {
866 : 0 : return false;
867 : : }
868 : :
869 [ - + ]: 3403730 : if (spdk_unlikely(!nvme_ns_is_accessible(io_path->nvme_ns))) {
870 : 0 : return false;
871 : : }
872 : :
873 : 3403730 : return true;
874 : : }
875 : :
876 : : static inline bool
877 : 622971 : nvme_ctrlr_is_failed(struct nvme_ctrlr *nvme_ctrlr)
878 : : {
879 [ + + ]: 622971 : if (nvme_ctrlr->destruct) {
880 : 512 : return true;
881 : : }
882 : :
883 [ + + ]: 622459 : if (nvme_ctrlr->fast_io_fail_timedout) {
884 : 115300 : return true;
885 : : }
886 : :
887 [ + + ]: 507159 : if (nvme_ctrlr->resetting) {
888 [ + + ]: 368623 : if (nvme_ctrlr->opts.reconnect_delay_sec != 0) {
889 : 1040 : return false;
890 : : } else {
891 : 367583 : return true;
892 : : }
893 : : }
894 : :
895 [ + + ]: 138536 : if (nvme_ctrlr->reconnect_is_delayed) {
896 : 4104 : return false;
897 : : }
898 : :
899 [ - + ]: 134432 : if (nvme_ctrlr->disabled) {
900 : 0 : return true;
901 : : }
902 : :
903 [ + + ]: 134432 : if (spdk_nvme_ctrlr_is_failed(nvme_ctrlr->ctrlr)) {
904 : 130912 : return true;
905 : : } else {
906 : 3520 : return false;
907 : : }
908 : : }
909 : :
910 : : static bool
911 : 13252 : nvme_ctrlr_is_available(struct nvme_ctrlr *nvme_ctrlr)
912 : : {
913 [ - + ]: 13252 : if (nvme_ctrlr->destruct) {
914 : 0 : return false;
915 : : }
916 : :
917 [ + + ]: 13252 : if (spdk_nvme_ctrlr_is_failed(nvme_ctrlr->ctrlr)) {
918 : 15 : return false;
919 : : }
920 : :
921 [ + + - + ]: 13237 : if (nvme_ctrlr->resetting || nvme_ctrlr->reconnect_is_delayed) {
922 : 8817 : return false;
923 : : }
924 : :
925 [ - + ]: 4420 : if (nvme_ctrlr->disabled) {
926 : 0 : return false;
927 : : }
928 : :
929 : 4420 : return true;
930 : : }
931 : :
932 : : /* Simulate circular linked list. */
933 : : static inline struct nvme_io_path *
934 : 2958600 : nvme_io_path_get_next(struct nvme_bdev_channel *nbdev_ch, struct nvme_io_path *prev_path)
935 : : {
936 : : struct nvme_io_path *next_path;
937 : :
938 [ + + ]: 2958600 : if (prev_path != NULL) {
939 : 1764585 : next_path = STAILQ_NEXT(prev_path, stailq);
940 [ + + ]: 1764585 : if (next_path != NULL) {
941 : 572604 : return next_path;
942 : : }
943 : : }
944 : :
945 : 2385996 : return STAILQ_FIRST(&nbdev_ch->io_path_list);
946 : : }
947 : :
948 : : static struct nvme_io_path *
949 : 1194043 : _bdev_nvme_find_io_path(struct nvme_bdev_channel *nbdev_ch)
950 : : {
951 : 1194043 : struct nvme_io_path *io_path, *start, *non_optimized = NULL;
952 : :
953 : 1194043 : start = nvme_io_path_get_next(nbdev_ch, nbdev_ch->current_io_path);
954 : :
955 : 1194043 : io_path = start;
956 : : do {
957 [ + + + + ]: 1766639 : if (spdk_likely(nvme_qpair_is_connected(io_path->qpair) &&
958 : : nvme_ns_is_active(io_path->nvme_ns))) {
959 [ + + + ]: 807278 : switch (io_path->nvme_ns->ana_state) {
960 : 2082 : case SPDK_NVME_ANA_OPTIMIZED_STATE:
961 : 2082 : nbdev_ch->current_io_path = io_path;
962 : 2082 : return io_path;
963 : 570536 : case SPDK_NVME_ANA_NON_OPTIMIZED_STATE:
964 [ + + ]: 570536 : if (non_optimized == NULL) {
965 : 570524 : non_optimized = io_path;
966 : : }
967 : 570536 : break;
968 : 234660 : default:
969 : 234660 : break;
970 : : }
971 : 26 : }
972 : 1764557 : io_path = nvme_io_path_get_next(nbdev_ch, io_path);
973 [ + + ]: 1764557 : } while (io_path != start);
974 : :
975 [ + + ]: 1191961 : if (nbdev_ch->mp_policy == BDEV_NVME_MP_POLICY_ACTIVE_ACTIVE) {
976 : : /* We come here only if there is no optimized path. Cache even non_optimized
977 : : * path for load balance across multiple non_optimized paths.
978 : : */
979 : 4 : nbdev_ch->current_io_path = non_optimized;
980 : : }
981 : :
982 : 1191961 : return non_optimized;
983 : : }
984 : :
985 : : static struct nvme_io_path *
986 : 16 : _bdev_nvme_find_io_path_min_qd(struct nvme_bdev_channel *nbdev_ch)
987 : : {
988 : : struct nvme_io_path *io_path;
989 : 16 : struct nvme_io_path *optimized = NULL, *non_optimized = NULL;
990 : 16 : uint32_t opt_min_qd = UINT32_MAX, non_opt_min_qd = UINT32_MAX;
991 : : uint32_t num_outstanding_reqs;
992 : :
993 [ + + ]: 64 : STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
994 [ - + ]: 48 : if (spdk_unlikely(!nvme_qpair_is_connected(io_path->qpair))) {
995 : : /* The device is currently resetting. */
996 : 0 : continue;
997 : : }
998 : :
999 [ - + ]: 48 : if (spdk_unlikely(!nvme_ns_is_active(io_path->nvme_ns))) {
1000 : 0 : continue;
1001 : : }
1002 : :
1003 : 48 : num_outstanding_reqs = spdk_nvme_qpair_get_num_outstanding_reqs(io_path->qpair->qpair);
1004 [ + + + ]: 48 : switch (io_path->nvme_ns->ana_state) {
1005 : 24 : case SPDK_NVME_ANA_OPTIMIZED_STATE:
1006 [ + + ]: 24 : if (num_outstanding_reqs < opt_min_qd) {
1007 : 20 : opt_min_qd = num_outstanding_reqs;
1008 : 20 : optimized = io_path;
1009 : : }
1010 : 24 : break;
1011 : 12 : case SPDK_NVME_ANA_NON_OPTIMIZED_STATE:
1012 [ + - ]: 12 : if (num_outstanding_reqs < non_opt_min_qd) {
1013 : 12 : non_opt_min_qd = num_outstanding_reqs;
1014 : 12 : non_optimized = io_path;
1015 : : }
1016 : 12 : break;
1017 : 12 : default:
1018 : 12 : break;
1019 : : }
1020 : : }
1021 : :
1022 : : /* don't cache io path for BDEV_NVME_MP_SELECTOR_QUEUE_DEPTH selector */
1023 [ + + ]: 16 : if (optimized != NULL) {
1024 : 12 : return optimized;
1025 : : }
1026 : :
1027 : 4 : return non_optimized;
1028 : : }
1029 : :
1030 : : static inline struct nvme_io_path *
1031 : 38148174 : bdev_nvme_find_io_path(struct nvme_bdev_channel *nbdev_ch)
1032 : : {
1033 [ + + ]: 38148174 : if (spdk_likely(nbdev_ch->current_io_path != NULL)) {
1034 [ + + ]: 36954143 : if (nbdev_ch->mp_policy == BDEV_NVME_MP_POLICY_ACTIVE_PASSIVE) {
1035 : 36954103 : return nbdev_ch->current_io_path;
1036 [ + - ]: 40 : } else if (nbdev_ch->mp_selector == BDEV_NVME_MP_SELECTOR_ROUND_ROBIN) {
1037 [ + + ]: 40 : if (++nbdev_ch->rr_counter < nbdev_ch->rr_min_io) {
1038 : 12 : return nbdev_ch->current_io_path;
1039 : : }
1040 : 28 : nbdev_ch->rr_counter = 0;
1041 : : }
1042 : : }
1043 : :
1044 [ + + ]: 1194059 : if (nbdev_ch->mp_policy == BDEV_NVME_MP_POLICY_ACTIVE_PASSIVE ||
1045 [ + + ]: 56 : nbdev_ch->mp_selector == BDEV_NVME_MP_SELECTOR_ROUND_ROBIN) {
1046 : 1194043 : return _bdev_nvme_find_io_path(nbdev_ch);
1047 : : } else {
1048 : 16 : return _bdev_nvme_find_io_path_min_qd(nbdev_ch);
1049 : : }
1050 : : }
1051 : :
1052 : : /* Return true if there is any io_path whose qpair is active or ctrlr is not failed,
1053 : : * or false otherwise.
1054 : : *
1055 : : * If any io_path has an active qpair but find_io_path() returned NULL, its namespace
1056 : : * is likely to be non-accessible now but may become accessible.
1057 : : *
1058 : : * If any io_path has an unfailed ctrlr but find_io_path() returned NULL, the ctrlr
1059 : : * is likely to be resetting now but the reset may succeed. A ctrlr is set to unfailed
1060 : : * when starting to reset it but it is set to failed when the reset failed. Hence, if
1061 : : * a ctrlr is unfailed, it is likely that it works fine or is resetting.
1062 : : */
1063 : : static bool
1064 : 626507 : any_io_path_may_become_available(struct nvme_bdev_channel *nbdev_ch)
1065 : : {
1066 : : struct nvme_io_path *io_path;
1067 : :
1068 [ + + ]: 1241838 : STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
1069 [ - + + + ]: 627531 : if (io_path->nvme_ns->ana_transition_timedout) {
1070 : 1024 : continue;
1071 : : }
1072 : :
1073 [ + + ]: 626507 : if (nvme_qpair_is_connected(io_path->qpair) ||
1074 [ + + ]: 622971 : !nvme_ctrlr_is_failed(io_path->qpair->ctrlr)) {
1075 : 12200 : return true;
1076 : : }
1077 : : }
1078 : :
1079 : 614307 : return false;
1080 : : }
1081 : :
1082 : : static void
1083 : 15135 : bdev_nvme_retry_io(struct nvme_bdev_channel *nbdev_ch, struct spdk_bdev_io *bdev_io)
1084 : : {
1085 : 15135 : struct nvme_bdev_io *nbdev_io = (struct nvme_bdev_io *)bdev_io->driver_ctx;
1086 : : struct spdk_io_channel *ch;
1087 : :
1088 [ + + + - ]: 15135 : if (nbdev_io->io_path != NULL && nvme_io_path_is_available(nbdev_io->io_path)) {
1089 : 2935 : _bdev_nvme_submit_request(nbdev_ch, bdev_io);
1090 : : } else {
1091 : 12200 : ch = spdk_io_channel_from_ctx(nbdev_ch);
1092 : 12200 : bdev_nvme_submit_request(ch, bdev_io);
1093 : : }
1094 : 15135 : }
1095 : :
1096 : : static int
1097 : 3344 : bdev_nvme_retry_ios(void *arg)
1098 : : {
1099 : 3344 : struct nvme_bdev_channel *nbdev_ch = arg;
1100 : : struct spdk_bdev_io *bdev_io, *tmp_bdev_io;
1101 : : struct nvme_bdev_io *bio;
1102 : : uint64_t now, delay_us;
1103 : :
1104 : 3344 : now = spdk_get_ticks();
1105 : :
1106 [ + + ]: 18479 : TAILQ_FOREACH_SAFE(bdev_io, &nbdev_ch->retry_io_list, module_link, tmp_bdev_io) {
1107 : 15455 : bio = (struct nvme_bdev_io *)bdev_io->driver_ctx;
1108 [ + + ]: 15455 : if (bio->retry_ticks > now) {
1109 : 320 : break;
1110 : : }
1111 : :
1112 [ + + ]: 15135 : TAILQ_REMOVE(&nbdev_ch->retry_io_list, bdev_io, module_link);
1113 : :
1114 : 15135 : bdev_nvme_retry_io(nbdev_ch, bdev_io);
1115 : : }
1116 : :
1117 : 3344 : spdk_poller_unregister(&nbdev_ch->retry_io_poller);
1118 : :
1119 : 3344 : bdev_io = TAILQ_FIRST(&nbdev_ch->retry_io_list);
1120 [ + + ]: 3344 : if (bdev_io != NULL) {
1121 : 332 : bio = (struct nvme_bdev_io *)bdev_io->driver_ctx;
1122 : :
1123 [ - + ]: 332 : delay_us = (bio->retry_ticks - now) * SPDK_SEC_TO_USEC / spdk_get_ticks_hz();
1124 : :
1125 : 332 : nbdev_ch->retry_io_poller = SPDK_POLLER_REGISTER(bdev_nvme_retry_ios, nbdev_ch,
1126 : : delay_us);
1127 : : }
1128 : :
1129 : 3344 : return SPDK_POLLER_BUSY;
1130 : : }
1131 : :
1132 : : static void
1133 : 15139 : bdev_nvme_queue_retry_io(struct nvme_bdev_channel *nbdev_ch,
1134 : : struct nvme_bdev_io *bio, uint64_t delay_ms)
1135 : : {
1136 : 15139 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
1137 : : struct spdk_bdev_io *tmp_bdev_io;
1138 : : struct nvme_bdev_io *tmp_bio;
1139 : :
1140 : 15139 : bio->retry_ticks = spdk_get_ticks() + delay_ms * spdk_get_ticks_hz() / 1000ULL;
1141 : :
1142 [ + + ]: 28281 : TAILQ_FOREACH_REVERSE(tmp_bdev_io, &nbdev_ch->retry_io_list, retry_io_head, module_link) {
1143 : 25247 : tmp_bio = (struct nvme_bdev_io *)tmp_bdev_io->driver_ctx;
1144 : :
1145 [ + + ]: 25247 : if (tmp_bio->retry_ticks <= bio->retry_ticks) {
1146 [ + + ]: 12105 : TAILQ_INSERT_AFTER(&nbdev_ch->retry_io_list, tmp_bdev_io, bdev_io,
1147 : : module_link);
1148 : 12105 : return;
1149 : : }
1150 : : }
1151 : :
1152 : : /* No earlier I/Os were found. This I/O must be the new head. */
1153 [ + + ]: 3034 : TAILQ_INSERT_HEAD(&nbdev_ch->retry_io_list, bdev_io, module_link);
1154 : :
1155 : 3034 : spdk_poller_unregister(&nbdev_ch->retry_io_poller);
1156 : :
1157 : 3034 : nbdev_ch->retry_io_poller = SPDK_POLLER_REGISTER(bdev_nvme_retry_ios, nbdev_ch,
1158 : : delay_ms * 1000ULL);
1159 : : }
1160 : :
1161 : : static void
1162 : 2094 : bdev_nvme_abort_retry_ios(struct nvme_bdev_channel *nbdev_ch)
1163 : : {
1164 : : struct spdk_bdev_io *bdev_io, *tmp_io;
1165 : :
1166 [ - + ]: 2094 : TAILQ_FOREACH_SAFE(bdev_io, &nbdev_ch->retry_io_list, module_link, tmp_io) {
1167 [ # # ]: 0 : TAILQ_REMOVE(&nbdev_ch->retry_io_list, bdev_io, module_link);
1168 : 0 : __bdev_nvme_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_ABORTED, NULL);
1169 : : }
1170 : :
1171 : 2094 : spdk_poller_unregister(&nbdev_ch->retry_io_poller);
1172 : 2094 : }
1173 : :
1174 : : static int
1175 : 7154 : bdev_nvme_abort_retry_io(struct nvme_bdev_channel *nbdev_ch,
1176 : : struct nvme_bdev_io *bio_to_abort)
1177 : : {
1178 : : struct spdk_bdev_io *bdev_io_to_abort;
1179 : :
1180 [ + + ]: 7154 : TAILQ_FOREACH(bdev_io_to_abort, &nbdev_ch->retry_io_list, module_link) {
1181 [ + - ]: 4 : if ((struct nvme_bdev_io *)bdev_io_to_abort->driver_ctx == bio_to_abort) {
1182 [ - + ]: 4 : TAILQ_REMOVE(&nbdev_ch->retry_io_list, bdev_io_to_abort, module_link);
1183 : 4 : __bdev_nvme_io_complete(bdev_io_to_abort, SPDK_BDEV_IO_STATUS_ABORTED, NULL);
1184 : 4 : return 0;
1185 : : }
1186 : : }
1187 : :
1188 : 7150 : return -ENOENT;
1189 : : }
1190 : :
1191 : : static void
1192 : 8081 : bdev_nvme_update_nvme_error_stat(struct spdk_bdev_io *bdev_io, const struct spdk_nvme_cpl *cpl)
1193 : : {
1194 : : struct nvme_bdev *nbdev;
1195 : : uint16_t sct, sc;
1196 : :
1197 [ + + - + ]: 8081 : assert(spdk_nvme_cpl_is_error(cpl));
1198 : :
1199 : 8081 : nbdev = bdev_io->bdev->ctxt;
1200 : :
1201 [ + + ]: 8081 : if (nbdev->err_stat == NULL) {
1202 : 5206 : return;
1203 : : }
1204 : :
1205 : 2875 : sct = cpl->status.sct;
1206 : 2875 : sc = cpl->status.sc;
1207 : :
1208 [ - + ]: 2875 : pthread_mutex_lock(&nbdev->mutex);
1209 : :
1210 : 2875 : nbdev->err_stat->status_type[sct]++;
1211 [ + - ]: 2875 : switch (sct) {
1212 : 2875 : case SPDK_NVME_SCT_GENERIC:
1213 : : case SPDK_NVME_SCT_COMMAND_SPECIFIC:
1214 : : case SPDK_NVME_SCT_MEDIA_ERROR:
1215 : : case SPDK_NVME_SCT_PATH:
1216 : 2875 : nbdev->err_stat->status[sct][sc]++;
1217 : 2875 : break;
1218 : 0 : default:
1219 : 0 : break;
1220 : : }
1221 : :
1222 [ - + ]: 2875 : pthread_mutex_unlock(&nbdev->mutex);
1223 : : }
1224 : :
1225 : : static inline void
1226 : 35567392 : bdev_nvme_update_io_path_stat(struct nvme_bdev_io *bio)
1227 : : {
1228 : 35567392 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
1229 : 35567392 : uint64_t num_blocks = bdev_io->u.bdev.num_blocks;
1230 : 35567392 : uint32_t blocklen = bdev_io->bdev->blocklen;
1231 : : struct spdk_bdev_io_stat *stat;
1232 : : uint64_t tsc_diff;
1233 : :
1234 [ + - ]: 35567392 : if (bio->io_path->stat == NULL) {
1235 : 35567392 : return;
1236 : : }
1237 : :
1238 : 0 : tsc_diff = spdk_get_ticks() - bio->submit_tsc;
1239 : 0 : stat = bio->io_path->stat;
1240 : :
1241 [ # # # # : 0 : switch (bdev_io->type) {
# # ]
1242 : 0 : case SPDK_BDEV_IO_TYPE_READ:
1243 : 0 : stat->bytes_read += num_blocks * blocklen;
1244 : 0 : stat->num_read_ops++;
1245 : 0 : stat->read_latency_ticks += tsc_diff;
1246 [ # # ]: 0 : if (stat->max_read_latency_ticks < tsc_diff) {
1247 : 0 : stat->max_read_latency_ticks = tsc_diff;
1248 : : }
1249 [ # # ]: 0 : if (stat->min_read_latency_ticks > tsc_diff) {
1250 : 0 : stat->min_read_latency_ticks = tsc_diff;
1251 : : }
1252 : 0 : break;
1253 : 0 : case SPDK_BDEV_IO_TYPE_WRITE:
1254 : 0 : stat->bytes_written += num_blocks * blocklen;
1255 : 0 : stat->num_write_ops++;
1256 : 0 : stat->write_latency_ticks += tsc_diff;
1257 [ # # ]: 0 : if (stat->max_write_latency_ticks < tsc_diff) {
1258 : 0 : stat->max_write_latency_ticks = tsc_diff;
1259 : : }
1260 [ # # ]: 0 : if (stat->min_write_latency_ticks > tsc_diff) {
1261 : 0 : stat->min_write_latency_ticks = tsc_diff;
1262 : : }
1263 : 0 : break;
1264 : 0 : case SPDK_BDEV_IO_TYPE_UNMAP:
1265 : 0 : stat->bytes_unmapped += num_blocks * blocklen;
1266 : 0 : stat->num_unmap_ops++;
1267 : 0 : stat->unmap_latency_ticks += tsc_diff;
1268 [ # # ]: 0 : if (stat->max_unmap_latency_ticks < tsc_diff) {
1269 : 0 : stat->max_unmap_latency_ticks = tsc_diff;
1270 : : }
1271 [ # # ]: 0 : if (stat->min_unmap_latency_ticks > tsc_diff) {
1272 : 0 : stat->min_unmap_latency_ticks = tsc_diff;
1273 : : }
1274 : 0 : break;
1275 : 0 : case SPDK_BDEV_IO_TYPE_ZCOPY:
1276 : : /* Track the data in the start phase only */
1277 [ # # ]: 0 : if (!bdev_io->u.bdev.zcopy.start) {
1278 : 0 : break;
1279 : : }
1280 [ # # ]: 0 : if (bdev_io->u.bdev.zcopy.populate) {
1281 : 0 : stat->bytes_read += num_blocks * blocklen;
1282 : 0 : stat->num_read_ops++;
1283 : 0 : stat->read_latency_ticks += tsc_diff;
1284 [ # # ]: 0 : if (stat->max_read_latency_ticks < tsc_diff) {
1285 : 0 : stat->max_read_latency_ticks = tsc_diff;
1286 : : }
1287 [ # # ]: 0 : if (stat->min_read_latency_ticks > tsc_diff) {
1288 : 0 : stat->min_read_latency_ticks = tsc_diff;
1289 : : }
1290 : : } else {
1291 : 0 : stat->bytes_written += num_blocks * blocklen;
1292 : 0 : stat->num_write_ops++;
1293 : 0 : stat->write_latency_ticks += tsc_diff;
1294 [ # # ]: 0 : if (stat->max_write_latency_ticks < tsc_diff) {
1295 : 0 : stat->max_write_latency_ticks = tsc_diff;
1296 : : }
1297 [ # # ]: 0 : if (stat->min_write_latency_ticks > tsc_diff) {
1298 : 0 : stat->min_write_latency_ticks = tsc_diff;
1299 : : }
1300 : : }
1301 : 0 : break;
1302 : 0 : case SPDK_BDEV_IO_TYPE_COPY:
1303 : 0 : stat->bytes_copied += num_blocks * blocklen;
1304 : 0 : stat->num_copy_ops++;
1305 : 0 : stat->copy_latency_ticks += tsc_diff;
1306 [ # # ]: 0 : if (stat->max_copy_latency_ticks < tsc_diff) {
1307 : 0 : stat->max_copy_latency_ticks = tsc_diff;
1308 : : }
1309 [ # # ]: 0 : if (stat->min_copy_latency_ticks > tsc_diff) {
1310 : 0 : stat->min_copy_latency_ticks = tsc_diff;
1311 : : }
1312 : 0 : break;
1313 : 0 : default:
1314 : 0 : break;
1315 : : }
1316 : : }
1317 : :
1318 : : static bool
1319 : 8003 : bdev_nvme_check_retry_io(struct nvme_bdev_io *bio,
1320 : : const struct spdk_nvme_cpl *cpl,
1321 : : struct nvme_bdev_channel *nbdev_ch,
1322 : : uint64_t *_delay_ms)
1323 : : {
1324 : 8003 : struct nvme_io_path *io_path = bio->io_path;
1325 : 8003 : struct nvme_ctrlr *nvme_ctrlr = io_path->qpair->ctrlr;
1326 : : const struct spdk_nvme_ctrlr_data *cdata;
1327 : :
1328 [ + + ]: 8003 : if (spdk_nvme_cpl_is_path_error(cpl) ||
1329 [ + + + + ]: 7295 : spdk_nvme_cpl_is_aborted_sq_deletion(cpl) ||
1330 [ + - ]: 2939 : !nvme_io_path_is_available(io_path) ||
1331 [ - + ]: 2939 : !nvme_ctrlr_is_available(nvme_ctrlr)) {
1332 : 5064 : bdev_nvme_clear_current_io_path(nbdev_ch);
1333 : 5064 : bio->io_path = NULL;
1334 [ + + + - : 5064 : if (spdk_nvme_cpl_is_ana_error(cpl)) {
+ + - + ]
1335 [ + + ]: 704 : if (nvme_ctrlr_read_ana_log_page(nvme_ctrlr) == 0) {
1336 : 10 : io_path->nvme_ns->ana_state_updating = true;
1337 : : }
1338 : : }
1339 [ + + ]: 5064 : if (!any_io_path_may_become_available(nbdev_ch)) {
1340 : 64 : return false;
1341 : : }
1342 : 5000 : *_delay_ms = 0;
1343 : : } else {
1344 : 2939 : bio->retry_count++;
1345 : :
1346 : 2939 : cdata = spdk_nvme_ctrlr_get_data(nvme_ctrlr->ctrlr);
1347 : :
1348 [ + + ]: 2939 : if (cpl->status.crd != 0) {
1349 : 4 : *_delay_ms = cdata->crdt[cpl->status.crd] * 100;
1350 : : } else {
1351 : 2935 : *_delay_ms = 0;
1352 : : }
1353 : : }
1354 : :
1355 : 7939 : return true;
1356 : : }
1357 : :
1358 : : static inline void
1359 : 35575473 : bdev_nvme_io_complete_nvme_status(struct nvme_bdev_io *bio,
1360 : : const struct spdk_nvme_cpl *cpl)
1361 : : {
1362 : 35575473 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
1363 : : struct nvme_bdev_channel *nbdev_ch;
1364 : 8767303 : uint64_t delay_ms;
1365 : :
1366 [ - + ]: 35575473 : assert(!bdev_nvme_io_type_is_admin(bdev_io->type));
1367 : :
1368 [ + + + + ]: 35575473 : if (spdk_likely(spdk_nvme_cpl_is_success(cpl))) {
1369 : 35567392 : bdev_nvme_update_io_path_stat(bio);
1370 : 35567392 : goto complete;
1371 : : }
1372 : :
1373 : : /* Update error counts before deciding if retry is needed.
1374 : : * Hence, error counts may be more than the number of I/O errors.
1375 : : */
1376 : 8081 : bdev_nvme_update_nvme_error_stat(bdev_io, cpl);
1377 : :
1378 [ + + + + : 8081 : if (cpl->status.dnr != 0 || spdk_nvme_cpl_is_aborted_by_request(cpl) ||
+ + ]
1379 [ + + + + ]: 8023 : (g_opts.bdev_retry_count != -1 && bio->retry_count >= g_opts.bdev_retry_count)) {
1380 : 78 : goto complete;
1381 : : }
1382 : :
1383 : : /* At this point we don't know whether the sequence was successfully executed or not, so we
1384 : : * cannot retry the IO */
1385 [ - + ]: 8003 : if (bdev_io->u.bdev.accel_sequence != NULL) {
1386 : 0 : goto complete;
1387 : : }
1388 : :
1389 : 8003 : nbdev_ch = spdk_io_channel_get_ctx(spdk_bdev_io_get_io_channel(bdev_io));
1390 : :
1391 [ + + ]: 8003 : if (bdev_nvme_check_retry_io(bio, cpl, nbdev_ch, &delay_ms)) {
1392 : 7939 : bdev_nvme_queue_retry_io(nbdev_ch, bio, delay_ms);
1393 : 7939 : return;
1394 : : }
1395 : :
1396 : 8767339 : complete:
1397 : 35567534 : bio->retry_count = 0;
1398 : 35567534 : bio->submit_tsc = 0;
1399 : 35567534 : bdev_io->u.bdev.accel_sequence = NULL;
1400 : 35567534 : __bdev_nvme_io_complete(bdev_io, 0, cpl);
1401 : : }
1402 : :
1403 : : static inline void
1404 : 2568216 : bdev_nvme_io_complete(struct nvme_bdev_io *bio, int rc)
1405 : : {
1406 : 2568216 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
1407 : : struct nvme_bdev_channel *nbdev_ch;
1408 : : enum spdk_bdev_io_status io_status;
1409 : :
1410 [ - + ]: 2568216 : assert(!bdev_nvme_io_type_is_admin(bdev_io->type));
1411 : :
1412 [ + + + - ]: 2568216 : switch (rc) {
1413 : 1752996 : case 0:
1414 : 1752996 : io_status = SPDK_BDEV_IO_STATUS_SUCCESS;
1415 : 1752996 : break;
1416 : 193777 : case -ENOMEM:
1417 : 193777 : io_status = SPDK_BDEV_IO_STATUS_NOMEM;
1418 : 193777 : break;
1419 : 621443 : case -ENXIO:
1420 [ + + + - ]: 621443 : if (g_opts.bdev_retry_count == -1 || bio->retry_count < g_opts.bdev_retry_count) {
1421 : 621443 : nbdev_ch = spdk_io_channel_get_ctx(spdk_bdev_io_get_io_channel(bdev_io));
1422 : :
1423 : 621443 : bdev_nvme_clear_current_io_path(nbdev_ch);
1424 : 621443 : bio->io_path = NULL;
1425 : :
1426 [ + + ]: 621443 : if (any_io_path_may_become_available(nbdev_ch)) {
1427 : 7200 : bdev_nvme_queue_retry_io(nbdev_ch, bio, 1000ULL);
1428 : 7200 : return;
1429 : : }
1430 : : }
1431 : :
1432 : : /* fallthrough */
1433 : : default:
1434 : 614243 : spdk_accel_sequence_abort(bdev_io->u.bdev.accel_sequence);
1435 : 614243 : bdev_io->u.bdev.accel_sequence = NULL;
1436 : 614243 : io_status = SPDK_BDEV_IO_STATUS_FAILED;
1437 : 614243 : break;
1438 : : }
1439 : :
1440 : 2561016 : bio->retry_count = 0;
1441 : 2561016 : bio->submit_tsc = 0;
1442 : 2561016 : __bdev_nvme_io_complete(bdev_io, io_status, NULL);
1443 : : }
1444 : :
1445 : : static inline void
1446 : 16 : bdev_nvme_admin_complete(struct nvme_bdev_io *bio, int rc)
1447 : : {
1448 : 16 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
1449 : : enum spdk_bdev_io_status io_status;
1450 : :
1451 [ + - + ]: 16 : switch (rc) {
1452 : 4 : case 0:
1453 : 4 : io_status = SPDK_BDEV_IO_STATUS_SUCCESS;
1454 : 4 : break;
1455 : 0 : case -ENOMEM:
1456 : 0 : io_status = SPDK_BDEV_IO_STATUS_NOMEM;
1457 : 0 : break;
1458 : 12 : case -ENXIO:
1459 : : /* fallthrough */
1460 : : default:
1461 : 12 : io_status = SPDK_BDEV_IO_STATUS_FAILED;
1462 : 12 : break;
1463 : : }
1464 : :
1465 : 16 : __bdev_nvme_io_complete(bdev_io, io_status, NULL);
1466 : 16 : }
1467 : :
1468 : : static void
1469 : 695 : bdev_nvme_clear_io_path_caches_done(struct spdk_io_channel_iter *i, int status)
1470 : : {
1471 : 695 : struct nvme_ctrlr *nvme_ctrlr = spdk_io_channel_iter_get_io_device(i);
1472 : :
1473 [ - + ]: 695 : pthread_mutex_lock(&nvme_ctrlr->mutex);
1474 : :
1475 [ - + ]: 695 : assert(nvme_ctrlr->io_path_cache_clearing == true);
1476 : 695 : nvme_ctrlr->io_path_cache_clearing = false;
1477 : :
1478 [ + - ]: 695 : if (!nvme_ctrlr_can_be_unregistered(nvme_ctrlr)) {
1479 [ - + ]: 695 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
1480 : 695 : return;
1481 : : }
1482 : :
1483 [ # # ]: 0 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
1484 : :
1485 : 0 : nvme_ctrlr_unregister(nvme_ctrlr);
1486 : : }
1487 : :
1488 : : static void
1489 : 8001 : _bdev_nvme_clear_io_path_cache(struct nvme_qpair *nvme_qpair)
1490 : : {
1491 : : struct nvme_io_path *io_path;
1492 : :
1493 [ + + ]: 13748 : TAILQ_FOREACH(io_path, &nvme_qpair->io_path_list, tailq) {
1494 [ + + ]: 5747 : if (io_path->nbdev_ch == NULL) {
1495 : 4102 : continue;
1496 : : }
1497 : 1645 : bdev_nvme_clear_current_io_path(io_path->nbdev_ch);
1498 : : }
1499 : 8001 : }
1500 : :
1501 : : static void
1502 : 673 : bdev_nvme_clear_io_path_cache(struct spdk_io_channel_iter *i)
1503 : : {
1504 : 673 : struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
1505 : 673 : struct nvme_ctrlr_channel *ctrlr_ch = spdk_io_channel_get_ctx(_ch);
1506 : :
1507 [ - + ]: 673 : assert(ctrlr_ch->qpair != NULL);
1508 : :
1509 : 673 : _bdev_nvme_clear_io_path_cache(ctrlr_ch->qpair);
1510 : :
1511 : 673 : spdk_for_each_channel_continue(i, 0);
1512 : 673 : }
1513 : :
1514 : : static void
1515 : 9511 : bdev_nvme_clear_io_path_caches(struct nvme_ctrlr *nvme_ctrlr)
1516 : : {
1517 [ - + ]: 9511 : pthread_mutex_lock(&nvme_ctrlr->mutex);
1518 [ + + - + ]: 9511 : if (!nvme_ctrlr_is_available(nvme_ctrlr) ||
1519 : : nvme_ctrlr->io_path_cache_clearing) {
1520 [ - + ]: 8816 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
1521 : 8816 : return;
1522 : : }
1523 : :
1524 : 695 : nvme_ctrlr->io_path_cache_clearing = true;
1525 [ - + ]: 695 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
1526 : :
1527 : 695 : spdk_for_each_channel(nvme_ctrlr,
1528 : : bdev_nvme_clear_io_path_cache,
1529 : : NULL,
1530 : : bdev_nvme_clear_io_path_caches_done);
1531 : : }
1532 : :
1533 : : static struct nvme_qpair *
1534 : 2277 : nvme_poll_group_get_qpair(struct nvme_poll_group *group, struct spdk_nvme_qpair *qpair)
1535 : : {
1536 : : struct nvme_qpair *nvme_qpair;
1537 : :
1538 [ + - ]: 2400 : TAILQ_FOREACH(nvme_qpair, &group->qpair_list, tailq) {
1539 [ + + ]: 2400 : if (nvme_qpair->qpair == qpair) {
1540 : 2277 : break;
1541 : : }
1542 : : }
1543 : :
1544 : 2277 : return nvme_qpair;
1545 : : }
1546 : :
1547 : : static void nvme_qpair_delete(struct nvme_qpair *nvme_qpair);
1548 : :
1549 : : static void
1550 : 2277 : bdev_nvme_disconnected_qpair_cb(struct spdk_nvme_qpair *qpair, void *poll_group_ctx)
1551 : : {
1552 : 2277 : struct nvme_poll_group *group = poll_group_ctx;
1553 : : struct nvme_qpair *nvme_qpair;
1554 : : struct nvme_ctrlr_channel *ctrlr_ch;
1555 : : int status;
1556 : :
1557 : 2277 : nvme_qpair = nvme_poll_group_get_qpair(group, qpair);
1558 [ - + ]: 2277 : if (nvme_qpair == NULL) {
1559 : 0 : return;
1560 : : }
1561 : :
1562 [ + - ]: 2277 : if (nvme_qpair->qpair != NULL) {
1563 : 2277 : spdk_nvme_ctrlr_free_io_qpair(nvme_qpair->qpair);
1564 : 2277 : nvme_qpair->qpair = NULL;
1565 : : }
1566 : :
1567 : 2277 : _bdev_nvme_clear_io_path_cache(nvme_qpair);
1568 : :
1569 : 2277 : ctrlr_ch = nvme_qpair->ctrlr_ch;
1570 : :
1571 [ + + ]: 2277 : if (ctrlr_ch != NULL) {
1572 [ + + ]: 309 : if (ctrlr_ch->reset_iter != NULL) {
1573 : : /* We are in a full reset sequence. */
1574 [ - + ]: 257 : if (ctrlr_ch->connect_poller != NULL) {
1575 : : /* qpair was failed to connect. Abort the reset sequence. */
1576 [ # # # # ]: 0 : SPDK_DEBUGLOG(bdev_nvme, "qpair %p was failed to connect. abort the reset ctrlr sequence.\n",
1577 : : qpair);
1578 : 0 : spdk_poller_unregister(&ctrlr_ch->connect_poller);
1579 : 0 : status = -1;
1580 : : } else {
1581 : : /* qpair was completed to disconnect. Just move to the next ctrlr_channel. */
1582 [ - + - + ]: 257 : SPDK_DEBUGLOG(bdev_nvme, "qpair %p was disconnected and freed in a reset ctrlr sequence.\n",
1583 : : qpair);
1584 : 257 : status = 0;
1585 : : }
1586 : 257 : spdk_for_each_channel_continue(ctrlr_ch->reset_iter, status);
1587 : 257 : ctrlr_ch->reset_iter = NULL;
1588 : : } else {
1589 : : /* qpair was disconnected unexpectedly. Reset controller for recovery. */
1590 : 52 : SPDK_NOTICELOG("qpair %p was disconnected and freed. reset controller.\n", qpair);
1591 : 52 : bdev_nvme_failover_ctrlr(nvme_qpair->ctrlr);
1592 : : }
1593 : : } else {
1594 : : /* In this case, ctrlr_channel is already deleted. */
1595 [ - + + + ]: 1968 : SPDK_DEBUGLOG(bdev_nvme, "qpair %p was disconnected and freed. delete nvme_qpair.\n", qpair);
1596 : 1968 : nvme_qpair_delete(nvme_qpair);
1597 : : }
1598 : : }
1599 : :
1600 : : static void
1601 : 8 : bdev_nvme_check_io_qpairs(struct nvme_poll_group *group)
1602 : : {
1603 : : struct nvme_qpair *nvme_qpair;
1604 : :
1605 [ + + ]: 16 : TAILQ_FOREACH(nvme_qpair, &group->qpair_list, tailq) {
1606 [ + - - + ]: 8 : if (nvme_qpair->qpair == NULL || nvme_qpair->ctrlr_ch == NULL) {
1607 : 0 : continue;
1608 : : }
1609 : :
1610 [ + - ]: 8 : if (spdk_nvme_qpair_get_failure_reason(nvme_qpair->qpair) !=
1611 : : SPDK_NVME_QPAIR_FAILURE_NONE) {
1612 : 8 : _bdev_nvme_clear_io_path_cache(nvme_qpair);
1613 : : }
1614 : : }
1615 : 8 : }
1616 : :
1617 : : static int
1618 : 841435162 : bdev_nvme_poll(void *arg)
1619 : : {
1620 : 841435162 : struct nvme_poll_group *group = arg;
1621 : : int64_t num_completions;
1622 : :
1623 [ - + - + : 841435162 : if (group->collect_spin_stat && group->start_ticks == 0) {
- - ]
1624 : 0 : group->start_ticks = spdk_get_ticks();
1625 : : }
1626 : :
1627 : 841435162 : num_completions = spdk_nvme_poll_group_process_completions(group->group, 0,
1628 : : bdev_nvme_disconnected_qpair_cb);
1629 [ - + - + ]: 841435162 : if (group->collect_spin_stat) {
1630 [ # # ]: 0 : if (num_completions > 0) {
1631 [ # # ]: 0 : if (group->end_ticks != 0) {
1632 : 0 : group->spin_ticks += (group->end_ticks - group->start_ticks);
1633 : 0 : group->end_ticks = 0;
1634 : : }
1635 : 0 : group->start_ticks = 0;
1636 : : } else {
1637 : 0 : group->end_ticks = spdk_get_ticks();
1638 : : }
1639 : : }
1640 : :
1641 [ + + ]: 841435162 : if (spdk_unlikely(num_completions < 0)) {
1642 : 8 : bdev_nvme_check_io_qpairs(group);
1643 : : }
1644 : :
1645 : 841435162 : return num_completions > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
1646 : : }
1647 : :
1648 : : static int bdev_nvme_poll_adminq(void *arg);
1649 : :
1650 : : static void
1651 : 1362 : bdev_nvme_change_adminq_poll_period(struct nvme_ctrlr *nvme_ctrlr, uint64_t new_period_us)
1652 : : {
1653 : 1362 : spdk_poller_unregister(&nvme_ctrlr->adminq_timer_poller);
1654 : :
1655 : 1362 : nvme_ctrlr->adminq_timer_poller = SPDK_POLLER_REGISTER(bdev_nvme_poll_adminq,
1656 : : nvme_ctrlr, new_period_us);
1657 : 1362 : }
1658 : :
1659 : : static int
1660 : 683531 : bdev_nvme_poll_adminq(void *arg)
1661 : : {
1662 : : int32_t rc;
1663 : 683531 : struct nvme_ctrlr *nvme_ctrlr = arg;
1664 : : nvme_ctrlr_disconnected_cb disconnected_cb;
1665 : :
1666 [ - + ]: 683531 : assert(nvme_ctrlr != NULL);
1667 : :
1668 : 683531 : rc = spdk_nvme_ctrlr_process_admin_completions(nvme_ctrlr->ctrlr);
1669 [ + + ]: 683531 : if (rc < 0) {
1670 : 1477 : disconnected_cb = nvme_ctrlr->disconnected_cb;
1671 : 1477 : nvme_ctrlr->disconnected_cb = NULL;
1672 : :
1673 [ + + ]: 1477 : if (disconnected_cb != NULL) {
1674 : 681 : bdev_nvme_change_adminq_poll_period(nvme_ctrlr,
1675 : : g_opts.nvme_adminq_poll_period_us);
1676 : 681 : disconnected_cb(nvme_ctrlr);
1677 : : } else {
1678 : 796 : bdev_nvme_failover_ctrlr(nvme_ctrlr);
1679 : : }
1680 [ + + ]: 682054 : } else if (spdk_nvme_ctrlr_get_admin_qp_failure_reason(nvme_ctrlr->ctrlr) !=
1681 : : SPDK_NVME_QPAIR_FAILURE_NONE) {
1682 : 9479 : bdev_nvme_clear_io_path_caches(nvme_ctrlr);
1683 : : }
1684 : :
1685 : 683531 : return rc == 0 ? SPDK_POLLER_IDLE : SPDK_POLLER_BUSY;
1686 : : }
1687 : :
1688 : : static void
1689 : 1069 : nvme_bdev_free(void *io_device)
1690 : : {
1691 : 1069 : struct nvme_bdev *nvme_disk = io_device;
1692 : :
1693 [ - + ]: 1069 : pthread_mutex_destroy(&nvme_disk->mutex);
1694 : 1069 : free(nvme_disk->disk.name);
1695 : 1069 : free(nvme_disk->err_stat);
1696 : 1069 : free(nvme_disk);
1697 : 1069 : }
1698 : :
1699 : : static int
1700 : 1063 : bdev_nvme_destruct(void *ctx)
1701 : : {
1702 : 1063 : struct nvme_bdev *nvme_disk = ctx;
1703 : : struct nvme_ns *nvme_ns, *tmp_nvme_ns;
1704 : :
1705 : 186 : SPDK_DTRACE_PROBE2(bdev_nvme_destruct, nvme_disk->nbdev_ctrlr->name, nvme_disk->nsid);
1706 : :
1707 [ + + ]: 2132 : TAILQ_FOREACH_SAFE(nvme_ns, &nvme_disk->nvme_ns_list, tailq, tmp_nvme_ns) {
1708 [ - + ]: 1069 : pthread_mutex_lock(&nvme_ns->ctrlr->mutex);
1709 : :
1710 : 1069 : nvme_ns->bdev = NULL;
1711 : :
1712 [ - + ]: 1069 : assert(nvme_ns->id > 0);
1713 : :
1714 [ + + ]: 1069 : if (nvme_ctrlr_get_ns(nvme_ns->ctrlr, nvme_ns->id) == NULL) {
1715 [ - + ]: 149 : pthread_mutex_unlock(&nvme_ns->ctrlr->mutex);
1716 : :
1717 : 149 : nvme_ctrlr_release(nvme_ns->ctrlr);
1718 : 149 : nvme_ns_free(nvme_ns);
1719 : : } else {
1720 [ - + ]: 920 : pthread_mutex_unlock(&nvme_ns->ctrlr->mutex);
1721 : : }
1722 : : }
1723 : :
1724 [ - + ]: 1063 : pthread_mutex_lock(&g_bdev_nvme_mutex);
1725 [ + + ]: 1063 : TAILQ_REMOVE(&nvme_disk->nbdev_ctrlr->bdevs, nvme_disk, tailq);
1726 [ - + ]: 1063 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
1727 : :
1728 : 1063 : spdk_io_device_unregister(nvme_disk, nvme_bdev_free);
1729 : :
1730 : 1063 : return 0;
1731 : : }
1732 : :
1733 : : static int
1734 : 2281 : bdev_nvme_create_qpair(struct nvme_qpair *nvme_qpair)
1735 : : {
1736 : : struct nvme_ctrlr *nvme_ctrlr;
1737 : 1126 : struct spdk_nvme_io_qpair_opts opts;
1738 : : struct spdk_nvme_qpair *qpair;
1739 : : int rc;
1740 : :
1741 : 2281 : nvme_ctrlr = nvme_qpair->ctrlr;
1742 : :
1743 : 2281 : spdk_nvme_ctrlr_get_default_io_qpair_opts(nvme_ctrlr->ctrlr, &opts, sizeof(opts));
1744 [ - + ]: 2281 : opts.delay_cmd_submit = g_opts.delay_cmd_submit;
1745 : 2281 : opts.create_only = true;
1746 : 2281 : opts.async_mode = true;
1747 : 2281 : opts.io_queue_requests = spdk_max(g_opts.io_queue_requests, opts.io_queue_requests);
1748 : 2281 : g_opts.io_queue_requests = opts.io_queue_requests;
1749 : :
1750 : 2281 : qpair = spdk_nvme_ctrlr_alloc_io_qpair(nvme_ctrlr->ctrlr, &opts, sizeof(opts));
1751 [ - + ]: 2281 : if (qpair == NULL) {
1752 : 0 : return -1;
1753 : : }
1754 : :
1755 : 392 : SPDK_DTRACE_PROBE3(bdev_nvme_create_qpair, nvme_ctrlr->nbdev_ctrlr->name,
1756 : : spdk_nvme_qpair_get_id(qpair), spdk_thread_get_id(nvme_ctrlr->thread));
1757 : :
1758 [ - + ]: 2281 : assert(nvme_qpair->group != NULL);
1759 : :
1760 : 2281 : rc = spdk_nvme_poll_group_add(nvme_qpair->group->group, qpair);
1761 [ - + ]: 2281 : if (rc != 0) {
1762 : 0 : SPDK_ERRLOG("Unable to begin polling on NVMe Channel.\n");
1763 : 0 : goto err;
1764 : : }
1765 : :
1766 : 2281 : rc = spdk_nvme_ctrlr_connect_io_qpair(nvme_ctrlr->ctrlr, qpair);
1767 [ - + ]: 2281 : if (rc != 0) {
1768 : 0 : SPDK_ERRLOG("Unable to connect I/O qpair.\n");
1769 : 0 : goto err;
1770 : : }
1771 : :
1772 : 2281 : nvme_qpair->qpair = qpair;
1773 : :
1774 [ + + + + ]: 2281 : if (!g_opts.disable_auto_failback) {
1775 : 2165 : _bdev_nvme_clear_io_path_cache(nvme_qpair);
1776 : : }
1777 : :
1778 : 2281 : return 0;
1779 : :
1780 : 0 : err:
1781 : 0 : spdk_nvme_ctrlr_free_io_qpair(qpair);
1782 : :
1783 : 0 : return rc;
1784 : : }
1785 : :
1786 : : static void
1787 : 741 : bdev_nvme_complete_pending_resets(struct spdk_io_channel_iter *i)
1788 : : {
1789 : 741 : struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
1790 : 741 : struct nvme_ctrlr_channel *ctrlr_ch = spdk_io_channel_get_ctx(_ch);
1791 : 741 : enum spdk_bdev_io_status status = SPDK_BDEV_IO_STATUS_SUCCESS;
1792 : : struct spdk_bdev_io *bdev_io;
1793 : :
1794 [ + + ]: 741 : if (spdk_io_channel_iter_get_ctx(i) != NULL) {
1795 : 486 : status = SPDK_BDEV_IO_STATUS_FAILED;
1796 : : }
1797 : :
1798 [ + + ]: 753 : while (!TAILQ_EMPTY(&ctrlr_ch->pending_resets)) {
1799 : 12 : bdev_io = TAILQ_FIRST(&ctrlr_ch->pending_resets);
1800 [ - + ]: 12 : TAILQ_REMOVE(&ctrlr_ch->pending_resets, bdev_io, module_link);
1801 : 12 : __bdev_nvme_io_complete(bdev_io, status, NULL);
1802 : : }
1803 : :
1804 : 741 : spdk_for_each_channel_continue(i, 0);
1805 : 741 : }
1806 : :
1807 : : /* This function marks the current trid as failed by storing the current ticks
1808 : : * and then sets the next trid to the active trid within a controller if exists.
1809 : : *
1810 : : * The purpose of the boolean return value is to request the caller to disconnect
1811 : : * the current trid now to try connecting the next trid.
1812 : : */
1813 : : static bool
1814 : 948 : bdev_nvme_failover_trid(struct nvme_ctrlr *nvme_ctrlr, bool remove, bool start)
1815 : : {
1816 : : struct nvme_path_id *path_id, *next_path;
1817 : : int rc __attribute__((unused));
1818 : :
1819 : 948 : path_id = TAILQ_FIRST(&nvme_ctrlr->trids);
1820 [ - + ]: 948 : assert(path_id);
1821 [ - + ]: 948 : assert(path_id == nvme_ctrlr->active_path_id);
1822 : 948 : next_path = TAILQ_NEXT(path_id, link);
1823 : :
1824 : : /* Update the last failed time. It means the trid is failed if its last
1825 : : * failed time is non-zero.
1826 : : */
1827 : 948 : path_id->last_failed_tsc = spdk_get_ticks();
1828 : :
1829 [ + + ]: 948 : if (next_path == NULL) {
1830 : : /* There is no alternate trid within a controller. */
1831 : 884 : return false;
1832 : : }
1833 : :
1834 [ + + + + ]: 64 : if (!start && nvme_ctrlr->opts.reconnect_delay_sec == 0) {
1835 : : /* Connect is not retried in a controller reset sequence. Connecting
1836 : : * the next trid will be done by the next bdev_nvme_failover_ctrlr() call.
1837 : : */
1838 : 12 : return false;
1839 : : }
1840 : :
1841 [ - + ]: 52 : assert(path_id->trid.trtype != SPDK_NVME_TRANSPORT_PCIE);
1842 : :
1843 : 52 : SPDK_NOTICELOG("Start failover from %s:%s to %s:%s\n", path_id->trid.traddr,
1844 : : path_id->trid.trsvcid, next_path->trid.traddr, next_path->trid.trsvcid);
1845 : :
1846 : 52 : spdk_nvme_ctrlr_fail(nvme_ctrlr->ctrlr);
1847 : 52 : nvme_ctrlr->active_path_id = next_path;
1848 : 52 : rc = spdk_nvme_ctrlr_set_trid(nvme_ctrlr->ctrlr, &next_path->trid);
1849 [ - + ]: 52 : assert(rc == 0);
1850 [ + - ]: 52 : TAILQ_REMOVE(&nvme_ctrlr->trids, path_id, link);
1851 [ + + ]: 52 : if (!remove) {
1852 : : /** Shuffle the old trid to the end of the list and use the new one.
1853 : : * Allows for round robin through multiple connections.
1854 : : */
1855 : 39 : TAILQ_INSERT_TAIL(&nvme_ctrlr->trids, path_id, link);
1856 : : } else {
1857 : 13 : free(path_id);
1858 : : }
1859 : :
1860 [ + + + + ]: 52 : if (start || next_path->last_failed_tsc == 0) {
1861 : : /* bdev_nvme_failover_ctrlr() is just called or the next trid is not failed
1862 : : * or used yet. Try the next trid now.
1863 : : */
1864 : 48 : return true;
1865 : : }
1866 : :
1867 : 4 : if (spdk_get_ticks() > next_path->last_failed_tsc + spdk_get_ticks_hz() *
1868 [ - + ]: 4 : nvme_ctrlr->opts.reconnect_delay_sec) {
1869 : : /* Enough backoff passed since the next trid failed. Try the next trid now. */
1870 : 0 : return true;
1871 : : }
1872 : :
1873 : : /* The next trid will be tried after reconnect_delay_sec seconds. */
1874 : 4 : return false;
1875 : : }
1876 : :
1877 : : static bool
1878 : 157865 : bdev_nvme_check_ctrlr_loss_timeout(struct nvme_ctrlr *nvme_ctrlr)
1879 : : {
1880 : : int32_t elapsed;
1881 : :
1882 [ + + ]: 157865 : if (nvme_ctrlr->opts.ctrlr_loss_timeout_sec == 0 ||
1883 [ + + ]: 6000 : nvme_ctrlr->opts.ctrlr_loss_timeout_sec == -1) {
1884 : 154741 : return false;
1885 : : }
1886 : :
1887 [ - + ]: 3124 : elapsed = (spdk_get_ticks() - nvme_ctrlr->reset_start_tsc) / spdk_get_ticks_hz();
1888 [ + + ]: 3124 : if (elapsed >= nvme_ctrlr->opts.ctrlr_loss_timeout_sec) {
1889 : 38 : return true;
1890 : : } else {
1891 : 3086 : return false;
1892 : : }
1893 : : }
1894 : :
1895 : : static bool
1896 : 74 : bdev_nvme_check_fast_io_fail_timeout(struct nvme_ctrlr *nvme_ctrlr)
1897 : : {
1898 : : uint32_t elapsed;
1899 : :
1900 [ + + ]: 74 : if (nvme_ctrlr->opts.fast_io_fail_timeout_sec == 0) {
1901 : 46 : return false;
1902 : : }
1903 : :
1904 [ - + ]: 28 : elapsed = (spdk_get_ticks() - nvme_ctrlr->reset_start_tsc) / spdk_get_ticks_hz();
1905 [ + + ]: 28 : if (elapsed >= nvme_ctrlr->opts.fast_io_fail_timeout_sec) {
1906 : 12 : return true;
1907 : : } else {
1908 : 16 : return false;
1909 : : }
1910 : : }
1911 : :
1912 : : static void bdev_nvme_reset_ctrlr_complete(struct nvme_ctrlr *nvme_ctrlr, bool success);
1913 : :
1914 : : static void
1915 : 685 : nvme_ctrlr_disconnect(struct nvme_ctrlr *nvme_ctrlr, nvme_ctrlr_disconnected_cb cb_fn)
1916 : : {
1917 : : int rc;
1918 : :
1919 : 685 : rc = spdk_nvme_ctrlr_disconnect(nvme_ctrlr->ctrlr);
1920 [ + + ]: 685 : if (rc != 0) {
1921 : : /* Disconnect fails if ctrlr is already resetting or removed. In this case,
1922 : : * fail the reset sequence immediately.
1923 : : */
1924 : 4 : bdev_nvme_reset_ctrlr_complete(nvme_ctrlr, false);
1925 : 4 : return;
1926 : : }
1927 : :
1928 : : /* spdk_nvme_ctrlr_disconnect() may complete asynchronously later by polling adminq.
1929 : : * Set callback here to execute the specified operation after ctrlr is really disconnected.
1930 : : */
1931 [ - + ]: 681 : assert(nvme_ctrlr->disconnected_cb == NULL);
1932 : 681 : nvme_ctrlr->disconnected_cb = cb_fn;
1933 : :
1934 : : /* During disconnection, reduce the period to poll adminq more often. */
1935 : 681 : bdev_nvme_change_adminq_poll_period(nvme_ctrlr, 0);
1936 : : }
1937 : :
1938 : : enum bdev_nvme_op_after_reset {
1939 : : OP_NONE,
1940 : : OP_COMPLETE_PENDING_DESTRUCT,
1941 : : OP_DESTRUCT,
1942 : : OP_DELAYED_RECONNECT,
1943 : : OP_FAILOVER,
1944 : : };
1945 : :
1946 : : typedef enum bdev_nvme_op_after_reset _bdev_nvme_op_after_reset;
1947 : :
1948 : : static _bdev_nvme_op_after_reset
1949 : 681 : bdev_nvme_check_op_after_reset(struct nvme_ctrlr *nvme_ctrlr, bool success)
1950 : : {
1951 [ + + ]: 681 : if (nvme_ctrlr_can_be_unregistered(nvme_ctrlr)) {
1952 : : /* Complete pending destruct after reset completes. */
1953 : 4 : return OP_COMPLETE_PENDING_DESTRUCT;
1954 [ + + ]: 677 : } else if (nvme_ctrlr->pending_failover) {
1955 : 12 : nvme_ctrlr->pending_failover = false;
1956 : 12 : nvme_ctrlr->reset_start_tsc = 0;
1957 : 12 : return OP_FAILOVER;
1958 [ + + + + ]: 665 : } else if (success || nvme_ctrlr->opts.reconnect_delay_sec == 0) {
1959 : 576 : nvme_ctrlr->reset_start_tsc = 0;
1960 : 576 : return OP_NONE;
1961 [ + + ]: 89 : } else if (bdev_nvme_check_ctrlr_loss_timeout(nvme_ctrlr)) {
1962 : 15 : return OP_DESTRUCT;
1963 : : } else {
1964 [ + + ]: 74 : if (bdev_nvme_check_fast_io_fail_timeout(nvme_ctrlr)) {
1965 : 12 : nvme_ctrlr->fast_io_fail_timedout = true;
1966 : : }
1967 : 74 : return OP_DELAYED_RECONNECT;
1968 : : }
1969 : : }
1970 : :
1971 : : static int bdev_nvme_delete_ctrlr(struct nvme_ctrlr *nvme_ctrlr, bool hotplug);
1972 : : static void bdev_nvme_reconnect_ctrlr(struct nvme_ctrlr *nvme_ctrlr);
1973 : :
1974 : : static int
1975 : 62 : bdev_nvme_reconnect_delay_timer_expired(void *ctx)
1976 : : {
1977 : 62 : struct nvme_ctrlr *nvme_ctrlr = ctx;
1978 : :
1979 : 26 : SPDK_DTRACE_PROBE1(bdev_nvme_ctrlr_reconnect_delay, nvme_ctrlr->nbdev_ctrlr->name);
1980 [ - + ]: 62 : pthread_mutex_lock(&nvme_ctrlr->mutex);
1981 : :
1982 : 62 : spdk_poller_unregister(&nvme_ctrlr->reconnect_delay_timer);
1983 : :
1984 [ - + ]: 62 : if (!nvme_ctrlr->reconnect_is_delayed) {
1985 [ # # ]: 0 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
1986 : 0 : return SPDK_POLLER_BUSY;
1987 : : }
1988 : :
1989 : 62 : nvme_ctrlr->reconnect_is_delayed = false;
1990 : :
1991 [ - + ]: 62 : if (nvme_ctrlr->destruct) {
1992 [ # # ]: 0 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
1993 : 0 : return SPDK_POLLER_BUSY;
1994 : : }
1995 : :
1996 [ - + ]: 62 : assert(nvme_ctrlr->resetting == false);
1997 : 62 : nvme_ctrlr->resetting = true;
1998 : :
1999 [ - + ]: 62 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2000 : :
2001 : 62 : spdk_poller_resume(nvme_ctrlr->adminq_timer_poller);
2002 : :
2003 : 62 : bdev_nvme_reconnect_ctrlr(nvme_ctrlr);
2004 : 62 : return SPDK_POLLER_BUSY;
2005 : : }
2006 : :
2007 : : static void
2008 : 74 : bdev_nvme_start_reconnect_delay_timer(struct nvme_ctrlr *nvme_ctrlr)
2009 : : {
2010 : 74 : spdk_poller_pause(nvme_ctrlr->adminq_timer_poller);
2011 : :
2012 [ - + ]: 74 : assert(nvme_ctrlr->reconnect_is_delayed == false);
2013 : 74 : nvme_ctrlr->reconnect_is_delayed = true;
2014 : :
2015 [ - + ]: 74 : assert(nvme_ctrlr->reconnect_delay_timer == NULL);
2016 : 74 : nvme_ctrlr->reconnect_delay_timer = SPDK_POLLER_REGISTER(bdev_nvme_reconnect_delay_timer_expired,
2017 : : nvme_ctrlr,
2018 : : nvme_ctrlr->opts.reconnect_delay_sec * SPDK_SEC_TO_USEC);
2019 : 74 : }
2020 : :
2021 : : static void remove_discovery_entry(struct nvme_ctrlr *nvme_ctrlr);
2022 : :
2023 : : static void
2024 : 673 : _bdev_nvme_reset_ctrlr_complete(struct spdk_io_channel_iter *i, int status)
2025 : : {
2026 : 673 : struct nvme_ctrlr *nvme_ctrlr = spdk_io_channel_iter_get_io_device(i);
2027 : 673 : bool success = spdk_io_channel_iter_get_ctx(i) == NULL;
2028 : 673 : bdev_nvme_ctrlr_op_cb ctrlr_op_cb_fn = nvme_ctrlr->ctrlr_op_cb_fn;
2029 : 673 : void *ctrlr_op_cb_arg = nvme_ctrlr->ctrlr_op_cb_arg;
2030 : : enum bdev_nvme_op_after_reset op_after_reset;
2031 : :
2032 [ - + ]: 673 : assert(nvme_ctrlr->thread == spdk_get_thread());
2033 : :
2034 : 673 : nvme_ctrlr->ctrlr_op_cb_fn = NULL;
2035 : 673 : nvme_ctrlr->ctrlr_op_cb_arg = NULL;
2036 : :
2037 [ + + ]: 673 : if (!success) {
2038 : 483 : SPDK_ERRLOG("Resetting controller failed.\n");
2039 : : } else {
2040 : 190 : SPDK_NOTICELOG("Resetting controller successful.\n");
2041 : : }
2042 : :
2043 [ - + ]: 673 : pthread_mutex_lock(&nvme_ctrlr->mutex);
2044 : 673 : nvme_ctrlr->resetting = false;
2045 : 673 : nvme_ctrlr->dont_retry = false;
2046 : 673 : nvme_ctrlr->in_failover = false;
2047 : :
2048 : 673 : op_after_reset = bdev_nvme_check_op_after_reset(nvme_ctrlr, success);
2049 [ - + ]: 673 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2050 : :
2051 : : /* Delay callbacks when the next operation is a failover. */
2052 [ + + + - ]: 673 : if (ctrlr_op_cb_fn && op_after_reset != OP_FAILOVER) {
2053 [ + + ]: 90 : ctrlr_op_cb_fn(ctrlr_op_cb_arg, success ? 0 : -1);
2054 : : }
2055 : :
2056 [ + + + + : 673 : switch (op_after_reset) {
+ ]
2057 : 4 : case OP_COMPLETE_PENDING_DESTRUCT:
2058 : 4 : nvme_ctrlr_unregister(nvme_ctrlr);
2059 : 4 : break;
2060 : 15 : case OP_DESTRUCT:
2061 : 15 : bdev_nvme_delete_ctrlr(nvme_ctrlr, false);
2062 : 15 : remove_discovery_entry(nvme_ctrlr);
2063 : 15 : break;
2064 : 74 : case OP_DELAYED_RECONNECT:
2065 : 74 : nvme_ctrlr_disconnect(nvme_ctrlr, bdev_nvme_start_reconnect_delay_timer);
2066 : 74 : break;
2067 : 12 : case OP_FAILOVER:
2068 : 12 : nvme_ctrlr->ctrlr_op_cb_fn = ctrlr_op_cb_fn;
2069 : 12 : nvme_ctrlr->ctrlr_op_cb_arg = ctrlr_op_cb_arg;
2070 : 12 : bdev_nvme_failover_ctrlr(nvme_ctrlr);
2071 : 12 : break;
2072 : 568 : default:
2073 : 568 : break;
2074 : : }
2075 : 673 : }
2076 : :
2077 : : static void
2078 : 681 : bdev_nvme_reset_ctrlr_complete(struct nvme_ctrlr *nvme_ctrlr, bool success)
2079 : : {
2080 [ - + ]: 681 : pthread_mutex_lock(&nvme_ctrlr->mutex);
2081 [ + + ]: 681 : if (!success) {
2082 : : /* Connecting the active trid failed. Set the next alternate trid to the
2083 : : * active trid if it exists.
2084 : : */
2085 [ + + ]: 491 : if (bdev_nvme_failover_trid(nvme_ctrlr, false, false)) {
2086 : : /* The next alternate trid exists and is ready to try. Try it now. */
2087 [ - + ]: 8 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2088 : :
2089 : 8 : nvme_ctrlr_disconnect(nvme_ctrlr, bdev_nvme_reconnect_ctrlr);
2090 : 8 : return;
2091 : : }
2092 : :
2093 : : /* We came here if there is no alternate trid or if the next trid exists but
2094 : : * is not ready to try. We will try the active trid after reconnect_delay_sec
2095 : : * seconds if it is non-zero or at the next reset call otherwise.
2096 : : */
2097 : : } else {
2098 : : /* Connecting the active trid succeeded. Clear the last failed time because it
2099 : : * means the trid is failed if its last failed time is non-zero.
2100 : : */
2101 : 190 : nvme_ctrlr->active_path_id->last_failed_tsc = 0;
2102 : : }
2103 [ - + ]: 673 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2104 : :
2105 : : /* Make sure we clear any pending resets before returning. */
2106 [ + + ]: 673 : spdk_for_each_channel(nvme_ctrlr,
2107 : : bdev_nvme_complete_pending_resets,
2108 : : success ? NULL : (void *)0x1,
2109 : : _bdev_nvme_reset_ctrlr_complete);
2110 : : }
2111 : :
2112 : : static void
2113 : 0 : bdev_nvme_reset_create_qpairs_failed(struct spdk_io_channel_iter *i, int status)
2114 : : {
2115 : 0 : struct nvme_ctrlr *nvme_ctrlr = spdk_io_channel_iter_get_io_device(i);
2116 : :
2117 : 0 : bdev_nvme_reset_ctrlr_complete(nvme_ctrlr, false);
2118 : 0 : }
2119 : :
2120 : : static void
2121 : 649 : bdev_nvme_reset_destroy_qpair(struct spdk_io_channel_iter *i)
2122 : : {
2123 : 649 : struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
2124 : 649 : struct nvme_ctrlr_channel *ctrlr_ch = spdk_io_channel_get_ctx(ch);
2125 : : struct nvme_qpair *nvme_qpair;
2126 : :
2127 : 649 : nvme_qpair = ctrlr_ch->qpair;
2128 [ - + ]: 649 : assert(nvme_qpair != NULL);
2129 : :
2130 : 649 : _bdev_nvme_clear_io_path_cache(nvme_qpair);
2131 : :
2132 [ + + ]: 649 : if (nvme_qpair->qpair != NULL) {
2133 [ + + ]: 257 : if (nvme_qpair->ctrlr->dont_retry) {
2134 : 200 : spdk_nvme_qpair_set_abort_dnr(nvme_qpair->qpair, true);
2135 : : }
2136 : 257 : spdk_nvme_ctrlr_disconnect_io_qpair(nvme_qpair->qpair);
2137 : :
2138 : : /* The current full reset sequence will move to the next
2139 : : * ctrlr_channel after the qpair is actually disconnected.
2140 : : */
2141 [ - + ]: 257 : assert(ctrlr_ch->reset_iter == NULL);
2142 : 257 : ctrlr_ch->reset_iter = i;
2143 : : } else {
2144 : 392 : spdk_for_each_channel_continue(i, 0);
2145 : : }
2146 : 649 : }
2147 : :
2148 : : static void
2149 : 190 : bdev_nvme_reset_create_qpairs_done(struct spdk_io_channel_iter *i, int status)
2150 : : {
2151 : 190 : struct nvme_ctrlr *nvme_ctrlr = spdk_io_channel_iter_get_io_device(i);
2152 : :
2153 [ + - ]: 190 : if (status == 0) {
2154 : 190 : bdev_nvme_reset_ctrlr_complete(nvme_ctrlr, true);
2155 : : } else {
2156 : : /* Delete the added qpairs and quiesce ctrlr to make the states clean. */
2157 : 0 : spdk_for_each_channel(nvme_ctrlr,
2158 : : bdev_nvme_reset_destroy_qpair,
2159 : : NULL,
2160 : : bdev_nvme_reset_create_qpairs_failed);
2161 : : }
2162 : 190 : }
2163 : :
2164 : : static int
2165 : 13172 : bdev_nvme_reset_check_qpair_connected(void *ctx)
2166 : : {
2167 : 13172 : struct nvme_ctrlr_channel *ctrlr_ch = ctx;
2168 : :
2169 [ - + ]: 13172 : if (ctrlr_ch->reset_iter == NULL) {
2170 : : /* qpair was already failed to connect and the reset sequence is being aborted. */
2171 [ # # ]: 0 : assert(ctrlr_ch->connect_poller == NULL);
2172 [ # # ]: 0 : assert(ctrlr_ch->qpair->qpair == NULL);
2173 : 0 : return SPDK_POLLER_BUSY;
2174 : : }
2175 : :
2176 [ - + ]: 13172 : assert(ctrlr_ch->qpair->qpair != NULL);
2177 : :
2178 [ + + ]: 13172 : if (!spdk_nvme_qpair_is_connected(ctrlr_ch->qpair->qpair)) {
2179 : 12933 : return SPDK_POLLER_BUSY;
2180 : : }
2181 : :
2182 : 239 : spdk_poller_unregister(&ctrlr_ch->connect_poller);
2183 : :
2184 : : /* qpair was completed to connect. Move to the next ctrlr_channel */
2185 : 239 : spdk_for_each_channel_continue(ctrlr_ch->reset_iter, 0);
2186 : 239 : ctrlr_ch->reset_iter = NULL;
2187 : :
2188 [ + + + + ]: 239 : if (!g_opts.disable_auto_failback) {
2189 : 187 : _bdev_nvme_clear_io_path_cache(ctrlr_ch->qpair);
2190 : : }
2191 : :
2192 : 239 : return SPDK_POLLER_BUSY;
2193 : : }
2194 : :
2195 : : static void
2196 : 239 : bdev_nvme_reset_create_qpair(struct spdk_io_channel_iter *i)
2197 : : {
2198 : 239 : struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
2199 : 239 : struct nvme_ctrlr_channel *ctrlr_ch = spdk_io_channel_get_ctx(_ch);
2200 : : int rc;
2201 : :
2202 : 239 : rc = bdev_nvme_create_qpair(ctrlr_ch->qpair);
2203 [ + - ]: 239 : if (rc == 0) {
2204 : 239 : ctrlr_ch->connect_poller = SPDK_POLLER_REGISTER(bdev_nvme_reset_check_qpair_connected,
2205 : : ctrlr_ch, 0);
2206 : :
2207 : : /* The current full reset sequence will move to the next
2208 : : * ctrlr_channel after the qpair is actually connected.
2209 : : */
2210 [ - + ]: 239 : assert(ctrlr_ch->reset_iter == NULL);
2211 : 239 : ctrlr_ch->reset_iter = i;
2212 : : } else {
2213 : 0 : spdk_for_each_channel_continue(i, rc);
2214 : : }
2215 : 239 : }
2216 : :
2217 : : static void
2218 : 190 : nvme_ctrlr_check_namespaces(struct nvme_ctrlr *nvme_ctrlr)
2219 : : {
2220 : 190 : struct spdk_nvme_ctrlr *ctrlr = nvme_ctrlr->ctrlr;
2221 : : struct nvme_ns *nvme_ns;
2222 : :
2223 [ + + ]: 218 : for (nvme_ns = nvme_ctrlr_get_first_active_ns(nvme_ctrlr);
2224 [ + + ]: 242 : nvme_ns != NULL;
2225 : 138 : nvme_ns = nvme_ctrlr_get_next_active_ns(nvme_ctrlr, nvme_ns)) {
2226 [ + + ]: 138 : if (!spdk_nvme_ctrlr_is_active_ns(ctrlr, nvme_ns->id)) {
2227 [ - + - + ]: 4 : SPDK_DEBUGLOG(bdev_nvme, "NSID %u was removed during reset.\n", nvme_ns->id);
2228 : : /* NS can be added again. Just nullify nvme_ns->ns. */
2229 : 4 : nvme_ns->ns = NULL;
2230 : : }
2231 : : }
2232 : 190 : }
2233 : :
2234 : :
2235 : : static int
2236 : 157756 : bdev_nvme_reconnect_ctrlr_poll(void *arg)
2237 : : {
2238 : 157756 : struct nvme_ctrlr *nvme_ctrlr = arg;
2239 : 157756 : int rc = -ETIMEDOUT;
2240 : :
2241 [ + + ]: 157756 : if (bdev_nvme_check_ctrlr_loss_timeout(nvme_ctrlr)) {
2242 : : /* Mark the ctrlr as failed. The next call to
2243 : : * spdk_nvme_ctrlr_reconnect_poll_async() will then
2244 : : * do the necessary cleanup and return failure.
2245 : : */
2246 : 15 : spdk_nvme_ctrlr_fail(nvme_ctrlr->ctrlr);
2247 : : }
2248 : :
2249 : 157756 : rc = spdk_nvme_ctrlr_reconnect_poll_async(nvme_ctrlr->ctrlr);
2250 [ + + ]: 157756 : if (rc == -EAGAIN) {
2251 : 157079 : return SPDK_POLLER_BUSY;
2252 : : }
2253 : :
2254 : 677 : spdk_poller_unregister(&nvme_ctrlr->reset_detach_poller);
2255 [ + + ]: 677 : if (rc == 0) {
2256 : 190 : nvme_ctrlr_check_namespaces(nvme_ctrlr);
2257 : :
2258 : : /* Recreate all of the I/O queue pairs */
2259 : 190 : spdk_for_each_channel(nvme_ctrlr,
2260 : : bdev_nvme_reset_create_qpair,
2261 : : NULL,
2262 : : bdev_nvme_reset_create_qpairs_done);
2263 : : } else {
2264 : 487 : bdev_nvme_reset_ctrlr_complete(nvme_ctrlr, false);
2265 : : }
2266 : 677 : return SPDK_POLLER_BUSY;
2267 : : }
2268 : :
2269 : : static void
2270 : 677 : bdev_nvme_reconnect_ctrlr(struct nvme_ctrlr *nvme_ctrlr)
2271 : : {
2272 : 677 : spdk_nvme_ctrlr_reconnect_async(nvme_ctrlr->ctrlr);
2273 : :
2274 : 83 : SPDK_DTRACE_PROBE1(bdev_nvme_ctrlr_reconnect, nvme_ctrlr->nbdev_ctrlr->name);
2275 [ - + ]: 677 : assert(nvme_ctrlr->reset_detach_poller == NULL);
2276 : 677 : nvme_ctrlr->reset_detach_poller = SPDK_POLLER_REGISTER(bdev_nvme_reconnect_ctrlr_poll,
2277 : : nvme_ctrlr, 0);
2278 : 677 : }
2279 : :
2280 : : static void
2281 : 599 : bdev_nvme_reset_destroy_qpair_done(struct spdk_io_channel_iter *i, int status)
2282 : : {
2283 : 599 : struct nvme_ctrlr *nvme_ctrlr = spdk_io_channel_iter_get_io_device(i);
2284 : :
2285 : 57 : SPDK_DTRACE_PROBE1(bdev_nvme_ctrlr_reset, nvme_ctrlr->nbdev_ctrlr->name);
2286 [ - + ]: 599 : assert(status == 0);
2287 : :
2288 [ + + ]: 599 : if (!spdk_nvme_ctrlr_is_fabrics(nvme_ctrlr->ctrlr)) {
2289 : 38 : bdev_nvme_reconnect_ctrlr(nvme_ctrlr);
2290 : : } else {
2291 : 561 : nvme_ctrlr_disconnect(nvme_ctrlr, bdev_nvme_reconnect_ctrlr);
2292 : : }
2293 : 599 : }
2294 : :
2295 : : static void
2296 : 599 : bdev_nvme_reset_destroy_qpairs(struct nvme_ctrlr *nvme_ctrlr)
2297 : : {
2298 : 599 : spdk_for_each_channel(nvme_ctrlr,
2299 : : bdev_nvme_reset_destroy_qpair,
2300 : : NULL,
2301 : : bdev_nvme_reset_destroy_qpair_done);
2302 : 599 : }
2303 : :
2304 : : static void
2305 : 12 : bdev_nvme_reconnect_ctrlr_now(void *ctx)
2306 : : {
2307 : 12 : struct nvme_ctrlr *nvme_ctrlr = ctx;
2308 : :
2309 [ - + ]: 12 : assert(nvme_ctrlr->resetting == true);
2310 [ - + ]: 12 : assert(nvme_ctrlr->thread == spdk_get_thread());
2311 : :
2312 : 12 : spdk_poller_unregister(&nvme_ctrlr->reconnect_delay_timer);
2313 : :
2314 : 12 : spdk_poller_resume(nvme_ctrlr->adminq_timer_poller);
2315 : :
2316 : 12 : bdev_nvme_reconnect_ctrlr(nvme_ctrlr);
2317 : 12 : }
2318 : :
2319 : : static void
2320 : 599 : _bdev_nvme_reset_ctrlr(void *ctx)
2321 : : {
2322 : 599 : struct nvme_ctrlr *nvme_ctrlr = ctx;
2323 : :
2324 [ - + ]: 599 : assert(nvme_ctrlr->resetting == true);
2325 [ - + ]: 599 : assert(nvme_ctrlr->thread == spdk_get_thread());
2326 : :
2327 [ + + ]: 599 : if (!spdk_nvme_ctrlr_is_fabrics(nvme_ctrlr->ctrlr)) {
2328 : 38 : nvme_ctrlr_disconnect(nvme_ctrlr, bdev_nvme_reset_destroy_qpairs);
2329 : : } else {
2330 : 561 : bdev_nvme_reset_destroy_qpairs(nvme_ctrlr);
2331 : : }
2332 : 599 : }
2333 : :
2334 : : static int
2335 : 182 : bdev_nvme_reset_ctrlr(struct nvme_ctrlr *nvme_ctrlr)
2336 : : {
2337 : : spdk_msg_fn msg_fn;
2338 : :
2339 [ - + ]: 182 : pthread_mutex_lock(&nvme_ctrlr->mutex);
2340 [ + + ]: 182 : if (nvme_ctrlr->destruct) {
2341 [ - + ]: 12 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2342 : 12 : return -ENXIO;
2343 : : }
2344 : :
2345 [ + + ]: 170 : if (nvme_ctrlr->resetting) {
2346 [ - + ]: 20 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2347 : 20 : SPDK_NOTICELOG("Unable to perform reset, already in progress.\n");
2348 : 20 : return -EBUSY;
2349 : : }
2350 : :
2351 [ - + ]: 150 : if (nvme_ctrlr->disabled) {
2352 [ # # ]: 0 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2353 : 0 : SPDK_NOTICELOG("Unable to perform reset. Controller is disabled.\n");
2354 : 0 : return -EALREADY;
2355 : : }
2356 : :
2357 : 150 : nvme_ctrlr->resetting = true;
2358 : 150 : nvme_ctrlr->dont_retry = true;
2359 : :
2360 [ + + ]: 150 : if (nvme_ctrlr->reconnect_is_delayed) {
2361 [ - + - + ]: 4 : SPDK_DEBUGLOG(bdev_nvme, "Reconnect is already scheduled.\n");
2362 : 4 : msg_fn = bdev_nvme_reconnect_ctrlr_now;
2363 : 4 : nvme_ctrlr->reconnect_is_delayed = false;
2364 : : } else {
2365 : 146 : msg_fn = _bdev_nvme_reset_ctrlr;
2366 [ - + ]: 146 : assert(nvme_ctrlr->reset_start_tsc == 0);
2367 : : }
2368 : :
2369 : 150 : nvme_ctrlr->reset_start_tsc = spdk_get_ticks();
2370 : :
2371 [ - + ]: 150 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2372 : :
2373 : 150 : spdk_thread_send_msg(nvme_ctrlr->thread, msg_fn, nvme_ctrlr);
2374 : 150 : return 0;
2375 : : }
2376 : :
2377 : : static int
2378 : 12 : bdev_nvme_enable_ctrlr(struct nvme_ctrlr *nvme_ctrlr)
2379 : : {
2380 [ - + ]: 12 : pthread_mutex_lock(&nvme_ctrlr->mutex);
2381 [ - + ]: 12 : if (nvme_ctrlr->destruct) {
2382 [ # # ]: 0 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2383 : 0 : return -ENXIO;
2384 : : }
2385 : :
2386 [ - + ]: 12 : if (nvme_ctrlr->resetting) {
2387 [ # # ]: 0 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2388 : 0 : return -EBUSY;
2389 : : }
2390 : :
2391 [ + + ]: 12 : if (!nvme_ctrlr->disabled) {
2392 [ - + ]: 4 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2393 : 4 : return -EALREADY;
2394 : : }
2395 : :
2396 : 8 : nvme_ctrlr->disabled = false;
2397 : 8 : nvme_ctrlr->resetting = true;
2398 : :
2399 : 8 : nvme_ctrlr->reset_start_tsc = spdk_get_ticks();
2400 : :
2401 [ - + ]: 8 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2402 : :
2403 : 8 : spdk_thread_send_msg(nvme_ctrlr->thread, bdev_nvme_reconnect_ctrlr_now, nvme_ctrlr);
2404 : 8 : return 0;
2405 : : }
2406 : :
2407 : : static void
2408 : 8 : _bdev_nvme_disable_ctrlr_complete(struct spdk_io_channel_iter *i, int status)
2409 : : {
2410 : 8 : struct nvme_ctrlr *nvme_ctrlr = spdk_io_channel_iter_get_io_device(i);
2411 : 8 : bdev_nvme_ctrlr_op_cb ctrlr_op_cb_fn = nvme_ctrlr->ctrlr_op_cb_fn;
2412 : 8 : void *ctrlr_op_cb_arg = nvme_ctrlr->ctrlr_op_cb_arg;
2413 : : enum bdev_nvme_op_after_reset op_after_disable;
2414 : :
2415 [ - + ]: 8 : assert(nvme_ctrlr->thread == spdk_get_thread());
2416 : :
2417 : 8 : nvme_ctrlr->ctrlr_op_cb_fn = NULL;
2418 : 8 : nvme_ctrlr->ctrlr_op_cb_arg = NULL;
2419 : :
2420 [ - + ]: 8 : pthread_mutex_lock(&nvme_ctrlr->mutex);
2421 : :
2422 : 8 : nvme_ctrlr->resetting = false;
2423 : 8 : nvme_ctrlr->dont_retry = false;
2424 : :
2425 : 8 : op_after_disable = bdev_nvme_check_op_after_reset(nvme_ctrlr, true);
2426 : :
2427 : 8 : nvme_ctrlr->disabled = true;
2428 : 8 : spdk_poller_pause(nvme_ctrlr->adminq_timer_poller);
2429 : :
2430 [ - + ]: 8 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2431 : :
2432 [ - + ]: 8 : if (ctrlr_op_cb_fn) {
2433 : 0 : ctrlr_op_cb_fn(ctrlr_op_cb_arg, 0);
2434 : : }
2435 : :
2436 [ - + ]: 8 : switch (op_after_disable) {
2437 : 0 : case OP_COMPLETE_PENDING_DESTRUCT:
2438 : 0 : nvme_ctrlr_unregister(nvme_ctrlr);
2439 : 0 : break;
2440 : 8 : default:
2441 : 8 : break;
2442 : : }
2443 : :
2444 : 8 : }
2445 : :
2446 : : static void
2447 : 8 : bdev_nvme_disable_ctrlr_complete(struct nvme_ctrlr *nvme_ctrlr)
2448 : : {
2449 : : /* Make sure we clear any pending resets before returning. */
2450 : 8 : spdk_for_each_channel(nvme_ctrlr,
2451 : : bdev_nvme_complete_pending_resets,
2452 : : NULL,
2453 : : _bdev_nvme_disable_ctrlr_complete);
2454 : 8 : }
2455 : :
2456 : : static void
2457 : 4 : bdev_nvme_disable_destroy_qpairs_done(struct spdk_io_channel_iter *i, int status)
2458 : : {
2459 : 4 : struct nvme_ctrlr *nvme_ctrlr = spdk_io_channel_iter_get_io_device(i);
2460 : :
2461 [ - + ]: 4 : assert(status == 0);
2462 : :
2463 [ - + ]: 4 : if (!spdk_nvme_ctrlr_is_fabrics(nvme_ctrlr->ctrlr)) {
2464 : 0 : bdev_nvme_disable_ctrlr_complete(nvme_ctrlr);
2465 : : } else {
2466 : 4 : nvme_ctrlr_disconnect(nvme_ctrlr, bdev_nvme_disable_ctrlr_complete);
2467 : : }
2468 : 4 : }
2469 : :
2470 : : static void
2471 : 4 : bdev_nvme_disable_destroy_qpairs(struct nvme_ctrlr *nvme_ctrlr)
2472 : : {
2473 : 4 : spdk_for_each_channel(nvme_ctrlr,
2474 : : bdev_nvme_reset_destroy_qpair,
2475 : : NULL,
2476 : : bdev_nvme_disable_destroy_qpairs_done);
2477 : 4 : }
2478 : :
2479 : : static void
2480 : 4 : _bdev_nvme_cancel_reconnect_and_disable_ctrlr(void *ctx)
2481 : : {
2482 : 4 : struct nvme_ctrlr *nvme_ctrlr = ctx;
2483 : :
2484 [ - + ]: 4 : assert(nvme_ctrlr->resetting == true);
2485 [ - + ]: 4 : assert(nvme_ctrlr->thread == spdk_get_thread());
2486 : :
2487 : 4 : spdk_poller_unregister(&nvme_ctrlr->reconnect_delay_timer);
2488 : :
2489 : 4 : bdev_nvme_disable_ctrlr_complete(nvme_ctrlr);
2490 : 4 : }
2491 : :
2492 : : static void
2493 : 4 : _bdev_nvme_disconnect_and_disable_ctrlr(void *ctx)
2494 : : {
2495 : 4 : struct nvme_ctrlr *nvme_ctrlr = ctx;
2496 : :
2497 [ - + ]: 4 : assert(nvme_ctrlr->resetting == true);
2498 [ - + ]: 4 : assert(nvme_ctrlr->thread == spdk_get_thread());
2499 : :
2500 [ - + ]: 4 : if (!spdk_nvme_ctrlr_is_fabrics(nvme_ctrlr->ctrlr)) {
2501 : 0 : nvme_ctrlr_disconnect(nvme_ctrlr, bdev_nvme_disable_destroy_qpairs);
2502 : : } else {
2503 : 4 : bdev_nvme_disable_destroy_qpairs(nvme_ctrlr);
2504 : : }
2505 : 4 : }
2506 : :
2507 : : static int
2508 : 20 : bdev_nvme_disable_ctrlr(struct nvme_ctrlr *nvme_ctrlr)
2509 : : {
2510 : : spdk_msg_fn msg_fn;
2511 : :
2512 [ - + ]: 20 : pthread_mutex_lock(&nvme_ctrlr->mutex);
2513 [ + + ]: 20 : if (nvme_ctrlr->destruct) {
2514 [ - + ]: 4 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2515 : 4 : return -ENXIO;
2516 : : }
2517 : :
2518 [ + + ]: 16 : if (nvme_ctrlr->resetting) {
2519 [ - + ]: 4 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2520 : 4 : return -EBUSY;
2521 : : }
2522 : :
2523 [ + + ]: 12 : if (nvme_ctrlr->disabled) {
2524 [ - + ]: 4 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2525 : 4 : return -EALREADY;
2526 : : }
2527 : :
2528 : 8 : nvme_ctrlr->resetting = true;
2529 : 8 : nvme_ctrlr->dont_retry = true;
2530 : :
2531 [ + + ]: 8 : if (nvme_ctrlr->reconnect_is_delayed) {
2532 : 4 : msg_fn = _bdev_nvme_cancel_reconnect_and_disable_ctrlr;
2533 : 4 : nvme_ctrlr->reconnect_is_delayed = false;
2534 : : } else {
2535 : 4 : msg_fn = _bdev_nvme_disconnect_and_disable_ctrlr;
2536 : : }
2537 : :
2538 : 8 : nvme_ctrlr->reset_start_tsc = spdk_get_ticks();
2539 : :
2540 [ - + ]: 8 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2541 : :
2542 : 8 : spdk_thread_send_msg(nvme_ctrlr->thread, msg_fn, nvme_ctrlr);
2543 : 8 : return 0;
2544 : : }
2545 : :
2546 : : static int
2547 : 110 : nvme_ctrlr_op(struct nvme_ctrlr *nvme_ctrlr, enum nvme_ctrlr_op op,
2548 : : bdev_nvme_ctrlr_op_cb cb_fn, void *cb_arg)
2549 : : {
2550 : : int rc;
2551 : :
2552 [ + - - + ]: 110 : switch (op) {
2553 : 106 : case NVME_CTRLR_OP_RESET:
2554 : 106 : rc = bdev_nvme_reset_ctrlr(nvme_ctrlr);
2555 : 106 : break;
2556 : 0 : case NVME_CTRLR_OP_ENABLE:
2557 : 0 : rc = bdev_nvme_enable_ctrlr(nvme_ctrlr);
2558 : 0 : break;
2559 : 0 : case NVME_CTRLR_OP_DISABLE:
2560 : 0 : rc = bdev_nvme_disable_ctrlr(nvme_ctrlr);
2561 : 0 : break;
2562 : 4 : default:
2563 : 4 : rc = -EINVAL;
2564 : 4 : break;
2565 : : }
2566 : :
2567 [ + + ]: 110 : if (rc == 0) {
2568 [ - + ]: 86 : assert(nvme_ctrlr->ctrlr_op_cb_fn == NULL);
2569 [ - + ]: 86 : assert(nvme_ctrlr->ctrlr_op_cb_arg == NULL);
2570 : 86 : nvme_ctrlr->ctrlr_op_cb_fn = cb_fn;
2571 : 86 : nvme_ctrlr->ctrlr_op_cb_arg = cb_arg;
2572 : : }
2573 : 110 : return rc;
2574 : : }
2575 : :
2576 : : struct nvme_ctrlr_op_rpc_ctx {
2577 : : struct nvme_ctrlr *nvme_ctrlr;
2578 : : struct spdk_thread *orig_thread;
2579 : : enum nvme_ctrlr_op op;
2580 : : int rc;
2581 : : bdev_nvme_ctrlr_op_cb cb_fn;
2582 : : void *cb_arg;
2583 : : };
2584 : :
2585 : : static void
2586 : 16 : _nvme_ctrlr_op_rpc_complete(void *_ctx)
2587 : : {
2588 : 16 : struct nvme_ctrlr_op_rpc_ctx *ctx = _ctx;
2589 : :
2590 [ - + ]: 16 : assert(ctx != NULL);
2591 [ - + ]: 16 : assert(ctx->cb_fn != NULL);
2592 : :
2593 : 16 : ctx->cb_fn(ctx->cb_arg, ctx->rc);
2594 : :
2595 : 16 : free(ctx);
2596 : 16 : }
2597 : :
2598 : : static void
2599 : 16 : nvme_ctrlr_op_rpc_complete(void *cb_arg, int rc)
2600 : : {
2601 : 16 : struct nvme_ctrlr_op_rpc_ctx *ctx = cb_arg;
2602 : :
2603 : 16 : ctx->rc = rc;
2604 : :
2605 : 16 : spdk_thread_send_msg(ctx->orig_thread, _nvme_ctrlr_op_rpc_complete, ctx);
2606 : 16 : }
2607 : :
2608 : : void
2609 : 16 : nvme_ctrlr_op_rpc(struct nvme_ctrlr *nvme_ctrlr, enum nvme_ctrlr_op op,
2610 : : bdev_nvme_ctrlr_op_cb cb_fn, void *cb_arg)
2611 : : {
2612 : : struct nvme_ctrlr_op_rpc_ctx *ctx;
2613 : : int rc;
2614 : :
2615 [ - + ]: 16 : assert(cb_fn != NULL);
2616 : :
2617 : 16 : ctx = calloc(1, sizeof(*ctx));
2618 [ - + ]: 16 : if (ctx == NULL) {
2619 : 0 : SPDK_ERRLOG("Failed to allocate nvme_ctrlr_op_rpc_ctx.\n");
2620 : 0 : cb_fn(cb_arg, -ENOMEM);
2621 : 0 : return;
2622 : : }
2623 : :
2624 : 16 : ctx->orig_thread = spdk_get_thread();
2625 : 16 : ctx->cb_fn = cb_fn;
2626 : 16 : ctx->cb_arg = cb_arg;
2627 : :
2628 : 16 : rc = nvme_ctrlr_op(nvme_ctrlr, op, nvme_ctrlr_op_rpc_complete, ctx);
2629 [ + + ]: 16 : if (rc == 0) {
2630 : 4 : return;
2631 [ - + ]: 12 : } else if (rc == -EALREADY) {
2632 : 0 : rc = 0;
2633 : : }
2634 : :
2635 : 12 : nvme_ctrlr_op_rpc_complete(ctx, rc);
2636 : : }
2637 : :
2638 : : static void nvme_bdev_ctrlr_op_rpc_continue(void *cb_arg, int rc);
2639 : :
2640 : : static void
2641 : 18 : _nvme_bdev_ctrlr_op_rpc_continue(void *_ctx)
2642 : : {
2643 : 18 : struct nvme_ctrlr_op_rpc_ctx *ctx = _ctx;
2644 : : struct nvme_ctrlr *prev_nvme_ctrlr, *next_nvme_ctrlr;
2645 : : int rc;
2646 : :
2647 : 18 : prev_nvme_ctrlr = ctx->nvme_ctrlr;
2648 : 18 : ctx->nvme_ctrlr = NULL;
2649 : :
2650 [ - + ]: 18 : if (ctx->rc != 0) {
2651 : 0 : goto complete;
2652 : : }
2653 : :
2654 : 18 : next_nvme_ctrlr = TAILQ_NEXT(prev_nvme_ctrlr, tailq);
2655 [ + + ]: 18 : if (next_nvme_ctrlr == NULL) {
2656 : 14 : goto complete;
2657 : : }
2658 : :
2659 : 4 : rc = nvme_ctrlr_op(next_nvme_ctrlr, ctx->op, nvme_bdev_ctrlr_op_rpc_continue, ctx);
2660 [ + - ]: 4 : if (rc == 0) {
2661 : 4 : ctx->nvme_ctrlr = next_nvme_ctrlr;
2662 : 4 : return;
2663 [ # # ]: 0 : } else if (rc == -EALREADY) {
2664 : 0 : ctx->nvme_ctrlr = next_nvme_ctrlr;
2665 : 0 : rc = 0;
2666 : : }
2667 : :
2668 : 0 : ctx->rc = rc;
2669 : :
2670 : 14 : complete:
2671 : 14 : ctx->cb_fn(ctx->cb_arg, ctx->rc);
2672 : 14 : free(ctx);
2673 : : }
2674 : :
2675 : : static void
2676 : 18 : nvme_bdev_ctrlr_op_rpc_continue(void *cb_arg, int rc)
2677 : : {
2678 : 18 : struct nvme_ctrlr_op_rpc_ctx *ctx = cb_arg;
2679 : :
2680 : 18 : ctx->rc = rc;
2681 : :
2682 : 18 : spdk_thread_send_msg(ctx->orig_thread, _nvme_bdev_ctrlr_op_rpc_continue, ctx);
2683 : 18 : }
2684 : :
2685 : : void
2686 : 14 : nvme_bdev_ctrlr_op_rpc(struct nvme_bdev_ctrlr *nbdev_ctrlr, enum nvme_ctrlr_op op,
2687 : : bdev_nvme_ctrlr_op_cb cb_fn, void *cb_arg)
2688 : : {
2689 : : struct nvme_ctrlr_op_rpc_ctx *ctx;
2690 : : struct nvme_ctrlr *nvme_ctrlr;
2691 : : int rc;
2692 : :
2693 [ - + ]: 14 : assert(cb_fn != NULL);
2694 : :
2695 : 14 : ctx = calloc(1, sizeof(*ctx));
2696 [ - + ]: 14 : if (ctx == NULL) {
2697 : 0 : SPDK_ERRLOG("Failed to allocate nvme_ctrlr_op_rpc_ctx.\n");
2698 : 0 : cb_fn(cb_arg, -ENOMEM);
2699 : 0 : return;
2700 : : }
2701 : :
2702 : 14 : ctx->orig_thread = spdk_get_thread();
2703 : 14 : ctx->op = op;
2704 : 14 : ctx->cb_fn = cb_fn;
2705 : 14 : ctx->cb_arg = cb_arg;
2706 : :
2707 : 14 : nvme_ctrlr = TAILQ_FIRST(&nbdev_ctrlr->ctrlrs);
2708 [ - + ]: 14 : assert(nvme_ctrlr != NULL);
2709 : :
2710 : 14 : rc = nvme_ctrlr_op(nvme_ctrlr, op, nvme_bdev_ctrlr_op_rpc_continue, ctx);
2711 [ + - ]: 14 : if (rc == 0) {
2712 : 14 : ctx->nvme_ctrlr = nvme_ctrlr;
2713 : 14 : return;
2714 [ # # ]: 0 : } else if (rc == -EALREADY) {
2715 : 0 : ctx->nvme_ctrlr = nvme_ctrlr;
2716 : 0 : rc = 0;
2717 : : }
2718 : :
2719 : 0 : nvme_bdev_ctrlr_op_rpc_continue(ctx, rc);
2720 : : }
2721 : :
2722 : : static int _bdev_nvme_reset_io(struct nvme_io_path *io_path, struct nvme_bdev_io *bio);
2723 : :
2724 : : static void
2725 : 56 : _bdev_nvme_reset_io_complete(struct spdk_io_channel_iter *i, int status)
2726 : : {
2727 : 56 : struct nvme_bdev_io *bio = spdk_io_channel_iter_get_ctx(i);
2728 : : enum spdk_bdev_io_status io_status;
2729 : :
2730 [ + + ]: 56 : if (bio->cpl.cdw0 == 0) {
2731 : 52 : io_status = SPDK_BDEV_IO_STATUS_SUCCESS;
2732 : : } else {
2733 : 4 : io_status = SPDK_BDEV_IO_STATUS_FAILED;
2734 : : }
2735 : :
2736 : 56 : __bdev_nvme_io_complete(spdk_bdev_io_from_ctx(bio), io_status, NULL);
2737 : 56 : }
2738 : :
2739 : : static void
2740 : 76 : bdev_nvme_abort_bdev_channel(struct spdk_io_channel_iter *i)
2741 : : {
2742 : 76 : struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
2743 : 76 : struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(_ch);
2744 : :
2745 : 76 : bdev_nvme_abort_retry_ios(nbdev_ch);
2746 : :
2747 : 76 : spdk_for_each_channel_continue(i, 0);
2748 : 76 : }
2749 : :
2750 : : static void
2751 : 56 : bdev_nvme_reset_io_complete(struct nvme_bdev_io *bio)
2752 : : {
2753 : 56 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
2754 : 56 : struct nvme_bdev *nbdev = (struct nvme_bdev *)bdev_io->bdev->ctxt;
2755 : :
2756 : : /* Abort all queued I/Os for retry. */
2757 : 56 : spdk_for_each_channel(nbdev,
2758 : : bdev_nvme_abort_bdev_channel,
2759 : : bio,
2760 : : _bdev_nvme_reset_io_complete);
2761 : 56 : }
2762 : :
2763 : : static void
2764 : 64 : _bdev_nvme_reset_io_continue(void *ctx)
2765 : : {
2766 : 64 : struct nvme_bdev_io *bio = ctx;
2767 : : struct nvme_io_path *prev_io_path, *next_io_path;
2768 : : int rc;
2769 : :
2770 : 64 : prev_io_path = bio->io_path;
2771 : 64 : bio->io_path = NULL;
2772 : :
2773 [ + + ]: 64 : if (bio->cpl.cdw0 != 0) {
2774 : 4 : goto complete;
2775 : : }
2776 : :
2777 : 60 : next_io_path = STAILQ_NEXT(prev_io_path, stailq);
2778 [ + + ]: 60 : if (next_io_path == NULL) {
2779 : 52 : goto complete;
2780 : : }
2781 : :
2782 : 8 : rc = _bdev_nvme_reset_io(next_io_path, bio);
2783 [ + - ]: 8 : if (rc == 0) {
2784 : 8 : return;
2785 : : }
2786 : :
2787 : 0 : bio->cpl.cdw0 = 1;
2788 : :
2789 : 56 : complete:
2790 : 56 : bdev_nvme_reset_io_complete(bio);
2791 : : }
2792 : :
2793 : : static void
2794 : 64 : bdev_nvme_reset_io_continue(void *cb_arg, int rc)
2795 : : {
2796 : 64 : struct nvme_bdev_io *bio = cb_arg;
2797 : 64 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
2798 : :
2799 : 64 : bio->cpl.cdw0 = (rc == 0) ? 0 : 1;
2800 : :
2801 : 64 : spdk_thread_send_msg(spdk_bdev_io_get_thread(bdev_io), _bdev_nvme_reset_io_continue, bio);
2802 : 64 : }
2803 : :
2804 : : static int
2805 : 76 : _bdev_nvme_reset_io(struct nvme_io_path *io_path, struct nvme_bdev_io *bio)
2806 : : {
2807 : : struct nvme_ctrlr_channel *ctrlr_ch;
2808 : : struct spdk_bdev_io *bdev_io;
2809 : : int rc;
2810 : :
2811 : 76 : rc = nvme_ctrlr_op(io_path->qpair->ctrlr, NVME_CTRLR_OP_RESET,
2812 : : bdev_nvme_reset_io_continue, bio);
2813 [ + + ]: 76 : if (rc == 0) {
2814 [ - + ]: 64 : assert(bio->io_path == NULL);
2815 : 64 : bio->io_path = io_path;
2816 [ + - ]: 12 : } else if (rc == -EBUSY) {
2817 : 12 : ctrlr_ch = io_path->qpair->ctrlr_ch;
2818 [ - + ]: 12 : assert(ctrlr_ch != NULL);
2819 : : /*
2820 : : * Reset call is queued only if it is from the app framework. This is on purpose so that
2821 : : * we don't interfere with the app framework reset strategy. i.e. we are deferring to the
2822 : : * upper level. If they are in the middle of a reset, we won't try to schedule another one.
2823 : : */
2824 : 12 : bdev_io = spdk_bdev_io_from_ctx(bio);
2825 : 12 : TAILQ_INSERT_TAIL(&ctrlr_ch->pending_resets, bdev_io, module_link);
2826 : 12 : rc = 0;
2827 : : }
2828 : :
2829 : 76 : return rc;
2830 : : }
2831 : :
2832 : : static void
2833 : 68 : bdev_nvme_reset_io(struct nvme_bdev_channel *nbdev_ch, struct nvme_bdev_io *bio)
2834 : : {
2835 : : struct nvme_io_path *io_path;
2836 : : int rc;
2837 : :
2838 : 68 : bio->cpl.cdw0 = 0;
2839 : :
2840 : : /* Reset all nvme_ctrlrs of a bdev controller sequentially. */
2841 : 68 : io_path = STAILQ_FIRST(&nbdev_ch->io_path_list);
2842 [ - + ]: 68 : assert(io_path != NULL);
2843 : :
2844 : 68 : rc = _bdev_nvme_reset_io(io_path, bio);
2845 [ - + ]: 68 : if (rc != 0) {
2846 : : /* If the current nvme_ctrlr is disabled, skip it and move to the next nvme_ctrlr. */
2847 : 0 : bdev_nvme_reset_io_continue(bio, rc == -EALREADY);
2848 : : }
2849 : 68 : }
2850 : :
2851 : : static int
2852 : 897 : bdev_nvme_failover_ctrlr_unsafe(struct nvme_ctrlr *nvme_ctrlr, bool remove)
2853 : : {
2854 [ + + ]: 897 : if (nvme_ctrlr->destruct) {
2855 : : /* Don't bother resetting if the controller is in the process of being destructed. */
2856 : 408 : return -ENXIO;
2857 : : }
2858 : :
2859 [ + + ]: 489 : if (nvme_ctrlr->resetting) {
2860 [ + + ]: 32 : if (!nvme_ctrlr->in_failover) {
2861 : 12 : SPDK_NOTICELOG("Reset is already in progress. Defer failover until reset completes.\n");
2862 : :
2863 : : /* Defer failover until reset completes. */
2864 : 12 : nvme_ctrlr->pending_failover = true;
2865 : 12 : return -EINPROGRESS;
2866 : : } else {
2867 : 20 : SPDK_NOTICELOG("Unable to perform failover, already in progress.\n");
2868 : 20 : return -EBUSY;
2869 : : }
2870 : : }
2871 : :
2872 : 457 : bdev_nvme_failover_trid(nvme_ctrlr, remove, true);
2873 : :
2874 [ + + ]: 457 : if (nvme_ctrlr->reconnect_is_delayed) {
2875 : 4 : SPDK_NOTICELOG("Reconnect is already scheduled.\n");
2876 : :
2877 : : /* We rely on the next reconnect for the failover. */
2878 : 4 : return -EALREADY;
2879 : : }
2880 : :
2881 [ - + ]: 453 : if (nvme_ctrlr->disabled) {
2882 : 0 : SPDK_NOTICELOG("Controller is disabled.\n");
2883 : :
2884 : : /* We rely on the enablement for the failover. */
2885 : 0 : return -EALREADY;
2886 : : }
2887 : :
2888 : 453 : nvme_ctrlr->resetting = true;
2889 : 453 : nvme_ctrlr->in_failover = true;
2890 : :
2891 [ - + ]: 453 : assert(nvme_ctrlr->reset_start_tsc == 0);
2892 : 453 : nvme_ctrlr->reset_start_tsc = spdk_get_ticks();
2893 : :
2894 : 453 : return 0;
2895 : : }
2896 : :
2897 : : static int
2898 : 884 : bdev_nvme_failover_ctrlr(struct nvme_ctrlr *nvme_ctrlr)
2899 : : {
2900 : : int rc;
2901 : :
2902 [ - + ]: 884 : pthread_mutex_lock(&nvme_ctrlr->mutex);
2903 : 884 : rc = bdev_nvme_failover_ctrlr_unsafe(nvme_ctrlr, false);
2904 [ - + ]: 884 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
2905 : :
2906 [ + + ]: 884 : if (rc == 0) {
2907 : 444 : spdk_thread_send_msg(nvme_ctrlr->thread, _bdev_nvme_reset_ctrlr, nvme_ctrlr);
2908 [ - + ]: 440 : } else if (rc == -EALREADY) {
2909 : 0 : rc = 0;
2910 : : }
2911 : :
2912 : 884 : return rc;
2913 : : }
2914 : :
2915 : : static int bdev_nvme_unmap(struct nvme_bdev_io *bio, uint64_t offset_blocks,
2916 : : uint64_t num_blocks);
2917 : :
2918 : : static int bdev_nvme_write_zeroes(struct nvme_bdev_io *bio, uint64_t offset_blocks,
2919 : : uint64_t num_blocks);
2920 : :
2921 : : static int bdev_nvme_copy(struct nvme_bdev_io *bio, uint64_t dst_offset_blocks,
2922 : : uint64_t src_offset_blocks,
2923 : : uint64_t num_blocks);
2924 : :
2925 : : static void
2926 : 3397855 : bdev_nvme_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
2927 : : bool success)
2928 : : {
2929 : 3397855 : struct nvme_bdev_io *bio = (struct nvme_bdev_io *)bdev_io->driver_ctx;
2930 : 3397855 : struct spdk_bdev *bdev = bdev_io->bdev;
2931 : : int ret;
2932 : :
2933 [ - + ]: 3397855 : if (!success) {
2934 : 0 : ret = -EINVAL;
2935 : 0 : goto exit;
2936 : : }
2937 : :
2938 [ - + ]: 3397855 : if (spdk_unlikely(!nvme_io_path_is_available(bio->io_path))) {
2939 : 0 : ret = -ENXIO;
2940 : 0 : goto exit;
2941 : : }
2942 : :
2943 : 3397855 : ret = bdev_nvme_readv(bio,
2944 : : bdev_io->u.bdev.iovs,
2945 : : bdev_io->u.bdev.iovcnt,
2946 : : bdev_io->u.bdev.md_buf,
2947 : : bdev_io->u.bdev.num_blocks,
2948 : : bdev_io->u.bdev.offset_blocks,
2949 : : bdev->dif_check_flags,
2950 : : bdev_io->u.bdev.memory_domain,
2951 : : bdev_io->u.bdev.memory_domain_ctx,
2952 : : bdev_io->u.bdev.accel_sequence);
2953 : :
2954 : 3397855 : exit:
2955 [ + + ]: 3397855 : if (spdk_unlikely(ret != 0)) {
2956 : 61773 : bdev_nvme_io_complete(bio, ret);
2957 : : }
2958 : 3397855 : }
2959 : :
2960 : : static inline void
2961 : 37529518 : _bdev_nvme_submit_request(struct nvme_bdev_channel *nbdev_ch, struct spdk_bdev_io *bdev_io)
2962 : : {
2963 : 37529518 : struct nvme_bdev_io *nbdev_io = (struct nvme_bdev_io *)bdev_io->driver_ctx;
2964 : 37529518 : struct spdk_bdev *bdev = bdev_io->bdev;
2965 : : struct nvme_bdev_io *nbdev_io_to_abort;
2966 : 37529518 : int rc = 0;
2967 : :
2968 [ + + + + : 37529518 : switch (bdev_io->type) {
+ + + + +
+ + + + -
- + + - ]
2969 : 18007886 : case SPDK_BDEV_IO_TYPE_READ:
2970 [ + + + + ]: 18007886 : if (bdev_io->u.bdev.iovs && bdev_io->u.bdev.iovs[0].iov_base) {
2971 : 14610031 : rc = bdev_nvme_readv(nbdev_io,
2972 : : bdev_io->u.bdev.iovs,
2973 : : bdev_io->u.bdev.iovcnt,
2974 : : bdev_io->u.bdev.md_buf,
2975 : : bdev_io->u.bdev.num_blocks,
2976 : : bdev_io->u.bdev.offset_blocks,
2977 : : bdev->dif_check_flags,
2978 : : bdev_io->u.bdev.memory_domain,
2979 : : bdev_io->u.bdev.memory_domain_ctx,
2980 : : bdev_io->u.bdev.accel_sequence);
2981 : : } else {
2982 : 3397855 : spdk_bdev_io_get_buf(bdev_io, bdev_nvme_get_buf_cb,
2983 : 3397855 : bdev_io->u.bdev.num_blocks * bdev->blocklen);
2984 : 3397855 : rc = 0;
2985 : : }
2986 : 18007886 : break;
2987 : 16588748 : case SPDK_BDEV_IO_TYPE_WRITE:
2988 : 16588748 : rc = bdev_nvme_writev(nbdev_io,
2989 : : bdev_io->u.bdev.iovs,
2990 : : bdev_io->u.bdev.iovcnt,
2991 : : bdev_io->u.bdev.md_buf,
2992 : : bdev_io->u.bdev.num_blocks,
2993 : : bdev_io->u.bdev.offset_blocks,
2994 : : bdev->dif_check_flags,
2995 : : bdev_io->u.bdev.memory_domain,
2996 : : bdev_io->u.bdev.memory_domain_ctx,
2997 : : bdev_io->u.bdev.accel_sequence);
2998 : 16588748 : break;
2999 : 52 : case SPDK_BDEV_IO_TYPE_COMPARE:
3000 : 52 : rc = bdev_nvme_comparev(nbdev_io,
3001 : : bdev_io->u.bdev.iovs,
3002 : : bdev_io->u.bdev.iovcnt,
3003 : : bdev_io->u.bdev.md_buf,
3004 : : bdev_io->u.bdev.num_blocks,
3005 : : bdev_io->u.bdev.offset_blocks,
3006 : : bdev->dif_check_flags);
3007 : 52 : break;
3008 : 48 : case SPDK_BDEV_IO_TYPE_COMPARE_AND_WRITE:
3009 : 48 : rc = bdev_nvme_comparev_and_writev(nbdev_io,
3010 : : bdev_io->u.bdev.iovs,
3011 : : bdev_io->u.bdev.iovcnt,
3012 : : bdev_io->u.bdev.fused_iovs,
3013 : : bdev_io->u.bdev.fused_iovcnt,
3014 : : bdev_io->u.bdev.md_buf,
3015 : : bdev_io->u.bdev.num_blocks,
3016 : : bdev_io->u.bdev.offset_blocks,
3017 : : bdev->dif_check_flags);
3018 : 48 : break;
3019 : 269290 : case SPDK_BDEV_IO_TYPE_UNMAP:
3020 : 269290 : rc = bdev_nvme_unmap(nbdev_io,
3021 : : bdev_io->u.bdev.offset_blocks,
3022 : : bdev_io->u.bdev.num_blocks);
3023 : 269290 : break;
3024 : 651178 : case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
3025 : 651178 : rc = bdev_nvme_write_zeroes(nbdev_io,
3026 : : bdev_io->u.bdev.offset_blocks,
3027 : : bdev_io->u.bdev.num_blocks);
3028 : 651178 : break;
3029 : 68 : case SPDK_BDEV_IO_TYPE_RESET:
3030 : 68 : nbdev_io->io_path = NULL;
3031 : 68 : bdev_nvme_reset_io(nbdev_ch, nbdev_io);
3032 : 68 : return;
3033 : :
3034 : 1752996 : case SPDK_BDEV_IO_TYPE_FLUSH:
3035 : 1752996 : bdev_nvme_io_complete(nbdev_io, 0);
3036 : 1752996 : return;
3037 : :
3038 : 251867 : case SPDK_BDEV_IO_TYPE_ZONE_APPEND:
3039 : 251867 : rc = bdev_nvme_zone_appendv(nbdev_io,
3040 : : bdev_io->u.bdev.iovs,
3041 : : bdev_io->u.bdev.iovcnt,
3042 : : bdev_io->u.bdev.md_buf,
3043 : : bdev_io->u.bdev.num_blocks,
3044 : : bdev_io->u.bdev.offset_blocks,
3045 : : bdev->dif_check_flags);
3046 : 251867 : break;
3047 : 1 : case SPDK_BDEV_IO_TYPE_GET_ZONE_INFO:
3048 : 1 : rc = bdev_nvme_get_zone_info(nbdev_io,
3049 : : bdev_io->u.zone_mgmt.zone_id,
3050 : : bdev_io->u.zone_mgmt.num_zones,
3051 : 1 : bdev_io->u.zone_mgmt.buf);
3052 : 1 : break;
3053 : 43 : case SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT:
3054 : 43 : rc = bdev_nvme_zone_management(nbdev_io,
3055 : : bdev_io->u.zone_mgmt.zone_id,
3056 : : bdev_io->u.zone_mgmt.zone_action);
3057 : 43 : break;
3058 : 50 : case SPDK_BDEV_IO_TYPE_NVME_ADMIN:
3059 : 50 : nbdev_io->io_path = NULL;
3060 : 50 : bdev_nvme_admin_passthru(nbdev_ch,
3061 : : nbdev_io,
3062 : : &bdev_io->u.nvme_passthru.cmd,
3063 : : bdev_io->u.nvme_passthru.buf,
3064 : : bdev_io->u.nvme_passthru.nbytes);
3065 : 50 : return;
3066 : :
3067 : 102 : case SPDK_BDEV_IO_TYPE_NVME_IO:
3068 : 102 : rc = bdev_nvme_io_passthru(nbdev_io,
3069 : : &bdev_io->u.nvme_passthru.cmd,
3070 : : bdev_io->u.nvme_passthru.buf,
3071 : : bdev_io->u.nvme_passthru.nbytes);
3072 : 102 : break;
3073 : 0 : case SPDK_BDEV_IO_TYPE_NVME_IO_MD:
3074 : 0 : rc = bdev_nvme_io_passthru_md(nbdev_io,
3075 : : &bdev_io->u.nvme_passthru.cmd,
3076 : : bdev_io->u.nvme_passthru.buf,
3077 : : bdev_io->u.nvme_passthru.nbytes,
3078 : : bdev_io->u.nvme_passthru.md_buf,
3079 : : bdev_io->u.nvme_passthru.md_len);
3080 : 0 : break;
3081 : 0 : case SPDK_BDEV_IO_TYPE_NVME_IOV_MD:
3082 : 0 : rc = bdev_nvme_iov_passthru_md(nbdev_io,
3083 : : &bdev_io->u.nvme_passthru.cmd,
3084 : : bdev_io->u.nvme_passthru.iovs,
3085 : : bdev_io->u.nvme_passthru.iovcnt,
3086 : : bdev_io->u.nvme_passthru.nbytes,
3087 : : bdev_io->u.nvme_passthru.md_buf,
3088 : : bdev_io->u.nvme_passthru.md_len);
3089 : 0 : break;
3090 : 7154 : case SPDK_BDEV_IO_TYPE_ABORT:
3091 : 7154 : nbdev_io->io_path = NULL;
3092 : 7154 : nbdev_io_to_abort = (struct nvme_bdev_io *)bdev_io->u.abort.bio_to_abort->driver_ctx;
3093 : 7154 : bdev_nvme_abort(nbdev_ch,
3094 : : nbdev_io,
3095 : : nbdev_io_to_abort);
3096 : 7154 : return;
3097 : :
3098 : 35 : case SPDK_BDEV_IO_TYPE_COPY:
3099 : 35 : rc = bdev_nvme_copy(nbdev_io,
3100 : : bdev_io->u.bdev.offset_blocks,
3101 : : bdev_io->u.bdev.copy.src_offset_blocks,
3102 : : bdev_io->u.bdev.num_blocks);
3103 : 35 : break;
3104 : 0 : default:
3105 : 0 : rc = -EINVAL;
3106 : 0 : break;
3107 : : }
3108 : :
3109 [ + + ]: 35769250 : if (spdk_unlikely(rc != 0)) {
3110 : 132004 : bdev_nvme_io_complete(nbdev_io, rc);
3111 : : }
3112 : : }
3113 : :
3114 : : static void
3115 : 38148026 : bdev_nvme_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
3116 : : {
3117 : 38148026 : struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(ch);
3118 : 38148026 : struct nvme_bdev_io *nbdev_io = (struct nvme_bdev_io *)bdev_io->driver_ctx;
3119 : :
3120 [ + + ]: 38148026 : if (spdk_likely(nbdev_io->submit_tsc == 0)) {
3121 : 38128699 : nbdev_io->submit_tsc = spdk_bdev_io_get_submit_tsc(bdev_io);
3122 : : } else {
3123 : : /* There are cases where submit_tsc != 0, i.e. retry I/O.
3124 : : * We need to update submit_tsc here.
3125 : : */
3126 : 19327 : nbdev_io->submit_tsc = spdk_get_ticks();
3127 : : }
3128 : :
3129 [ + + + + ]: 38148026 : spdk_trace_record(TRACE_BDEV_NVME_IO_START, 0, 0, (uintptr_t)nbdev_io, (uintptr_t)bdev_io);
3130 : 38148026 : nbdev_io->io_path = bdev_nvme_find_io_path(nbdev_ch);
3131 [ + + ]: 38148026 : if (spdk_unlikely(!nbdev_io->io_path)) {
3132 [ + + ]: 621447 : if (!bdev_nvme_io_type_is_admin(bdev_io->type)) {
3133 : 621443 : bdev_nvme_io_complete(nbdev_io, -ENXIO);
3134 : 621443 : return;
3135 : : }
3136 : :
3137 : : /* Admin commands do not use the optimal I/O path.
3138 : : * Simply fall through even if it is not found.
3139 : : */
3140 : : }
3141 : :
3142 : 37526583 : _bdev_nvme_submit_request(nbdev_ch, bdev_io);
3143 : : }
3144 : :
3145 : : static bool
3146 : 2439823 : bdev_nvme_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
3147 : : {
3148 : 2439823 : struct nvme_bdev *nbdev = ctx;
3149 : : struct nvme_ns *nvme_ns;
3150 : : struct spdk_nvme_ns *ns;
3151 : : struct spdk_nvme_ctrlr *ctrlr;
3152 : : const struct spdk_nvme_ctrlr_data *cdata;
3153 : :
3154 : 2439823 : nvme_ns = TAILQ_FIRST(&nbdev->nvme_ns_list);
3155 [ - + ]: 2439823 : assert(nvme_ns != NULL);
3156 : 2439823 : ns = nvme_ns->ns;
3157 [ - + ]: 2439823 : if (ns == NULL) {
3158 : 0 : return false;
3159 : : }
3160 : :
3161 : 2439823 : ctrlr = spdk_nvme_ns_get_ctrlr(ns);
3162 : :
3163 [ + + - + : 2439823 : switch (io_type) {
+ + - + +
+ ]
3164 : 197226 : case SPDK_BDEV_IO_TYPE_READ:
3165 : : case SPDK_BDEV_IO_TYPE_WRITE:
3166 : : case SPDK_BDEV_IO_TYPE_RESET:
3167 : : case SPDK_BDEV_IO_TYPE_FLUSH:
3168 : : case SPDK_BDEV_IO_TYPE_NVME_ADMIN:
3169 : : case SPDK_BDEV_IO_TYPE_NVME_IO:
3170 : : case SPDK_BDEV_IO_TYPE_ABORT:
3171 : 197226 : return true;
3172 : :
3173 : 3471 : case SPDK_BDEV_IO_TYPE_COMPARE:
3174 : 3471 : return spdk_nvme_ns_supports_compare(ns);
3175 : :
3176 : 0 : case SPDK_BDEV_IO_TYPE_NVME_IO_MD:
3177 : 0 : return spdk_nvme_ns_get_md_size(ns) ? true : false;
3178 : :
3179 : 100431 : case SPDK_BDEV_IO_TYPE_UNMAP:
3180 : 100431 : cdata = spdk_nvme_ctrlr_get_data(ctrlr);
3181 : 100431 : return cdata->oncs.dsm;
3182 : :
3183 : 2132968 : case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
3184 : 2132968 : cdata = spdk_nvme_ctrlr_get_data(ctrlr);
3185 : 2132968 : return cdata->oncs.write_zeroes;
3186 : :
3187 : 3471 : case SPDK_BDEV_IO_TYPE_COMPARE_AND_WRITE:
3188 [ + + ]: 3471 : if (spdk_nvme_ctrlr_get_flags(ctrlr) &
3189 : : SPDK_NVME_CTRLR_COMPARE_AND_WRITE_SUPPORTED) {
3190 : 216 : return true;
3191 : : }
3192 : 3255 : return false;
3193 : :
3194 : 0 : case SPDK_BDEV_IO_TYPE_GET_ZONE_INFO:
3195 : : case SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT:
3196 : 0 : return spdk_nvme_ns_get_csi(ns) == SPDK_NVME_CSI_ZNS;
3197 : :
3198 : 1 : case SPDK_BDEV_IO_TYPE_ZONE_APPEND:
3199 [ + - ]: 2 : return spdk_nvme_ns_get_csi(ns) == SPDK_NVME_CSI_ZNS &&
3200 [ + - ]: 1 : spdk_nvme_ctrlr_get_flags(ctrlr) & SPDK_NVME_CTRLR_ZONE_APPEND_SUPPORTED;
3201 : :
3202 : 2231 : case SPDK_BDEV_IO_TYPE_COPY:
3203 : 2231 : cdata = spdk_nvme_ctrlr_get_data(ctrlr);
3204 : 2231 : return cdata->oncs.copy;
3205 : :
3206 : 24 : default:
3207 : 24 : return false;
3208 : : }
3209 : : }
3210 : :
3211 : : static int
3212 : 2042 : nvme_qpair_create(struct nvme_ctrlr *nvme_ctrlr, struct nvme_ctrlr_channel *ctrlr_ch)
3213 : : {
3214 : : struct nvme_qpair *nvme_qpair;
3215 : : struct spdk_io_channel *pg_ch;
3216 : : int rc;
3217 : :
3218 : 2042 : nvme_qpair = calloc(1, sizeof(*nvme_qpair));
3219 [ - + ]: 2042 : if (!nvme_qpair) {
3220 : 0 : SPDK_ERRLOG("Failed to alloc nvme_qpair.\n");
3221 : 0 : return -1;
3222 : : }
3223 : :
3224 : 2042 : TAILQ_INIT(&nvme_qpair->io_path_list);
3225 : :
3226 : 2042 : nvme_qpair->ctrlr = nvme_ctrlr;
3227 : 2042 : nvme_qpair->ctrlr_ch = ctrlr_ch;
3228 : :
3229 : 2042 : pg_ch = spdk_get_io_channel(&g_nvme_bdev_ctrlrs);
3230 [ - + ]: 2042 : if (!pg_ch) {
3231 : 0 : free(nvme_qpair);
3232 : 0 : return -1;
3233 : : }
3234 : :
3235 : 2042 : nvme_qpair->group = spdk_io_channel_get_ctx(pg_ch);
3236 : :
3237 : : #ifdef SPDK_CONFIG_VTUNE
3238 : : nvme_qpair->group->collect_spin_stat = true;
3239 : : #else
3240 : 2042 : nvme_qpair->group->collect_spin_stat = false;
3241 : : #endif
3242 : :
3243 [ + - ]: 2042 : if (!nvme_ctrlr->disabled) {
3244 : : /* If a nvme_ctrlr is disabled, don't try to create qpair for it. Qpair will
3245 : : * be created when it's enabled.
3246 : : */
3247 : 2042 : rc = bdev_nvme_create_qpair(nvme_qpair);
3248 [ - + ]: 2042 : if (rc != 0) {
3249 : : /* nvme_ctrlr can't create IO qpair if connection is down.
3250 : : * If reconnect_delay_sec is non-zero, creating IO qpair is retried
3251 : : * after reconnect_delay_sec seconds. If bdev_retry_count is non-zero,
3252 : : * submitted IO will be queued until IO qpair is successfully created.
3253 : : *
3254 : : * Hence, if both are satisfied, ignore the failure.
3255 : : */
3256 [ # # # # ]: 0 : if (nvme_ctrlr->opts.reconnect_delay_sec == 0 || g_opts.bdev_retry_count == 0) {
3257 : 0 : spdk_put_io_channel(pg_ch);
3258 : 0 : free(nvme_qpair);
3259 : 0 : return rc;
3260 : : }
3261 : : }
3262 : : }
3263 : :
3264 : 2042 : TAILQ_INSERT_TAIL(&nvme_qpair->group->qpair_list, nvme_qpair, tailq);
3265 : :
3266 : 2042 : ctrlr_ch->qpair = nvme_qpair;
3267 : :
3268 [ - + ]: 2042 : pthread_mutex_lock(&nvme_qpair->ctrlr->mutex);
3269 : 2042 : nvme_qpair->ctrlr->ref++;
3270 [ - + ]: 2042 : pthread_mutex_unlock(&nvme_qpair->ctrlr->mutex);
3271 : :
3272 : 2042 : return 0;
3273 : : }
3274 : :
3275 : : static int
3276 : 2042 : bdev_nvme_create_ctrlr_channel_cb(void *io_device, void *ctx_buf)
3277 : : {
3278 : 2042 : struct nvme_ctrlr *nvme_ctrlr = io_device;
3279 : 2042 : struct nvme_ctrlr_channel *ctrlr_ch = ctx_buf;
3280 : :
3281 : 2042 : TAILQ_INIT(&ctrlr_ch->pending_resets);
3282 : :
3283 : 2042 : return nvme_qpair_create(nvme_ctrlr, ctrlr_ch);
3284 : : }
3285 : :
3286 : : static void
3287 : 2042 : nvme_qpair_delete(struct nvme_qpair *nvme_qpair)
3288 : : {
3289 : : struct nvme_io_path *io_path, *next;
3290 : :
3291 [ - + ]: 2042 : assert(nvme_qpair->group != NULL);
3292 : :
3293 [ + + ]: 4114 : TAILQ_FOREACH_SAFE(io_path, &nvme_qpair->io_path_list, tailq, next) {
3294 [ + + ]: 2072 : TAILQ_REMOVE(&nvme_qpair->io_path_list, io_path, tailq);
3295 : 2072 : nvme_io_path_free(io_path);
3296 : : }
3297 : :
3298 [ + + ]: 2042 : TAILQ_REMOVE(&nvme_qpair->group->qpair_list, nvme_qpair, tailq);
3299 : :
3300 : 2042 : spdk_put_io_channel(spdk_io_channel_from_ctx(nvme_qpair->group));
3301 : :
3302 : 2042 : nvme_ctrlr_release(nvme_qpair->ctrlr);
3303 : :
3304 : 2042 : free(nvme_qpair);
3305 : 2042 : }
3306 : :
3307 : : static void
3308 : 2042 : bdev_nvme_destroy_ctrlr_channel_cb(void *io_device, void *ctx_buf)
3309 : : {
3310 : 2042 : struct nvme_ctrlr_channel *ctrlr_ch = ctx_buf;
3311 : : struct nvme_qpair *nvme_qpair;
3312 : :
3313 : 2042 : nvme_qpair = ctrlr_ch->qpair;
3314 [ - + ]: 2042 : assert(nvme_qpair != NULL);
3315 : :
3316 : 2042 : _bdev_nvme_clear_io_path_cache(nvme_qpair);
3317 : :
3318 [ + + ]: 2042 : if (nvme_qpair->qpair != NULL) {
3319 [ + - ]: 1968 : if (ctrlr_ch->reset_iter == NULL) {
3320 : 1968 : spdk_nvme_ctrlr_disconnect_io_qpair(nvme_qpair->qpair);
3321 : : } else {
3322 : : /* Skip current ctrlr_channel in a full reset sequence because
3323 : : * it is being deleted now. The qpair is already being disconnected.
3324 : : * We do not have to restart disconnecting it.
3325 : : */
3326 : 0 : spdk_for_each_channel_continue(ctrlr_ch->reset_iter, 0);
3327 : : }
3328 : :
3329 : : /* We cannot release a reference to the poll group now.
3330 : : * The qpair may be disconnected asynchronously later.
3331 : : * We need to poll it until it is actually disconnected.
3332 : : * Just detach the qpair from the deleting ctrlr_channel.
3333 : : */
3334 : 1968 : nvme_qpair->ctrlr_ch = NULL;
3335 : : } else {
3336 [ - + ]: 74 : assert(ctrlr_ch->reset_iter == NULL);
3337 : :
3338 : 74 : nvme_qpair_delete(nvme_qpair);
3339 : : }
3340 : 2042 : }
3341 : :
3342 : : static inline struct spdk_io_channel *
3343 : 729774 : bdev_nvme_get_accel_channel(struct nvme_poll_group *group)
3344 : : {
3345 [ + + ]: 729774 : if (spdk_unlikely(!group->accel_channel)) {
3346 : 53 : group->accel_channel = spdk_accel_get_io_channel();
3347 [ - + ]: 53 : if (!group->accel_channel) {
3348 : 0 : SPDK_ERRLOG("Cannot get the accel_channel for bdev nvme polling group=%p\n",
3349 : : group);
3350 : 0 : return NULL;
3351 : : }
3352 : : }
3353 : :
3354 : 729774 : return group->accel_channel;
3355 : : }
3356 : :
3357 : : static void
3358 : 0 : bdev_nvme_submit_accel_crc32c(void *ctx, uint32_t *dst, struct iovec *iov,
3359 : : uint32_t iov_cnt, uint32_t seed,
3360 : : spdk_nvme_accel_completion_cb cb_fn, void *cb_arg)
3361 : : {
3362 : : struct spdk_io_channel *accel_ch;
3363 : 0 : struct nvme_poll_group *group = ctx;
3364 : : int rc;
3365 : :
3366 [ # # ]: 0 : assert(cb_fn != NULL);
3367 : :
3368 : 0 : accel_ch = bdev_nvme_get_accel_channel(group);
3369 [ # # ]: 0 : if (spdk_unlikely(accel_ch == NULL)) {
3370 : 0 : cb_fn(cb_arg, -ENOMEM);
3371 : 0 : return;
3372 : : }
3373 : :
3374 : 0 : rc = spdk_accel_submit_crc32cv(accel_ch, dst, iov, iov_cnt, seed, cb_fn, cb_arg);
3375 [ # # ]: 0 : if (rc) {
3376 : : /* For the two cases, spdk_accel_submit_crc32cv does not call the user's cb_fn */
3377 [ # # # # ]: 0 : if (rc == -ENOMEM || rc == -EINVAL) {
3378 : 0 : cb_fn(cb_arg, rc);
3379 : : }
3380 : 0 : SPDK_ERRLOG("Cannot complete the accelerated crc32c operation with iov=%p\n", iov);
3381 : : }
3382 : : }
3383 : :
3384 : : static void
3385 : 729774 : bdev_nvme_finish_sequence(void *seq, spdk_nvme_accel_completion_cb cb_fn, void *cb_arg)
3386 : : {
3387 : 729774 : spdk_accel_sequence_finish(seq, cb_fn, cb_arg);
3388 : 729774 : }
3389 : :
3390 : : static void
3391 : 0 : bdev_nvme_abort_sequence(void *seq)
3392 : : {
3393 : 0 : spdk_accel_sequence_abort(seq);
3394 : 0 : }
3395 : :
3396 : : static void
3397 : 380156 : bdev_nvme_reverse_sequence(void *seq)
3398 : : {
3399 : 380156 : spdk_accel_sequence_reverse(seq);
3400 : 380156 : }
3401 : :
3402 : : static int
3403 : 729774 : bdev_nvme_append_crc32c(void *ctx, void **seq, uint32_t *dst, struct iovec *iovs, uint32_t iovcnt,
3404 : : struct spdk_memory_domain *domain, void *domain_ctx, uint32_t seed,
3405 : : spdk_nvme_accel_step_cb cb_fn, void *cb_arg)
3406 : : {
3407 : : struct spdk_io_channel *ch;
3408 : 729774 : struct nvme_poll_group *group = ctx;
3409 : :
3410 : 729774 : ch = bdev_nvme_get_accel_channel(group);
3411 [ - + ]: 729774 : if (spdk_unlikely(ch == NULL)) {
3412 : 0 : return -ENOMEM;
3413 : : }
3414 : :
3415 : 729774 : return spdk_accel_append_crc32c((struct spdk_accel_sequence **)seq, ch, dst, iovs, iovcnt,
3416 : : domain, domain_ctx, seed, cb_fn, cb_arg);
3417 : : }
3418 : :
3419 : : static struct spdk_nvme_accel_fn_table g_bdev_nvme_accel_fn_table = {
3420 : : .table_size = sizeof(struct spdk_nvme_accel_fn_table),
3421 : : .submit_accel_crc32c = bdev_nvme_submit_accel_crc32c,
3422 : : .append_crc32c = bdev_nvme_append_crc32c,
3423 : : .finish_sequence = bdev_nvme_finish_sequence,
3424 : : .reverse_sequence = bdev_nvme_reverse_sequence,
3425 : : .abort_sequence = bdev_nvme_abort_sequence,
3426 : : };
3427 : :
3428 : : static int
3429 : 1895 : bdev_nvme_create_poll_group_cb(void *io_device, void *ctx_buf)
3430 : : {
3431 : 1895 : struct nvme_poll_group *group = ctx_buf;
3432 : :
3433 : 1895 : TAILQ_INIT(&group->qpair_list);
3434 : :
3435 : 1895 : group->group = spdk_nvme_poll_group_create(group, &g_bdev_nvme_accel_fn_table);
3436 [ - + ]: 1895 : if (group->group == NULL) {
3437 : 0 : return -1;
3438 : : }
3439 : :
3440 : 1895 : group->poller = SPDK_POLLER_REGISTER(bdev_nvme_poll, group, g_opts.nvme_ioq_poll_period_us);
3441 : :
3442 [ - + ]: 1895 : if (group->poller == NULL) {
3443 : 0 : spdk_nvme_poll_group_destroy(group->group);
3444 : 0 : return -1;
3445 : : }
3446 : :
3447 : 1895 : return 0;
3448 : : }
3449 : :
3450 : : static void
3451 : 1895 : bdev_nvme_destroy_poll_group_cb(void *io_device, void *ctx_buf)
3452 : : {
3453 : 1895 : struct nvme_poll_group *group = ctx_buf;
3454 : :
3455 [ - + ]: 1895 : assert(TAILQ_EMPTY(&group->qpair_list));
3456 : :
3457 [ + + ]: 1895 : if (group->accel_channel) {
3458 : 53 : spdk_put_io_channel(group->accel_channel);
3459 : : }
3460 : :
3461 : 1895 : spdk_poller_unregister(&group->poller);
3462 [ - + ]: 1895 : if (spdk_nvme_poll_group_destroy(group->group)) {
3463 : 0 : SPDK_ERRLOG("Unable to destroy a poll group for the NVMe bdev module.\n");
3464 : 0 : assert(false);
3465 : : }
3466 : 1895 : }
3467 : :
3468 : : static struct spdk_io_channel *
3469 : 1930 : bdev_nvme_get_io_channel(void *ctx)
3470 : : {
3471 : 1930 : struct nvme_bdev *nvme_bdev = ctx;
3472 : :
3473 : 1930 : return spdk_get_io_channel(nvme_bdev);
3474 : : }
3475 : :
3476 : : static void *
3477 : 0 : bdev_nvme_get_module_ctx(void *ctx)
3478 : : {
3479 : 0 : struct nvme_bdev *nvme_bdev = ctx;
3480 : : struct nvme_ns *nvme_ns;
3481 : :
3482 [ # # # # ]: 0 : if (!nvme_bdev || nvme_bdev->disk.module != &nvme_if) {
3483 : 0 : return NULL;
3484 : : }
3485 : :
3486 : 0 : nvme_ns = TAILQ_FIRST(&nvme_bdev->nvme_ns_list);
3487 [ # # ]: 0 : if (!nvme_ns) {
3488 : 0 : return NULL;
3489 : : }
3490 : :
3491 : 0 : return nvme_ns->ns;
3492 : : }
3493 : :
3494 : : static const char *
3495 : 0 : _nvme_ana_state_str(enum spdk_nvme_ana_state ana_state)
3496 : : {
3497 [ # # # # : 0 : switch (ana_state) {
# # ]
3498 : 0 : case SPDK_NVME_ANA_OPTIMIZED_STATE:
3499 : 0 : return "optimized";
3500 : 0 : case SPDK_NVME_ANA_NON_OPTIMIZED_STATE:
3501 : 0 : return "non_optimized";
3502 : 0 : case SPDK_NVME_ANA_INACCESSIBLE_STATE:
3503 : 0 : return "inaccessible";
3504 : 0 : case SPDK_NVME_ANA_PERSISTENT_LOSS_STATE:
3505 : 0 : return "persistent_loss";
3506 : 0 : case SPDK_NVME_ANA_CHANGE_STATE:
3507 : 0 : return "change";
3508 : 0 : default:
3509 : 0 : return NULL;
3510 : : }
3511 : : }
3512 : :
3513 : : static int
3514 : 8332 : bdev_nvme_get_memory_domains(void *ctx, struct spdk_memory_domain **domains, int array_size)
3515 : : {
3516 : 8332 : struct spdk_memory_domain **_domains = NULL;
3517 : 8332 : struct nvme_bdev *nbdev = ctx;
3518 : : struct nvme_ns *nvme_ns;
3519 : 8332 : int i = 0, _array_size = array_size;
3520 : 8332 : int rc = 0;
3521 : :
3522 [ + + ]: 16714 : TAILQ_FOREACH(nvme_ns, &nbdev->nvme_ns_list, tailq) {
3523 [ + + + + ]: 8382 : if (domains && array_size >= i) {
3524 : 86 : _domains = &domains[i];
3525 : : } else {
3526 : 8296 : _domains = NULL;
3527 : : }
3528 : 8382 : rc = spdk_nvme_ctrlr_get_memory_domains(nvme_ns->ctrlr->ctrlr, _domains, _array_size);
3529 [ + + ]: 8382 : if (rc > 0) {
3530 : 487 : i += rc;
3531 [ + + ]: 487 : if (_array_size >= rc) {
3532 : 52 : _array_size -= rc;
3533 : : } else {
3534 : 435 : _array_size = 0;
3535 : : }
3536 [ - + ]: 7895 : } else if (rc < 0) {
3537 : 0 : return rc;
3538 : : }
3539 : : }
3540 : :
3541 : 8332 : return i;
3542 : : }
3543 : :
3544 : : static const char *
3545 : 92 : nvme_ctrlr_get_state_str(struct nvme_ctrlr *nvme_ctrlr)
3546 : : {
3547 [ - + ]: 92 : if (nvme_ctrlr->destruct) {
3548 : 0 : return "deleting";
3549 [ - + ]: 92 : } else if (spdk_nvme_ctrlr_is_failed(nvme_ctrlr->ctrlr)) {
3550 : 0 : return "failed";
3551 [ - + ]: 92 : } else if (nvme_ctrlr->resetting) {
3552 : 0 : return "resetting";
3553 [ + + ]: 92 : } else if (nvme_ctrlr->reconnect_is_delayed > 0) {
3554 : 2 : return "reconnect_is_delayed";
3555 [ - + ]: 90 : } else if (nvme_ctrlr->disabled) {
3556 : 0 : return "disabled";
3557 : : } else {
3558 : 90 : return "enabled";
3559 : : }
3560 : : }
3561 : :
3562 : : void
3563 : 92 : nvme_ctrlr_info_json(struct spdk_json_write_ctx *w, struct nvme_ctrlr *nvme_ctrlr)
3564 : 92 : {
3565 : : struct spdk_nvme_transport_id *trid;
3566 : : const struct spdk_nvme_ctrlr_opts *opts;
3567 : : const struct spdk_nvme_ctrlr_data *cdata;
3568 : : struct nvme_path_id *path_id;
3569 : :
3570 : 92 : spdk_json_write_object_begin(w);
3571 : :
3572 : 92 : spdk_json_write_named_string(w, "state", nvme_ctrlr_get_state_str(nvme_ctrlr));
3573 : :
3574 : : #ifdef SPDK_CONFIG_NVME_CUSE
3575 : 92 : size_t cuse_name_size = 128;
3576 [ - + ]: 92 : char cuse_name[cuse_name_size];
3577 : :
3578 : 92 : int rc = spdk_nvme_cuse_get_ctrlr_name(nvme_ctrlr->ctrlr, cuse_name, &cuse_name_size);
3579 [ + + ]: 92 : if (rc == 0) {
3580 : 3 : spdk_json_write_named_string(w, "cuse_device", cuse_name);
3581 : : }
3582 : : #endif
3583 : 92 : trid = &nvme_ctrlr->active_path_id->trid;
3584 : 92 : spdk_json_write_named_object_begin(w, "trid");
3585 : 92 : nvme_bdev_dump_trid_json(trid, w);
3586 : 92 : spdk_json_write_object_end(w);
3587 : :
3588 : 92 : path_id = TAILQ_NEXT(nvme_ctrlr->active_path_id, link);
3589 [ + + ]: 92 : if (path_id != NULL) {
3590 : 15 : spdk_json_write_named_array_begin(w, "alternate_trids");
3591 : : do {
3592 : 20 : trid = &path_id->trid;
3593 : 20 : spdk_json_write_object_begin(w);
3594 : 20 : nvme_bdev_dump_trid_json(trid, w);
3595 : 20 : spdk_json_write_object_end(w);
3596 : :
3597 : 20 : path_id = TAILQ_NEXT(path_id, link);
3598 [ + + ]: 20 : } while (path_id != NULL);
3599 : 15 : spdk_json_write_array_end(w);
3600 : : }
3601 : :
3602 : 92 : cdata = spdk_nvme_ctrlr_get_data(nvme_ctrlr->ctrlr);
3603 : 92 : spdk_json_write_named_uint16(w, "cntlid", cdata->cntlid);
3604 : :
3605 : 92 : opts = spdk_nvme_ctrlr_get_opts(nvme_ctrlr->ctrlr);
3606 : 92 : spdk_json_write_named_object_begin(w, "host");
3607 : 92 : spdk_json_write_named_string(w, "nqn", opts->hostnqn);
3608 : 92 : spdk_json_write_named_string(w, "addr", opts->src_addr);
3609 : 92 : spdk_json_write_named_string(w, "svcid", opts->src_svcid);
3610 : 92 : spdk_json_write_object_end(w);
3611 : :
3612 : 92 : spdk_json_write_object_end(w);
3613 : 92 : }
3614 : :
3615 : : static void
3616 : 989 : nvme_namespace_info_json(struct spdk_json_write_ctx *w,
3617 : : struct nvme_ns *nvme_ns)
3618 : 989 : {
3619 : : struct spdk_nvme_ns *ns;
3620 : : struct spdk_nvme_ctrlr *ctrlr;
3621 : : const struct spdk_nvme_ctrlr_data *cdata;
3622 : : const struct spdk_nvme_transport_id *trid;
3623 : : union spdk_nvme_vs_register vs;
3624 : : const struct spdk_nvme_ns_data *nsdata;
3625 : 791 : char buf[128];
3626 : :
3627 : 989 : ns = nvme_ns->ns;
3628 [ - + ]: 989 : if (ns == NULL) {
3629 : 0 : return;
3630 : : }
3631 : :
3632 : 989 : ctrlr = spdk_nvme_ns_get_ctrlr(ns);
3633 : :
3634 : 989 : cdata = spdk_nvme_ctrlr_get_data(ctrlr);
3635 : 989 : trid = spdk_nvme_ctrlr_get_transport_id(ctrlr);
3636 : 989 : vs = spdk_nvme_ctrlr_get_regs_vs(ctrlr);
3637 : :
3638 : 989 : spdk_json_write_object_begin(w);
3639 : :
3640 [ + + ]: 989 : if (trid->trtype == SPDK_NVME_TRANSPORT_PCIE) {
3641 : 779 : spdk_json_write_named_string(w, "pci_address", trid->traddr);
3642 : : }
3643 : :
3644 : 989 : spdk_json_write_named_object_begin(w, "trid");
3645 : :
3646 : 989 : nvme_bdev_dump_trid_json(trid, w);
3647 : :
3648 : 989 : spdk_json_write_object_end(w);
3649 : :
3650 : : #ifdef SPDK_CONFIG_NVME_CUSE
3651 : 989 : size_t cuse_name_size = 128;
3652 [ - + ]: 989 : char cuse_name[cuse_name_size];
3653 : :
3654 : 989 : int rc = spdk_nvme_cuse_get_ns_name(ctrlr, spdk_nvme_ns_get_id(ns),
3655 : : cuse_name, &cuse_name_size);
3656 [ + + ]: 989 : if (rc == 0) {
3657 : 3 : spdk_json_write_named_string(w, "cuse_device", cuse_name);
3658 : : }
3659 : : #endif
3660 : :
3661 : 989 : spdk_json_write_named_object_begin(w, "ctrlr_data");
3662 : :
3663 : 989 : spdk_json_write_named_uint16(w, "cntlid", cdata->cntlid);
3664 : :
3665 : 989 : spdk_json_write_named_string_fmt(w, "vendor_id", "0x%04x", cdata->vid);
3666 : :
3667 [ - + ]: 989 : snprintf(buf, sizeof(cdata->mn) + 1, "%s", cdata->mn);
3668 : 989 : spdk_str_trim(buf);
3669 : 989 : spdk_json_write_named_string(w, "model_number", buf);
3670 : :
3671 [ - + ]: 989 : snprintf(buf, sizeof(cdata->sn) + 1, "%s", cdata->sn);
3672 : 989 : spdk_str_trim(buf);
3673 : 989 : spdk_json_write_named_string(w, "serial_number", buf);
3674 : :
3675 [ - + ]: 989 : snprintf(buf, sizeof(cdata->fr) + 1, "%s", cdata->fr);
3676 : 989 : spdk_str_trim(buf);
3677 : 989 : spdk_json_write_named_string(w, "firmware_revision", buf);
3678 : :
3679 [ + + ]: 989 : if (cdata->subnqn[0] != '\0') {
3680 : 961 : spdk_json_write_named_string(w, "subnqn", cdata->subnqn);
3681 : : }
3682 : :
3683 : 989 : spdk_json_write_named_object_begin(w, "oacs");
3684 : :
3685 : 989 : spdk_json_write_named_uint32(w, "security", cdata->oacs.security);
3686 : 989 : spdk_json_write_named_uint32(w, "format", cdata->oacs.format);
3687 : 989 : spdk_json_write_named_uint32(w, "firmware", cdata->oacs.firmware);
3688 : 989 : spdk_json_write_named_uint32(w, "ns_manage", cdata->oacs.ns_manage);
3689 : :
3690 : 989 : spdk_json_write_object_end(w);
3691 : :
3692 : 989 : spdk_json_write_named_bool(w, "multi_ctrlr", cdata->cmic.multi_ctrlr);
3693 : 989 : spdk_json_write_named_bool(w, "ana_reporting", cdata->cmic.ana_reporting);
3694 : :
3695 : 989 : spdk_json_write_object_end(w);
3696 : :
3697 : 989 : spdk_json_write_named_object_begin(w, "vs");
3698 : :
3699 : 989 : spdk_json_write_name(w, "nvme_version");
3700 [ - + ]: 989 : if (vs.bits.ter) {
3701 : 0 : spdk_json_write_string_fmt(w, "%u.%u.%u", vs.bits.mjr, vs.bits.mnr, vs.bits.ter);
3702 : : } else {
3703 : 989 : spdk_json_write_string_fmt(w, "%u.%u", vs.bits.mjr, vs.bits.mnr);
3704 : : }
3705 : :
3706 : 989 : spdk_json_write_object_end(w);
3707 : :
3708 : 989 : nsdata = spdk_nvme_ns_get_data(ns);
3709 : :
3710 : 989 : spdk_json_write_named_object_begin(w, "ns_data");
3711 : :
3712 : 989 : spdk_json_write_named_uint32(w, "id", spdk_nvme_ns_get_id(ns));
3713 : :
3714 [ - + ]: 989 : if (cdata->cmic.ana_reporting) {
3715 : 0 : spdk_json_write_named_string(w, "ana_state",
3716 : : _nvme_ana_state_str(nvme_ns->ana_state));
3717 : : }
3718 : :
3719 : 989 : spdk_json_write_named_bool(w, "can_share", nsdata->nmic.can_share);
3720 : :
3721 : 989 : spdk_json_write_object_end(w);
3722 : :
3723 [ + + ]: 989 : if (cdata->oacs.security) {
3724 : 662 : spdk_json_write_named_object_begin(w, "security");
3725 : :
3726 [ - + ]: 662 : spdk_json_write_named_bool(w, "opal", nvme_ns->bdev->opal);
3727 : :
3728 : 662 : spdk_json_write_object_end(w);
3729 : : }
3730 : :
3731 : 989 : spdk_json_write_object_end(w);
3732 : : }
3733 : :
3734 : : static const char *
3735 : 979 : nvme_bdev_get_mp_policy_str(struct nvme_bdev *nbdev)
3736 : : {
3737 [ + - - ]: 979 : switch (nbdev->mp_policy) {
3738 : 979 : case BDEV_NVME_MP_POLICY_ACTIVE_PASSIVE:
3739 : 979 : return "active_passive";
3740 : 0 : case BDEV_NVME_MP_POLICY_ACTIVE_ACTIVE:
3741 : 0 : return "active_active";
3742 : 0 : default:
3743 : 0 : assert(false);
3744 : : return "invalid";
3745 : : }
3746 : : }
3747 : :
3748 : : static int
3749 : 979 : bdev_nvme_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
3750 : : {
3751 : 979 : struct nvme_bdev *nvme_bdev = ctx;
3752 : : struct nvme_ns *nvme_ns;
3753 : :
3754 [ - + ]: 979 : pthread_mutex_lock(&nvme_bdev->mutex);
3755 : 979 : spdk_json_write_named_array_begin(w, "nvme");
3756 [ + + ]: 1968 : TAILQ_FOREACH(nvme_ns, &nvme_bdev->nvme_ns_list, tailq) {
3757 : 989 : nvme_namespace_info_json(w, nvme_ns);
3758 : : }
3759 : 979 : spdk_json_write_array_end(w);
3760 : 979 : spdk_json_write_named_string(w, "mp_policy", nvme_bdev_get_mp_policy_str(nvme_bdev));
3761 [ - + ]: 979 : pthread_mutex_unlock(&nvme_bdev->mutex);
3762 : :
3763 : 979 : return 0;
3764 : : }
3765 : :
3766 : : static void
3767 : 167 : bdev_nvme_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
3768 : : {
3769 : : /* No config per bdev needed */
3770 : 167 : }
3771 : :
3772 : : static uint64_t
3773 : 0 : bdev_nvme_get_spin_time(struct spdk_io_channel *ch)
3774 : : {
3775 : 0 : struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(ch);
3776 : : struct nvme_io_path *io_path;
3777 : : struct nvme_poll_group *group;
3778 : 0 : uint64_t spin_time = 0;
3779 : :
3780 [ # # ]: 0 : STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
3781 : 0 : group = io_path->qpair->group;
3782 : :
3783 [ # # # # : 0 : if (!group || !group->collect_spin_stat) {
# # ]
3784 : 0 : continue;
3785 : : }
3786 : :
3787 [ # # ]: 0 : if (group->end_ticks != 0) {
3788 : 0 : group->spin_ticks += (group->end_ticks - group->start_ticks);
3789 : 0 : group->end_ticks = 0;
3790 : : }
3791 : :
3792 : 0 : spin_time += group->spin_ticks;
3793 : 0 : group->start_ticks = 0;
3794 : 0 : group->spin_ticks = 0;
3795 : : }
3796 : :
3797 [ # # ]: 0 : return (spin_time * 1000000ULL) / spdk_get_ticks_hz();
3798 : : }
3799 : :
3800 : : static void
3801 : 0 : bdev_nvme_reset_device_stat(void *ctx)
3802 : : {
3803 : 0 : struct nvme_bdev *nbdev = ctx;
3804 : :
3805 [ # # ]: 0 : if (nbdev->err_stat != NULL) {
3806 [ # # ]: 0 : memset(nbdev->err_stat, 0, sizeof(struct nvme_error_stat));
3807 : : }
3808 : 0 : }
3809 : :
3810 : : /* JSON string should be lowercases and underscore delimited string. */
3811 : : static void
3812 : 24 : bdev_nvme_format_nvme_status(char *dst, const char *src)
3813 : : {
3814 : 0 : char tmp[256];
3815 : :
3816 : 24 : spdk_strcpy_replace(dst, 256, src, " - ", "_");
3817 : 24 : spdk_strcpy_replace(tmp, 256, dst, "-", "_");
3818 : 24 : spdk_strcpy_replace(dst, 256, tmp, " ", "_");
3819 : 24 : spdk_strlwr(dst);
3820 : 24 : }
3821 : :
3822 : : static void
3823 : 19 : bdev_nvme_dump_device_stat_json(void *ctx, struct spdk_json_write_ctx *w)
3824 : : {
3825 : 19 : struct nvme_bdev *nbdev = ctx;
3826 : 19 : struct spdk_nvme_status status = {};
3827 : : uint16_t sct, sc;
3828 : 0 : char status_json[256];
3829 : : const char *status_str;
3830 : :
3831 [ + + ]: 19 : if (nbdev->err_stat == NULL) {
3832 : 7 : return;
3833 : : }
3834 : :
3835 : 12 : spdk_json_write_named_object_begin(w, "nvme_error");
3836 : :
3837 : 12 : spdk_json_write_named_object_begin(w, "status_type");
3838 [ + + ]: 108 : for (sct = 0; sct < 8; sct++) {
3839 [ + + ]: 96 : if (nbdev->err_stat->status_type[sct] == 0) {
3840 : 84 : continue;
3841 : : }
3842 : 12 : status.sct = sct;
3843 : :
3844 : 12 : status_str = spdk_nvme_cpl_get_status_type_string(&status);
3845 [ - + ]: 12 : assert(status_str != NULL);
3846 : 12 : bdev_nvme_format_nvme_status(status_json, status_str);
3847 : :
3848 : 12 : spdk_json_write_named_uint32(w, status_json, nbdev->err_stat->status_type[sct]);
3849 : : }
3850 : 12 : spdk_json_write_object_end(w);
3851 : :
3852 : 12 : spdk_json_write_named_object_begin(w, "status_code");
3853 [ + + ]: 60 : for (sct = 0; sct < 4; sct++) {
3854 : 48 : status.sct = sct;
3855 [ + + ]: 12336 : for (sc = 0; sc < 256; sc++) {
3856 [ + + ]: 12288 : if (nbdev->err_stat->status[sct][sc] == 0) {
3857 : 12276 : continue;
3858 : : }
3859 : 12 : status.sc = sc;
3860 : :
3861 : 12 : status_str = spdk_nvme_cpl_get_status_string(&status);
3862 [ - + ]: 12 : assert(status_str != NULL);
3863 : 12 : bdev_nvme_format_nvme_status(status_json, status_str);
3864 : :
3865 : 12 : spdk_json_write_named_uint32(w, status_json, nbdev->err_stat->status[sct][sc]);
3866 : : }
3867 : : }
3868 : 12 : spdk_json_write_object_end(w);
3869 : :
3870 : 12 : spdk_json_write_object_end(w);
3871 : : }
3872 : :
3873 : : static bool
3874 : 141225 : bdev_nvme_accel_sequence_supported(void *ctx, enum spdk_bdev_io_type type)
3875 : : {
3876 : 141225 : struct nvme_bdev *nbdev = ctx;
3877 : : struct spdk_nvme_ctrlr *ctrlr;
3878 : :
3879 [ + + + + ]: 141225 : if (!g_opts.allow_accel_sequence) {
3880 : 141099 : return false;
3881 : : }
3882 : :
3883 [ + + ]: 126 : switch (type) {
3884 : 12 : case SPDK_BDEV_IO_TYPE_WRITE:
3885 : : case SPDK_BDEV_IO_TYPE_READ:
3886 : 12 : break;
3887 : 114 : default:
3888 : 114 : return false;
3889 : : }
3890 : :
3891 : 12 : ctrlr = bdev_nvme_get_ctrlr(&nbdev->disk);
3892 [ - + ]: 12 : assert(ctrlr != NULL);
3893 : :
3894 : 12 : return spdk_nvme_ctrlr_get_flags(ctrlr) & SPDK_NVME_CTRLR_ACCEL_SEQUENCE_SUPPORTED;
3895 : : }
3896 : :
3897 : : static const struct spdk_bdev_fn_table nvmelib_fn_table = {
3898 : : .destruct = bdev_nvme_destruct,
3899 : : .submit_request = bdev_nvme_submit_request,
3900 : : .io_type_supported = bdev_nvme_io_type_supported,
3901 : : .get_io_channel = bdev_nvme_get_io_channel,
3902 : : .dump_info_json = bdev_nvme_dump_info_json,
3903 : : .write_config_json = bdev_nvme_write_config_json,
3904 : : .get_spin_time = bdev_nvme_get_spin_time,
3905 : : .get_module_ctx = bdev_nvme_get_module_ctx,
3906 : : .get_memory_domains = bdev_nvme_get_memory_domains,
3907 : : .accel_sequence_supported = bdev_nvme_accel_sequence_supported,
3908 : : .reset_device_stat = bdev_nvme_reset_device_stat,
3909 : : .dump_device_stat_json = bdev_nvme_dump_device_stat_json,
3910 : : };
3911 : :
3912 : : typedef int (*bdev_nvme_parse_ana_log_page_cb)(
3913 : : const struct spdk_nvme_ana_group_descriptor *desc, void *cb_arg);
3914 : :
3915 : : static int
3916 : 184 : bdev_nvme_parse_ana_log_page(struct nvme_ctrlr *nvme_ctrlr,
3917 : : bdev_nvme_parse_ana_log_page_cb cb_fn, void *cb_arg)
3918 : : {
3919 : : struct spdk_nvme_ana_group_descriptor *copied_desc;
3920 : : uint8_t *orig_desc;
3921 : : uint32_t i, desc_size, copy_len;
3922 : 184 : int rc = 0;
3923 : :
3924 [ - + ]: 184 : if (nvme_ctrlr->ana_log_page == NULL) {
3925 : 0 : return -EINVAL;
3926 : : }
3927 : :
3928 : 184 : copied_desc = nvme_ctrlr->copied_ana_desc;
3929 : :
3930 : 184 : orig_desc = (uint8_t *)nvme_ctrlr->ana_log_page + sizeof(struct spdk_nvme_ana_page);
3931 : 184 : copy_len = nvme_ctrlr->max_ana_log_page_size - sizeof(struct spdk_nvme_ana_page);
3932 : :
3933 [ + + ]: 320 : for (i = 0; i < nvme_ctrlr->ana_log_page->num_ana_group_desc; i++) {
3934 [ - + - + ]: 284 : memcpy(copied_desc, orig_desc, copy_len);
3935 : :
3936 : 284 : rc = cb_fn(copied_desc, cb_arg);
3937 [ + + ]: 284 : if (rc != 0) {
3938 : 148 : break;
3939 : : }
3940 : :
3941 : 136 : desc_size = sizeof(struct spdk_nvme_ana_group_descriptor) +
3942 : 136 : copied_desc->num_of_nsid * sizeof(uint32_t);
3943 : 136 : orig_desc += desc_size;
3944 : 136 : copy_len -= desc_size;
3945 : : }
3946 : :
3947 : 184 : return rc;
3948 : : }
3949 : :
3950 : : static int
3951 : 22 : nvme_ns_ana_transition_timedout(void *ctx)
3952 : : {
3953 : 22 : struct nvme_ns *nvme_ns = ctx;
3954 : :
3955 : 22 : spdk_poller_unregister(&nvme_ns->anatt_timer);
3956 : 22 : nvme_ns->ana_transition_timedout = true;
3957 : :
3958 : 22 : return SPDK_POLLER_BUSY;
3959 : : }
3960 : :
3961 : : static void
3962 : 204 : _nvme_ns_set_ana_state(struct nvme_ns *nvme_ns,
3963 : : const struct spdk_nvme_ana_group_descriptor *desc)
3964 : : {
3965 : : const struct spdk_nvme_ctrlr_data *cdata;
3966 : :
3967 : 204 : nvme_ns->ana_group_id = desc->ana_group_id;
3968 : 204 : nvme_ns->ana_state = desc->ana_state;
3969 : 204 : nvme_ns->ana_state_updating = false;
3970 : :
3971 [ + + + ]: 204 : switch (nvme_ns->ana_state) {
3972 : 168 : case SPDK_NVME_ANA_OPTIMIZED_STATE:
3973 : : case SPDK_NVME_ANA_NON_OPTIMIZED_STATE:
3974 : 168 : nvme_ns->ana_transition_timedout = false;
3975 : 168 : spdk_poller_unregister(&nvme_ns->anatt_timer);
3976 : 168 : break;
3977 : :
3978 : 32 : case SPDK_NVME_ANA_INACCESSIBLE_STATE:
3979 : : case SPDK_NVME_ANA_CHANGE_STATE:
3980 [ + + ]: 32 : if (nvme_ns->anatt_timer != NULL) {
3981 : 6 : break;
3982 : : }
3983 : :
3984 : 26 : cdata = spdk_nvme_ctrlr_get_data(nvme_ns->ctrlr->ctrlr);
3985 : 26 : nvme_ns->anatt_timer = SPDK_POLLER_REGISTER(nvme_ns_ana_transition_timedout,
3986 : : nvme_ns,
3987 : : cdata->anatt * SPDK_SEC_TO_USEC);
3988 : 26 : break;
3989 : 4 : default:
3990 : 4 : break;
3991 : : }
3992 : 204 : }
3993 : :
3994 : : static int
3995 : 240 : nvme_ns_set_ana_state(const struct spdk_nvme_ana_group_descriptor *desc, void *cb_arg)
3996 : : {
3997 : 240 : struct nvme_ns *nvme_ns = cb_arg;
3998 : : uint32_t i;
3999 : :
4000 [ - + ]: 240 : assert(nvme_ns->ns != NULL);
4001 : :
4002 [ + + ]: 328 : for (i = 0; i < desc->num_of_nsid; i++) {
4003 [ + + ]: 236 : if (desc->nsid[i] != spdk_nvme_ns_get_id(nvme_ns->ns)) {
4004 : 88 : continue;
4005 : : }
4006 : :
4007 : 148 : _nvme_ns_set_ana_state(nvme_ns, desc);
4008 : 148 : return 1;
4009 : : }
4010 : :
4011 : 92 : return 0;
4012 : : }
4013 : :
4014 : : static struct spdk_uuid
4015 : 20 : nvme_generate_uuid(const char *sn, uint32_t nsid)
4016 : : {
4017 : 20 : struct spdk_uuid new_uuid, namespace_uuid;
4018 : 20 : char merged_str[SPDK_NVME_CTRLR_SN_LEN + NSID_STR_LEN + 1] = {'\0'};
4019 : : /* This namespace UUID was generated using uuid_generate() method. */
4020 : 20 : const char *namespace_str = {"edaed2de-24bc-4b07-b559-f47ecbe730fd"};
4021 : : int size;
4022 : :
4023 [ - + - + ]: 20 : assert(strlen(sn) <= SPDK_NVME_CTRLR_SN_LEN);
4024 : :
4025 : 20 : spdk_uuid_set_null(&new_uuid);
4026 : 20 : spdk_uuid_set_null(&namespace_uuid);
4027 : :
4028 : 20 : size = snprintf(merged_str, sizeof(merged_str), "%s%"PRIu32, sn, nsid);
4029 [ + - + + ]: 20 : assert(size > 0 && (unsigned long)size < sizeof(merged_str));
4030 : :
4031 : 20 : spdk_uuid_parse(&namespace_uuid, namespace_str);
4032 : :
4033 : 20 : spdk_uuid_generate_sha1(&new_uuid, &namespace_uuid, merged_str, size);
4034 : :
4035 : 20 : return new_uuid;
4036 : : }
4037 : :
4038 : : static int
4039 : 1069 : nvme_disk_create(struct spdk_bdev *disk, const char *base_name,
4040 : : struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns,
4041 : : uint32_t prchk_flags, void *ctx)
4042 : : {
4043 : : const struct spdk_uuid *uuid;
4044 : : const uint8_t *nguid;
4045 : : const struct spdk_nvme_ctrlr_data *cdata;
4046 : : const struct spdk_nvme_ns_data *nsdata;
4047 : : const struct spdk_nvme_ctrlr_opts *opts;
4048 : : enum spdk_nvme_csi csi;
4049 : : uint32_t atomic_bs, phys_bs, bs;
4050 : 1069 : char sn_tmp[SPDK_NVME_CTRLR_SN_LEN + 1] = {'\0'};
4051 : :
4052 : 1069 : cdata = spdk_nvme_ctrlr_get_data(ctrlr);
4053 : 1069 : csi = spdk_nvme_ns_get_csi(ns);
4054 : 1069 : opts = spdk_nvme_ctrlr_get_opts(ctrlr);
4055 : :
4056 [ + + - ]: 1069 : switch (csi) {
4057 : 1067 : case SPDK_NVME_CSI_NVM:
4058 : 1067 : disk->product_name = "NVMe disk";
4059 : 1067 : break;
4060 : 2 : case SPDK_NVME_CSI_ZNS:
4061 : 2 : disk->product_name = "NVMe ZNS disk";
4062 : 2 : disk->zoned = true;
4063 : 2 : disk->zone_size = spdk_nvme_zns_ns_get_zone_size_sectors(ns);
4064 [ # # ]: 2 : disk->max_zone_append_size = spdk_nvme_zns_ctrlr_get_max_zone_append_size(ctrlr) /
4065 : 2 : spdk_nvme_ns_get_extended_sector_size(ns);
4066 : 2 : disk->max_open_zones = spdk_nvme_zns_ns_get_max_open_zones(ns);
4067 : 2 : disk->max_active_zones = spdk_nvme_zns_ns_get_max_active_zones(ns);
4068 : 2 : break;
4069 : 0 : default:
4070 : 0 : SPDK_ERRLOG("unsupported CSI: %u\n", csi);
4071 : 0 : return -ENOTSUP;
4072 : : }
4073 : :
4074 : 1069 : disk->name = spdk_sprintf_alloc("%sn%d", base_name, spdk_nvme_ns_get_id(ns));
4075 [ - + ]: 1069 : if (!disk->name) {
4076 : 0 : return -ENOMEM;
4077 : : }
4078 : :
4079 : 1069 : disk->write_cache = 0;
4080 [ + + ]: 1069 : if (cdata->vwc.present) {
4081 : : /* Enable if the Volatile Write Cache exists */
4082 : 835 : disk->write_cache = 1;
4083 : : }
4084 [ + + ]: 1069 : if (cdata->oncs.write_zeroes) {
4085 : 854 : disk->max_write_zeroes = UINT16_MAX + 1;
4086 : : }
4087 : 1069 : disk->blocklen = spdk_nvme_ns_get_extended_sector_size(ns);
4088 : 1069 : disk->blockcnt = spdk_nvme_ns_get_num_sectors(ns);
4089 : 1069 : disk->max_segment_size = spdk_nvme_ctrlr_get_max_xfer_size(ctrlr);
4090 : : /* NVMe driver will split one request into multiple requests
4091 : : * based on MDTS and stripe boundary, the bdev layer will use
4092 : : * max_segment_size and max_num_segments to split one big IO
4093 : : * into multiple requests, then small request can't run out
4094 : : * of NVMe internal requests data structure.
4095 : : */
4096 [ + + + - ]: 1069 : if (opts && opts->io_queue_requests) {
4097 : 921 : disk->max_num_segments = opts->io_queue_requests / 2;
4098 : : }
4099 : 1069 : disk->optimal_io_boundary = spdk_nvme_ns_get_optimal_io_boundary(ns);
4100 : :
4101 : 1069 : nguid = spdk_nvme_ns_get_nguid(ns);
4102 [ + + ]: 1069 : if (!nguid) {
4103 : 767 : uuid = spdk_nvme_ns_get_uuid(ns);
4104 [ + + ]: 767 : if (uuid) {
4105 : 48 : disk->uuid = *uuid;
4106 [ - + - + ]: 719 : } else if (g_opts.generate_uuids) {
4107 : 0 : spdk_strcpy_pad(sn_tmp, cdata->sn, SPDK_NVME_CTRLR_SN_LEN, '\0');
4108 : 0 : disk->uuid = nvme_generate_uuid(sn_tmp, spdk_nvme_ns_get_id(ns));
4109 : : }
4110 : : } else {
4111 : 302 : memcpy(&disk->uuid, nguid, sizeof(disk->uuid));
4112 : : }
4113 : :
4114 : 1069 : nsdata = spdk_nvme_ns_get_data(ns);
4115 : 1069 : bs = spdk_nvme_ns_get_sector_size(ns);
4116 : 1069 : atomic_bs = bs;
4117 : 1069 : phys_bs = bs;
4118 [ + - ]: 1069 : if (nsdata->nabo == 0) {
4119 [ + + + + ]: 1069 : if (nsdata->nsfeat.ns_atomic_write_unit && nsdata->nawupf) {
4120 : 21 : atomic_bs = bs * (1 + nsdata->nawupf);
4121 : : } else {
4122 : 1048 : atomic_bs = bs * (1 + cdata->awupf);
4123 : : }
4124 : : }
4125 [ + + ]: 1069 : if (nsdata->nsfeat.optperf) {
4126 : 854 : phys_bs = bs * (1 + nsdata->npwg);
4127 : : }
4128 : 1069 : disk->phys_blocklen = spdk_min(phys_bs, atomic_bs);
4129 : :
4130 : 1069 : disk->md_len = spdk_nvme_ns_get_md_size(ns);
4131 [ + + ]: 1069 : if (disk->md_len != 0) {
4132 : 40 : disk->md_interleave = nsdata->flbas.extended;
4133 : 40 : disk->dif_type = (enum spdk_dif_type)spdk_nvme_ns_get_pi_type(ns);
4134 [ - + ]: 40 : if (disk->dif_type != SPDK_DIF_DISABLE) {
4135 : 0 : disk->dif_is_head_of_md = nsdata->dps.md_start;
4136 : 0 : disk->dif_check_flags = prchk_flags;
4137 : : }
4138 : : }
4139 : :
4140 [ + + ]: 1069 : if (!(spdk_nvme_ctrlr_get_flags(ctrlr) &
4141 : : SPDK_NVME_CTRLR_COMPARE_AND_WRITE_SUPPORTED)) {
4142 : 786 : disk->acwu = 0;
4143 [ + - ]: 283 : } else if (nsdata->nsfeat.ns_atomic_write_unit) {
4144 : 283 : disk->acwu = nsdata->nacwu + 1; /* 0-based */
4145 : : } else {
4146 : 0 : disk->acwu = cdata->acwu + 1; /* 0-based */
4147 : : }
4148 : :
4149 [ + + ]: 1069 : if (cdata->oncs.copy) {
4150 : : /* For now bdev interface allows only single segment copy */
4151 : 835 : disk->max_copy = nsdata->mssrl;
4152 : : }
4153 : :
4154 : 1069 : disk->ctxt = ctx;
4155 : 1069 : disk->fn_table = &nvmelib_fn_table;
4156 : 1069 : disk->module = &nvme_if;
4157 : :
4158 : 1069 : return 0;
4159 : : }
4160 : :
4161 : : static struct nvme_bdev *
4162 : 1069 : nvme_bdev_alloc(void)
4163 : : {
4164 : : struct nvme_bdev *bdev;
4165 : : int rc;
4166 : :
4167 : 1069 : bdev = calloc(1, sizeof(*bdev));
4168 [ - + ]: 1069 : if (!bdev) {
4169 : 0 : SPDK_ERRLOG("bdev calloc() failed\n");
4170 : 0 : return NULL;
4171 : : }
4172 : :
4173 [ - + + + ]: 1069 : if (g_opts.nvme_error_stat) {
4174 : 12 : bdev->err_stat = calloc(1, sizeof(struct nvme_error_stat));
4175 [ - + ]: 12 : if (!bdev->err_stat) {
4176 : 0 : SPDK_ERRLOG("err_stat calloc() failed\n");
4177 : 0 : free(bdev);
4178 : 0 : return NULL;
4179 : : }
4180 : : }
4181 : :
4182 [ - + ]: 1069 : rc = pthread_mutex_init(&bdev->mutex, NULL);
4183 [ - + ]: 1069 : if (rc != 0) {
4184 : 0 : free(bdev->err_stat);
4185 : 0 : free(bdev);
4186 : 0 : return NULL;
4187 : : }
4188 : :
4189 : 1069 : bdev->ref = 1;
4190 : 1069 : bdev->mp_policy = BDEV_NVME_MP_POLICY_ACTIVE_PASSIVE;
4191 : 1069 : bdev->mp_selector = BDEV_NVME_MP_SELECTOR_ROUND_ROBIN;
4192 : 1069 : bdev->rr_min_io = UINT32_MAX;
4193 : 1069 : TAILQ_INIT(&bdev->nvme_ns_list);
4194 : :
4195 : 1069 : return bdev;
4196 : : }
4197 : :
4198 : : static int
4199 : 1069 : nvme_bdev_create(struct nvme_ctrlr *nvme_ctrlr, struct nvme_ns *nvme_ns)
4200 : : {
4201 : : struct nvme_bdev *bdev;
4202 : 1069 : struct nvme_bdev_ctrlr *nbdev_ctrlr = nvme_ctrlr->nbdev_ctrlr;
4203 : : int rc;
4204 : :
4205 : 1069 : bdev = nvme_bdev_alloc();
4206 [ - + ]: 1069 : if (bdev == NULL) {
4207 : 0 : SPDK_ERRLOG("Failed to allocate NVMe bdev\n");
4208 : 0 : return -ENOMEM;
4209 : : }
4210 : :
4211 : 1069 : bdev->opal = nvme_ctrlr->opal_dev != NULL;
4212 : :
4213 : 1069 : rc = nvme_disk_create(&bdev->disk, nbdev_ctrlr->name, nvme_ctrlr->ctrlr,
4214 : : nvme_ns->ns, nvme_ctrlr->opts.prchk_flags, bdev);
4215 [ - + ]: 1069 : if (rc != 0) {
4216 : 0 : SPDK_ERRLOG("Failed to create NVMe disk\n");
4217 : 0 : nvme_bdev_free(bdev);
4218 : 0 : return rc;
4219 : : }
4220 : :
4221 : 1069 : spdk_io_device_register(bdev,
4222 : : bdev_nvme_create_bdev_channel_cb,
4223 : : bdev_nvme_destroy_bdev_channel_cb,
4224 : : sizeof(struct nvme_bdev_channel),
4225 : 1069 : bdev->disk.name);
4226 : :
4227 : 1069 : nvme_ns->bdev = bdev;
4228 : 1069 : bdev->nsid = nvme_ns->id;
4229 : 1069 : TAILQ_INSERT_TAIL(&bdev->nvme_ns_list, nvme_ns, tailq);
4230 : :
4231 : 1069 : bdev->nbdev_ctrlr = nbdev_ctrlr;
4232 : 1069 : TAILQ_INSERT_TAIL(&nbdev_ctrlr->bdevs, bdev, tailq);
4233 : :
4234 : 1069 : rc = spdk_bdev_register(&bdev->disk);
4235 [ + + ]: 1069 : if (rc != 0) {
4236 : 6 : SPDK_ERRLOG("spdk_bdev_register() failed\n");
4237 : 6 : spdk_io_device_unregister(bdev, NULL);
4238 : 6 : nvme_ns->bdev = NULL;
4239 [ - + ]: 6 : TAILQ_REMOVE(&nbdev_ctrlr->bdevs, bdev, tailq);
4240 : 6 : nvme_bdev_free(bdev);
4241 : 6 : return rc;
4242 : : }
4243 : :
4244 : 1063 : return 0;
4245 : : }
4246 : :
4247 : : static bool
4248 : 126 : bdev_nvme_compare_ns(struct spdk_nvme_ns *ns1, struct spdk_nvme_ns *ns2)
4249 : : {
4250 : : const struct spdk_nvme_ns_data *nsdata1, *nsdata2;
4251 : : const struct spdk_uuid *uuid1, *uuid2;
4252 : :
4253 : 126 : nsdata1 = spdk_nvme_ns_get_data(ns1);
4254 : 126 : nsdata2 = spdk_nvme_ns_get_data(ns2);
4255 : 126 : uuid1 = spdk_nvme_ns_get_uuid(ns1);
4256 : 126 : uuid2 = spdk_nvme_ns_get_uuid(ns2);
4257 : :
4258 [ - + - + ]: 170 : return memcmp(nsdata1->nguid, nsdata2->nguid, sizeof(nsdata1->nguid)) == 0 &&
4259 [ + + + + ]: 122 : nsdata1->eui64 == nsdata2->eui64 &&
4260 [ + + + + ]: 118 : ((uuid1 == NULL && uuid2 == NULL) ||
4261 [ + + + - : 338 : (uuid1 != NULL && uuid2 != NULL && spdk_uuid_compare(uuid1, uuid2) == 0)) &&
+ + + + ]
4262 : 106 : spdk_nvme_ns_get_csi(ns1) == spdk_nvme_ns_get_csi(ns2);
4263 : : }
4264 : :
4265 : : static bool
4266 : 24 : hotplug_probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
4267 : : struct spdk_nvme_ctrlr_opts *opts)
4268 : : {
4269 : : struct nvme_probe_skip_entry *entry;
4270 : :
4271 [ - + ]: 24 : TAILQ_FOREACH(entry, &g_skipped_nvme_ctrlrs, tailq) {
4272 [ # # ]: 0 : if (spdk_nvme_transport_id_compare(trid, &entry->trid) == 0) {
4273 : 0 : return false;
4274 : : }
4275 : : }
4276 : :
4277 : 24 : opts->arbitration_burst = (uint8_t)g_opts.arbitration_burst;
4278 : 24 : opts->low_priority_weight = (uint8_t)g_opts.low_priority_weight;
4279 : 24 : opts->medium_priority_weight = (uint8_t)g_opts.medium_priority_weight;
4280 : 24 : opts->high_priority_weight = (uint8_t)g_opts.high_priority_weight;
4281 : 24 : opts->disable_read_ana_log_page = true;
4282 : :
4283 [ - + - + ]: 24 : SPDK_DEBUGLOG(bdev_nvme, "Attaching to %s\n", trid->traddr);
4284 : :
4285 : 24 : return true;
4286 : : }
4287 : :
4288 : : static void
4289 : 0 : nvme_abort_cpl(void *ctx, const struct spdk_nvme_cpl *cpl)
4290 : : {
4291 : 0 : struct nvme_ctrlr *nvme_ctrlr = ctx;
4292 : :
4293 [ # # # # ]: 0 : if (spdk_nvme_cpl_is_error(cpl)) {
4294 : 0 : SPDK_WARNLOG("Abort failed. Resetting controller. sc is %u, sct is %u.\n", cpl->status.sc,
4295 : : cpl->status.sct);
4296 : 0 : bdev_nvme_reset_ctrlr(nvme_ctrlr);
4297 [ # # ]: 0 : } else if (cpl->cdw0 & 0x1) {
4298 : 0 : SPDK_WARNLOG("Specified command could not be aborted.\n");
4299 : 0 : bdev_nvme_reset_ctrlr(nvme_ctrlr);
4300 : : }
4301 : 0 : }
4302 : :
4303 : : static void
4304 : 0 : timeout_cb(void *cb_arg, struct spdk_nvme_ctrlr *ctrlr,
4305 : : struct spdk_nvme_qpair *qpair, uint16_t cid)
4306 : : {
4307 : 0 : struct nvme_ctrlr *nvme_ctrlr = cb_arg;
4308 : : union spdk_nvme_csts_register csts;
4309 : : int rc;
4310 : :
4311 [ # # ]: 0 : assert(nvme_ctrlr->ctrlr == ctrlr);
4312 : :
4313 : 0 : SPDK_WARNLOG("Warning: Detected a timeout. ctrlr=%p qpair=%p cid=%u\n", ctrlr, qpair, cid);
4314 : :
4315 : : /* Only try to read CSTS if it's a PCIe controller or we have a timeout on an I/O
4316 : : * queue. (Note: qpair == NULL when there's an admin cmd timeout.) Otherwise we
4317 : : * would submit another fabrics cmd on the admin queue to read CSTS and check for its
4318 : : * completion recursively.
4319 : : */
4320 [ # # # # ]: 0 : if (nvme_ctrlr->active_path_id->trid.trtype == SPDK_NVME_TRANSPORT_PCIE || qpair != NULL) {
4321 : 0 : csts = spdk_nvme_ctrlr_get_regs_csts(ctrlr);
4322 [ # # ]: 0 : if (csts.bits.cfs) {
4323 : 0 : SPDK_ERRLOG("Controller Fatal Status, reset required\n");
4324 : 0 : bdev_nvme_reset_ctrlr(nvme_ctrlr);
4325 : 0 : return;
4326 : : }
4327 : : }
4328 : :
4329 [ # # # # ]: 0 : switch (g_opts.action_on_timeout) {
4330 : 0 : case SPDK_BDEV_NVME_TIMEOUT_ACTION_ABORT:
4331 [ # # ]: 0 : if (qpair) {
4332 : : /* Don't send abort to ctrlr when ctrlr is not available. */
4333 [ # # ]: 0 : pthread_mutex_lock(&nvme_ctrlr->mutex);
4334 [ # # ]: 0 : if (!nvme_ctrlr_is_available(nvme_ctrlr)) {
4335 [ # # ]: 0 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
4336 : 0 : SPDK_NOTICELOG("Quit abort. Ctrlr is not available.\n");
4337 : 0 : return;
4338 : : }
4339 [ # # ]: 0 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
4340 : :
4341 : 0 : rc = spdk_nvme_ctrlr_cmd_abort(ctrlr, qpair, cid,
4342 : : nvme_abort_cpl, nvme_ctrlr);
4343 [ # # ]: 0 : if (rc == 0) {
4344 : 0 : return;
4345 : : }
4346 : :
4347 : 0 : SPDK_ERRLOG("Unable to send abort. Resetting, rc is %d.\n", rc);
4348 : : }
4349 : :
4350 : : /* FALLTHROUGH */
4351 : : case SPDK_BDEV_NVME_TIMEOUT_ACTION_RESET:
4352 : 0 : bdev_nvme_reset_ctrlr(nvme_ctrlr);
4353 : 0 : break;
4354 : 0 : case SPDK_BDEV_NVME_TIMEOUT_ACTION_NONE:
4355 [ # # # # ]: 0 : SPDK_DEBUGLOG(bdev_nvme, "No action for nvme controller timeout.\n");
4356 : 0 : break;
4357 : 0 : default:
4358 : 0 : SPDK_ERRLOG("An invalid timeout action value is found.\n");
4359 : 0 : break;
4360 : : }
4361 : : }
4362 : :
4363 : : static struct nvme_ns *
4364 : 1133 : nvme_ns_alloc(void)
4365 : : {
4366 : : struct nvme_ns *nvme_ns;
4367 : :
4368 : 1133 : nvme_ns = calloc(1, sizeof(struct nvme_ns));
4369 [ - + ]: 1133 : if (nvme_ns == NULL) {
4370 : 0 : return NULL;
4371 : : }
4372 : :
4373 [ - + - + ]: 1133 : if (g_opts.io_path_stat) {
4374 : 0 : nvme_ns->stat = calloc(1, sizeof(struct spdk_bdev_io_stat));
4375 [ # # ]: 0 : if (nvme_ns->stat == NULL) {
4376 : 0 : free(nvme_ns);
4377 : 0 : return NULL;
4378 : : }
4379 : 0 : spdk_bdev_reset_io_stat(nvme_ns->stat, SPDK_BDEV_RESET_STAT_MAXMIN);
4380 : : }
4381 : :
4382 : 1133 : return nvme_ns;
4383 : : }
4384 : :
4385 : : static void
4386 : 1133 : nvme_ns_free(struct nvme_ns *nvme_ns)
4387 : : {
4388 : 1133 : free(nvme_ns->stat);
4389 : 1133 : free(nvme_ns);
4390 : 1133 : }
4391 : :
4392 : : static void
4393 : 1133 : nvme_ctrlr_populate_namespace_done(struct nvme_ns *nvme_ns, int rc)
4394 : : {
4395 : 1133 : struct nvme_ctrlr *nvme_ctrlr = nvme_ns->ctrlr;
4396 : 1133 : struct nvme_async_probe_ctx *ctx = nvme_ns->probe_ctx;
4397 : :
4398 [ + + ]: 1133 : if (rc == 0) {
4399 : 1123 : nvme_ns->probe_ctx = NULL;
4400 [ - + ]: 1123 : pthread_mutex_lock(&nvme_ctrlr->mutex);
4401 : 1123 : nvme_ctrlr->ref++;
4402 [ - + ]: 1123 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
4403 : : } else {
4404 : 10 : RB_REMOVE(nvme_ns_tree, &nvme_ctrlr->namespaces, nvme_ns);
4405 : 10 : nvme_ns_free(nvme_ns);
4406 : : }
4407 : :
4408 [ + + ]: 1133 : if (ctx) {
4409 : 1100 : ctx->populates_in_progress--;
4410 [ + + ]: 1100 : if (ctx->populates_in_progress == 0) {
4411 : 55 : nvme_ctrlr_populate_namespaces_done(nvme_ctrlr, ctx);
4412 : : }
4413 : : }
4414 : 1133 : }
4415 : :
4416 : : static void
4417 : 8 : bdev_nvme_add_io_path(struct spdk_io_channel_iter *i)
4418 : : {
4419 : 8 : struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
4420 : 8 : struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(_ch);
4421 : 8 : struct nvme_ns *nvme_ns = spdk_io_channel_iter_get_ctx(i);
4422 : : int rc;
4423 : :
4424 : 8 : rc = _bdev_nvme_add_io_path(nbdev_ch, nvme_ns);
4425 [ - + ]: 8 : if (rc != 0) {
4426 : 0 : SPDK_ERRLOG("Failed to add I/O path to bdev_channel dynamically.\n");
4427 : : }
4428 : :
4429 : 8 : spdk_for_each_channel_continue(i, rc);
4430 : 8 : }
4431 : :
4432 : : static void
4433 : 8 : bdev_nvme_delete_io_path(struct spdk_io_channel_iter *i)
4434 : : {
4435 : 8 : struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
4436 : 8 : struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(_ch);
4437 : 8 : struct nvme_ns *nvme_ns = spdk_io_channel_iter_get_ctx(i);
4438 : : struct nvme_io_path *io_path;
4439 : :
4440 : 8 : io_path = _bdev_nvme_get_io_path(nbdev_ch, nvme_ns);
4441 [ + - ]: 8 : if (io_path != NULL) {
4442 : 8 : _bdev_nvme_delete_io_path(nbdev_ch, io_path);
4443 : : }
4444 : :
4445 : 8 : spdk_for_each_channel_continue(i, 0);
4446 : 8 : }
4447 : :
4448 : : static void
4449 : 0 : bdev_nvme_add_io_path_failed(struct spdk_io_channel_iter *i, int status)
4450 : : {
4451 : 0 : struct nvme_ns *nvme_ns = spdk_io_channel_iter_get_ctx(i);
4452 : :
4453 : 0 : nvme_ctrlr_populate_namespace_done(nvme_ns, -1);
4454 : 0 : }
4455 : :
4456 : : static void
4457 : 60 : bdev_nvme_add_io_path_done(struct spdk_io_channel_iter *i, int status)
4458 : : {
4459 : 60 : struct nvme_ns *nvme_ns = spdk_io_channel_iter_get_ctx(i);
4460 : 60 : struct nvme_bdev *bdev = spdk_io_channel_iter_get_io_device(i);
4461 : :
4462 [ + - ]: 60 : if (status == 0) {
4463 : 60 : nvme_ctrlr_populate_namespace_done(nvme_ns, 0);
4464 : : } else {
4465 : : /* Delete the added io_paths and fail populating the namespace. */
4466 : 0 : spdk_for_each_channel(bdev,
4467 : : bdev_nvme_delete_io_path,
4468 : : nvme_ns,
4469 : : bdev_nvme_add_io_path_failed);
4470 : : }
4471 : 60 : }
4472 : :
4473 : : static int
4474 : 64 : nvme_bdev_add_ns(struct nvme_bdev *bdev, struct nvme_ns *nvme_ns)
4475 : : {
4476 : : struct nvme_ns *tmp_ns;
4477 : : const struct spdk_nvme_ns_data *nsdata;
4478 : :
4479 : 64 : nsdata = spdk_nvme_ns_get_data(nvme_ns->ns);
4480 [ - + ]: 64 : if (!nsdata->nmic.can_share) {
4481 : 0 : SPDK_ERRLOG("Namespace cannot be shared.\n");
4482 : 0 : return -EINVAL;
4483 : : }
4484 : :
4485 [ - + ]: 64 : pthread_mutex_lock(&bdev->mutex);
4486 : :
4487 : 64 : tmp_ns = TAILQ_FIRST(&bdev->nvme_ns_list);
4488 [ - + ]: 64 : assert(tmp_ns != NULL);
4489 : :
4490 [ + - + + ]: 64 : if (tmp_ns->ns != NULL && !bdev_nvme_compare_ns(nvme_ns->ns, tmp_ns->ns)) {
4491 [ - + ]: 4 : pthread_mutex_unlock(&bdev->mutex);
4492 : 4 : SPDK_ERRLOG("Namespaces are not identical.\n");
4493 : 4 : return -EINVAL;
4494 : : }
4495 : :
4496 : 60 : bdev->ref++;
4497 : 60 : TAILQ_INSERT_TAIL(&bdev->nvme_ns_list, nvme_ns, tailq);
4498 : 60 : nvme_ns->bdev = bdev;
4499 : :
4500 [ - + ]: 60 : pthread_mutex_unlock(&bdev->mutex);
4501 : :
4502 : : /* Add nvme_io_path to nvme_bdev_channels dynamically. */
4503 : 60 : spdk_for_each_channel(bdev,
4504 : : bdev_nvme_add_io_path,
4505 : : nvme_ns,
4506 : : bdev_nvme_add_io_path_done);
4507 : :
4508 : 60 : return 0;
4509 : : }
4510 : :
4511 : : static void
4512 : 1133 : nvme_ctrlr_populate_namespace(struct nvme_ctrlr *nvme_ctrlr, struct nvme_ns *nvme_ns)
4513 : : {
4514 : : struct spdk_nvme_ns *ns;
4515 : : struct nvme_bdev *bdev;
4516 : 1133 : int rc = 0;
4517 : :
4518 : 1133 : ns = spdk_nvme_ctrlr_get_ns(nvme_ctrlr->ctrlr, nvme_ns->id);
4519 [ - + ]: 1133 : if (!ns) {
4520 [ # # # # ]: 0 : SPDK_DEBUGLOG(bdev_nvme, "Invalid NS %d\n", nvme_ns->id);
4521 : 0 : rc = -EINVAL;
4522 : 0 : goto done;
4523 : : }
4524 : :
4525 : 1133 : nvme_ns->ns = ns;
4526 : 1133 : nvme_ns->ana_state = SPDK_NVME_ANA_OPTIMIZED_STATE;
4527 : :
4528 [ + + ]: 1133 : if (nvme_ctrlr->ana_log_page != NULL) {
4529 : 152 : bdev_nvme_parse_ana_log_page(nvme_ctrlr, nvme_ns_set_ana_state, nvme_ns);
4530 : : }
4531 : :
4532 : 1133 : bdev = nvme_bdev_ctrlr_get_bdev(nvme_ctrlr->nbdev_ctrlr, nvme_ns->id);
4533 [ + + ]: 1133 : if (bdev == NULL) {
4534 : 1069 : rc = nvme_bdev_create(nvme_ctrlr, nvme_ns);
4535 : : } else {
4536 : 64 : rc = nvme_bdev_add_ns(bdev, nvme_ns);
4537 [ + + ]: 64 : if (rc == 0) {
4538 : 60 : return;
4539 : : }
4540 : : }
4541 : 4 : done:
4542 : 1073 : nvme_ctrlr_populate_namespace_done(nvme_ns, rc);
4543 : : }
4544 : :
4545 : : static void
4546 : 1123 : nvme_ctrlr_depopulate_namespace_done(struct nvme_ns *nvme_ns)
4547 : : {
4548 : 1123 : struct nvme_ctrlr *nvme_ctrlr = nvme_ns->ctrlr;
4549 : :
4550 [ - + ]: 1123 : assert(nvme_ctrlr != NULL);
4551 : :
4552 [ - + ]: 1123 : pthread_mutex_lock(&nvme_ctrlr->mutex);
4553 : :
4554 : 1123 : RB_REMOVE(nvme_ns_tree, &nvme_ctrlr->namespaces, nvme_ns);
4555 : :
4556 [ + + ]: 1123 : if (nvme_ns->bdev != NULL) {
4557 [ - + ]: 149 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
4558 : 149 : return;
4559 : : }
4560 : :
4561 : 974 : nvme_ns_free(nvme_ns);
4562 [ - + ]: 974 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
4563 : :
4564 : 974 : nvme_ctrlr_release(nvme_ctrlr);
4565 : : }
4566 : :
4567 : : static void
4568 : 54 : bdev_nvme_delete_io_path_done(struct spdk_io_channel_iter *i, int status)
4569 : : {
4570 : 54 : struct nvme_ns *nvme_ns = spdk_io_channel_iter_get_ctx(i);
4571 : :
4572 : 54 : nvme_ctrlr_depopulate_namespace_done(nvme_ns);
4573 : 54 : }
4574 : :
4575 : : static void
4576 : 1123 : nvme_ctrlr_depopulate_namespace(struct nvme_ctrlr *nvme_ctrlr, struct nvme_ns *nvme_ns)
4577 : : {
4578 : : struct nvme_bdev *bdev;
4579 : :
4580 : 1123 : spdk_poller_unregister(&nvme_ns->anatt_timer);
4581 : :
4582 : 1123 : bdev = nvme_ns->bdev;
4583 [ + + ]: 1123 : if (bdev != NULL) {
4584 [ - + ]: 335 : pthread_mutex_lock(&bdev->mutex);
4585 : :
4586 [ - + ]: 335 : assert(bdev->ref > 0);
4587 : 335 : bdev->ref--;
4588 [ + + ]: 335 : if (bdev->ref == 0) {
4589 [ - + ]: 281 : pthread_mutex_unlock(&bdev->mutex);
4590 : :
4591 : 281 : spdk_bdev_unregister(&bdev->disk, NULL, NULL);
4592 : : } else {
4593 : : /* spdk_bdev_unregister() is not called until the last nvme_ns is
4594 : : * depopulated. Hence we need to remove nvme_ns from bdev->nvme_ns_list
4595 : : * and clear nvme_ns->bdev here.
4596 : : */
4597 [ + + ]: 54 : TAILQ_REMOVE(&bdev->nvme_ns_list, nvme_ns, tailq);
4598 : 54 : nvme_ns->bdev = NULL;
4599 : :
4600 [ - + ]: 54 : pthread_mutex_unlock(&bdev->mutex);
4601 : :
4602 : : /* Delete nvme_io_paths from nvme_bdev_channels dynamically. After that,
4603 : : * we call depopulate_namespace_done() to avoid use-after-free.
4604 : : */
4605 : 54 : spdk_for_each_channel(bdev,
4606 : : bdev_nvme_delete_io_path,
4607 : : nvme_ns,
4608 : : bdev_nvme_delete_io_path_done);
4609 : 54 : return;
4610 : : }
4611 : : }
4612 : :
4613 : 1069 : nvme_ctrlr_depopulate_namespace_done(nvme_ns);
4614 : : }
4615 : :
4616 : : static void
4617 : 1070 : nvme_ctrlr_populate_namespaces(struct nvme_ctrlr *nvme_ctrlr,
4618 : : struct nvme_async_probe_ctx *ctx)
4619 : : {
4620 : 1070 : struct spdk_nvme_ctrlr *ctrlr = nvme_ctrlr->ctrlr;
4621 : : struct nvme_ns *nvme_ns, *next;
4622 : : struct spdk_nvme_ns *ns;
4623 : : struct nvme_bdev *bdev;
4624 : : uint32_t nsid;
4625 : : int rc;
4626 : : uint64_t num_sectors;
4627 : :
4628 [ + + ]: 1070 : if (ctx) {
4629 : : /* Initialize this count to 1 to handle the populate functions
4630 : : * calling nvme_ctrlr_populate_namespace_done() immediately.
4631 : : */
4632 : 974 : ctx->populates_in_progress = 1;
4633 : : }
4634 : :
4635 : : /* First loop over our existing namespaces and see if they have been
4636 : : * removed. */
4637 : 1070 : nvme_ns = nvme_ctrlr_get_first_active_ns(nvme_ctrlr);
4638 [ + + ]: 1095 : while (nvme_ns != NULL) {
4639 : 25 : next = nvme_ctrlr_get_next_active_ns(nvme_ctrlr, nvme_ns);
4640 : :
4641 [ + + ]: 25 : if (spdk_nvme_ctrlr_is_active_ns(ctrlr, nvme_ns->id)) {
4642 : : /* NS is still there or added again. Its attributes may have changed. */
4643 : 18 : ns = spdk_nvme_ctrlr_get_ns(ctrlr, nvme_ns->id);
4644 [ + + ]: 18 : if (nvme_ns->ns != ns) {
4645 [ - + ]: 4 : assert(nvme_ns->ns == NULL);
4646 : 4 : nvme_ns->ns = ns;
4647 [ - + - + ]: 4 : SPDK_DEBUGLOG(bdev_nvme, "NSID %u was added\n", nvme_ns->id);
4648 : : }
4649 : :
4650 : 18 : num_sectors = spdk_nvme_ns_get_num_sectors(ns);
4651 : 18 : bdev = nvme_ns->bdev;
4652 [ - + ]: 18 : assert(bdev != NULL);
4653 [ + + ]: 18 : if (bdev->disk.blockcnt != num_sectors) {
4654 : 4 : SPDK_NOTICELOG("NSID %u is resized: bdev name %s, old size %" PRIu64 ", new size %" PRIu64 "\n",
4655 : : nvme_ns->id,
4656 : : bdev->disk.name,
4657 : : bdev->disk.blockcnt,
4658 : : num_sectors);
4659 : 4 : rc = spdk_bdev_notify_blockcnt_change(&bdev->disk, num_sectors);
4660 [ - + ]: 4 : if (rc != 0) {
4661 : 0 : SPDK_ERRLOG("Could not change num blocks for nvme bdev: name %s, errno: %d.\n",
4662 : : bdev->disk.name, rc);
4663 : : }
4664 : : }
4665 : : } else {
4666 : : /* Namespace was removed */
4667 : 7 : nvme_ctrlr_depopulate_namespace(nvme_ctrlr, nvme_ns);
4668 : : }
4669 : :
4670 : 25 : nvme_ns = next;
4671 : : }
4672 : :
4673 : : /* Loop through all of the namespaces at the nvme level and see if any of them are new */
4674 : 1070 : nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr);
4675 [ + + ]: 2221 : while (nsid != 0) {
4676 : 1151 : nvme_ns = nvme_ctrlr_get_ns(nvme_ctrlr, nsid);
4677 : :
4678 [ + + ]: 1151 : if (nvme_ns == NULL) {
4679 : : /* Found a new one */
4680 : 1133 : nvme_ns = nvme_ns_alloc();
4681 [ - + ]: 1133 : if (nvme_ns == NULL) {
4682 : 0 : SPDK_ERRLOG("Failed to allocate namespace\n");
4683 : : /* This just fails to attach the namespace. It may work on a future attempt. */
4684 : 0 : continue;
4685 : : }
4686 : :
4687 : 1133 : nvme_ns->id = nsid;
4688 : 1133 : nvme_ns->ctrlr = nvme_ctrlr;
4689 : :
4690 : 1133 : nvme_ns->bdev = NULL;
4691 : :
4692 [ + + ]: 1133 : if (ctx) {
4693 : 1100 : ctx->populates_in_progress++;
4694 : : }
4695 : 1133 : nvme_ns->probe_ctx = ctx;
4696 : :
4697 : 1133 : RB_INSERT(nvme_ns_tree, &nvme_ctrlr->namespaces, nvme_ns);
4698 : :
4699 : 1133 : nvme_ctrlr_populate_namespace(nvme_ctrlr, nvme_ns);
4700 : : }
4701 : :
4702 : 1151 : nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, nsid);
4703 : : }
4704 : :
4705 [ + + ]: 1070 : if (ctx) {
4706 : : /* Decrement this count now that the loop is over to account
4707 : : * for the one we started with. If the count is then 0, we
4708 : : * know any populate_namespace functions completed immediately,
4709 : : * so we'll kick the callback here.
4710 : : */
4711 : 974 : ctx->populates_in_progress--;
4712 [ + + ]: 974 : if (ctx->populates_in_progress == 0) {
4713 : 919 : nvme_ctrlr_populate_namespaces_done(nvme_ctrlr, ctx);
4714 : : }
4715 : : }
4716 : :
4717 : 1070 : }
4718 : :
4719 : : static void
4720 : 1054 : nvme_ctrlr_depopulate_namespaces(struct nvme_ctrlr *nvme_ctrlr)
4721 : : {
4722 : : struct nvme_ns *nvme_ns, *tmp;
4723 : :
4724 [ + + + - ]: 2170 : RB_FOREACH_SAFE(nvme_ns, nvme_ns_tree, &nvme_ctrlr->namespaces, tmp) {
4725 : 1116 : nvme_ctrlr_depopulate_namespace(nvme_ctrlr, nvme_ns);
4726 : : }
4727 : 1054 : }
4728 : :
4729 : : static uint32_t
4730 : 868 : nvme_ctrlr_get_ana_log_page_size(struct nvme_ctrlr *nvme_ctrlr)
4731 : : {
4732 : 868 : struct spdk_nvme_ctrlr *ctrlr = nvme_ctrlr->ctrlr;
4733 : : const struct spdk_nvme_ctrlr_data *cdata;
4734 : 868 : uint32_t nsid, ns_count = 0;
4735 : :
4736 : 868 : cdata = spdk_nvme_ctrlr_get_data(ctrlr);
4737 : :
4738 [ + + ]: 956 : for (nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr);
4739 [ + + ]: 1696 : nsid != 0; nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, nsid)) {
4740 : 900 : ns_count++;
4741 : : }
4742 : :
4743 : 868 : return sizeof(struct spdk_nvme_ana_page) + cdata->nanagrpid *
4744 : 868 : sizeof(struct spdk_nvme_ana_group_descriptor) + ns_count *
4745 : : sizeof(uint32_t);
4746 : : }
4747 : :
4748 : : static int
4749 : 44 : nvme_ctrlr_set_ana_states(const struct spdk_nvme_ana_group_descriptor *desc,
4750 : : void *cb_arg)
4751 : : {
4752 : 44 : struct nvme_ctrlr *nvme_ctrlr = cb_arg;
4753 : : struct nvme_ns *nvme_ns;
4754 : : uint32_t i, nsid;
4755 : :
4756 [ + + ]: 84 : for (i = 0; i < desc->num_of_nsid; i++) {
4757 : 40 : nsid = desc->nsid[i];
4758 [ - + ]: 40 : if (nsid == 0) {
4759 : 0 : continue;
4760 : : }
4761 : :
4762 : 40 : nvme_ns = nvme_ctrlr_get_ns(nvme_ctrlr, nsid);
4763 : :
4764 [ - + ]: 40 : assert(nvme_ns != NULL);
4765 [ - + ]: 40 : if (nvme_ns == NULL) {
4766 : : /* Target told us that an inactive namespace had an ANA change */
4767 : 0 : continue;
4768 : : }
4769 : :
4770 : 40 : _nvme_ns_set_ana_state(nvme_ns, desc);
4771 : : }
4772 : :
4773 : 44 : return 0;
4774 : : }
4775 : :
4776 : : static void
4777 : 0 : bdev_nvme_disable_read_ana_log_page(struct nvme_ctrlr *nvme_ctrlr)
4778 : : {
4779 : : struct nvme_ns *nvme_ns;
4780 : :
4781 : 0 : spdk_free(nvme_ctrlr->ana_log_page);
4782 : 0 : nvme_ctrlr->ana_log_page = NULL;
4783 : :
4784 [ # # ]: 0 : for (nvme_ns = nvme_ctrlr_get_first_active_ns(nvme_ctrlr);
4785 [ # # ]: 0 : nvme_ns != NULL;
4786 : 0 : nvme_ns = nvme_ctrlr_get_next_active_ns(nvme_ctrlr, nvme_ns)) {
4787 : 0 : nvme_ns->ana_state_updating = false;
4788 : 0 : nvme_ns->ana_state = SPDK_NVME_ANA_OPTIMIZED_STATE;
4789 : : }
4790 : 0 : }
4791 : :
4792 : : static void
4793 : 32 : nvme_ctrlr_read_ana_log_page_done(void *ctx, const struct spdk_nvme_cpl *cpl)
4794 : : {
4795 : 32 : struct nvme_ctrlr *nvme_ctrlr = ctx;
4796 : :
4797 [ + - + - : 32 : if (cpl != NULL && spdk_nvme_cpl_is_success(cpl)) {
+ - ]
4798 : 32 : bdev_nvme_parse_ana_log_page(nvme_ctrlr, nvme_ctrlr_set_ana_states,
4799 : : nvme_ctrlr);
4800 : : } else {
4801 : 0 : bdev_nvme_disable_read_ana_log_page(nvme_ctrlr);
4802 : : }
4803 : :
4804 [ - + ]: 32 : pthread_mutex_lock(&nvme_ctrlr->mutex);
4805 : :
4806 [ - + ]: 32 : assert(nvme_ctrlr->ana_log_page_updating == true);
4807 : 32 : nvme_ctrlr->ana_log_page_updating = false;
4808 : :
4809 [ - + ]: 32 : if (nvme_ctrlr_can_be_unregistered(nvme_ctrlr)) {
4810 [ # # ]: 0 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
4811 : :
4812 : 0 : nvme_ctrlr_unregister(nvme_ctrlr);
4813 : : } else {
4814 [ - + ]: 32 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
4815 : :
4816 : 32 : bdev_nvme_clear_io_path_caches(nvme_ctrlr);
4817 : : }
4818 : 32 : }
4819 : :
4820 : : static int
4821 : 744 : nvme_ctrlr_read_ana_log_page(struct nvme_ctrlr *nvme_ctrlr)
4822 : : {
4823 : : uint32_t ana_log_page_size;
4824 : : int rc;
4825 : :
4826 [ - + ]: 744 : if (nvme_ctrlr->ana_log_page == NULL) {
4827 : 0 : return -EINVAL;
4828 : : }
4829 : :
4830 : 744 : ana_log_page_size = nvme_ctrlr_get_ana_log_page_size(nvme_ctrlr);
4831 : :
4832 [ - + ]: 744 : if (ana_log_page_size > nvme_ctrlr->max_ana_log_page_size) {
4833 : 0 : SPDK_ERRLOG("ANA log page size %" PRIu32 " is larger than allowed %" PRIu32 "\n",
4834 : : ana_log_page_size, nvme_ctrlr->max_ana_log_page_size);
4835 : 0 : return -EINVAL;
4836 : : }
4837 : :
4838 [ - + ]: 744 : pthread_mutex_lock(&nvme_ctrlr->mutex);
4839 [ + + + + ]: 744 : if (!nvme_ctrlr_is_available(nvme_ctrlr) ||
4840 : : nvme_ctrlr->ana_log_page_updating) {
4841 [ - + ]: 712 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
4842 : 712 : return -EBUSY;
4843 : : }
4844 : :
4845 : 32 : nvme_ctrlr->ana_log_page_updating = true;
4846 [ - + ]: 32 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
4847 : :
4848 : 32 : rc = spdk_nvme_ctrlr_cmd_get_log_page(nvme_ctrlr->ctrlr,
4849 : : SPDK_NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS,
4850 : : SPDK_NVME_GLOBAL_NS_TAG,
4851 : 32 : nvme_ctrlr->ana_log_page,
4852 : : ana_log_page_size, 0,
4853 : : nvme_ctrlr_read_ana_log_page_done,
4854 : : nvme_ctrlr);
4855 [ - + ]: 32 : if (rc != 0) {
4856 : 0 : nvme_ctrlr_read_ana_log_page_done(nvme_ctrlr, NULL);
4857 : : }
4858 : :
4859 : 32 : return rc;
4860 : : }
4861 : :
4862 : : static void
4863 : 0 : dummy_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx)
4864 : : {
4865 : 0 : }
4866 : :
4867 : : struct bdev_nvme_set_preferred_path_ctx {
4868 : : struct spdk_bdev_desc *desc;
4869 : : struct nvme_ns *nvme_ns;
4870 : : bdev_nvme_set_preferred_path_cb cb_fn;
4871 : : void *cb_arg;
4872 : : };
4873 : :
4874 : : static void
4875 : 12 : bdev_nvme_set_preferred_path_done(struct spdk_io_channel_iter *i, int status)
4876 : : {
4877 : 12 : struct bdev_nvme_set_preferred_path_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
4878 : :
4879 [ - + ]: 12 : assert(ctx != NULL);
4880 [ - + ]: 12 : assert(ctx->desc != NULL);
4881 [ - + ]: 12 : assert(ctx->cb_fn != NULL);
4882 : :
4883 : 12 : spdk_bdev_close(ctx->desc);
4884 : :
4885 : 12 : ctx->cb_fn(ctx->cb_arg, status);
4886 : :
4887 : 12 : free(ctx);
4888 : 12 : }
4889 : :
4890 : : static void
4891 : 8 : _bdev_nvme_set_preferred_path(struct spdk_io_channel_iter *i)
4892 : : {
4893 : 8 : struct bdev_nvme_set_preferred_path_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
4894 : 8 : struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
4895 : 8 : struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(_ch);
4896 : : struct nvme_io_path *io_path, *prev;
4897 : :
4898 : 8 : prev = NULL;
4899 [ + - ]: 12 : STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
4900 [ + + ]: 12 : if (io_path->nvme_ns == ctx->nvme_ns) {
4901 : 8 : break;
4902 : : }
4903 : 4 : prev = io_path;
4904 : : }
4905 : :
4906 [ + - ]: 8 : if (io_path != NULL) {
4907 [ + + ]: 8 : if (prev != NULL) {
4908 [ - + ]: 4 : STAILQ_REMOVE_AFTER(&nbdev_ch->io_path_list, prev, stailq);
4909 [ - + ]: 4 : STAILQ_INSERT_HEAD(&nbdev_ch->io_path_list, io_path, stailq);
4910 : : }
4911 : :
4912 : : /* We can set io_path to nbdev_ch->current_io_path directly here.
4913 : : * However, it needs to be conditional. To simplify the code,
4914 : : * just clear nbdev_ch->current_io_path and let find_io_path()
4915 : : * fill it.
4916 : : *
4917 : : * Automatic failback may be disabled. Hence even if the io_path is
4918 : : * already at the head, clear nbdev_ch->current_io_path.
4919 : : */
4920 : 8 : bdev_nvme_clear_current_io_path(nbdev_ch);
4921 : : }
4922 : :
4923 : 8 : spdk_for_each_channel_continue(i, 0);
4924 : 8 : }
4925 : :
4926 : : static struct nvme_ns *
4927 : 12 : bdev_nvme_set_preferred_ns(struct nvme_bdev *nbdev, uint16_t cntlid)
4928 : : {
4929 : : struct nvme_ns *nvme_ns, *prev;
4930 : : const struct spdk_nvme_ctrlr_data *cdata;
4931 : :
4932 : 12 : prev = NULL;
4933 [ + - ]: 24 : TAILQ_FOREACH(nvme_ns, &nbdev->nvme_ns_list, tailq) {
4934 : 24 : cdata = spdk_nvme_ctrlr_get_data(nvme_ns->ctrlr->ctrlr);
4935 : :
4936 [ + + ]: 24 : if (cdata->cntlid == cntlid) {
4937 : 12 : break;
4938 : : }
4939 : 12 : prev = nvme_ns;
4940 : : }
4941 : :
4942 [ + - + + ]: 12 : if (nvme_ns != NULL && prev != NULL) {
4943 [ + + ]: 8 : TAILQ_REMOVE(&nbdev->nvme_ns_list, nvme_ns, tailq);
4944 [ + - ]: 8 : TAILQ_INSERT_HEAD(&nbdev->nvme_ns_list, nvme_ns, tailq);
4945 : : }
4946 : :
4947 : 12 : return nvme_ns;
4948 : : }
4949 : :
4950 : : /* This function supports only multipath mode. There is only a single I/O path
4951 : : * for each NVMe-oF controller. Hence, just move the matched I/O path to the
4952 : : * head of the I/O path list for each NVMe bdev channel.
4953 : : *
4954 : : * NVMe bdev channel may be acquired after completing this function. move the
4955 : : * matched namespace to the head of the namespace list for the NVMe bdev too.
4956 : : */
4957 : : void
4958 : 12 : bdev_nvme_set_preferred_path(const char *name, uint16_t cntlid,
4959 : : bdev_nvme_set_preferred_path_cb cb_fn, void *cb_arg)
4960 : : {
4961 : : struct bdev_nvme_set_preferred_path_ctx *ctx;
4962 : : struct spdk_bdev *bdev;
4963 : : struct nvme_bdev *nbdev;
4964 : 12 : int rc = 0;
4965 : :
4966 [ - + ]: 12 : assert(cb_fn != NULL);
4967 : :
4968 : 12 : ctx = calloc(1, sizeof(*ctx));
4969 [ - + ]: 12 : if (ctx == NULL) {
4970 : 0 : SPDK_ERRLOG("Failed to alloc context.\n");
4971 : 0 : rc = -ENOMEM;
4972 : 0 : goto err_alloc;
4973 : : }
4974 : :
4975 : 12 : ctx->cb_fn = cb_fn;
4976 : 12 : ctx->cb_arg = cb_arg;
4977 : :
4978 : 12 : rc = spdk_bdev_open_ext(name, false, dummy_bdev_event_cb, NULL, &ctx->desc);
4979 [ - + ]: 12 : if (rc != 0) {
4980 : 0 : SPDK_ERRLOG("Failed to open bdev %s.\n", name);
4981 : 0 : goto err_open;
4982 : : }
4983 : :
4984 : 12 : bdev = spdk_bdev_desc_get_bdev(ctx->desc);
4985 : :
4986 [ - + ]: 12 : if (bdev->module != &nvme_if) {
4987 : 0 : SPDK_ERRLOG("bdev %s is not registered in this module.\n", name);
4988 : 0 : rc = -ENODEV;
4989 : 0 : goto err_bdev;
4990 : : }
4991 : :
4992 : 12 : nbdev = SPDK_CONTAINEROF(bdev, struct nvme_bdev, disk);
4993 : :
4994 [ - + ]: 12 : pthread_mutex_lock(&nbdev->mutex);
4995 : :
4996 : 12 : ctx->nvme_ns = bdev_nvme_set_preferred_ns(nbdev, cntlid);
4997 [ - + ]: 12 : if (ctx->nvme_ns == NULL) {
4998 [ # # ]: 0 : pthread_mutex_unlock(&nbdev->mutex);
4999 : :
5000 : 0 : SPDK_ERRLOG("bdev %s does not have namespace to controller %u.\n", name, cntlid);
5001 : 0 : rc = -ENODEV;
5002 : 0 : goto err_bdev;
5003 : : }
5004 : :
5005 [ - + ]: 12 : pthread_mutex_unlock(&nbdev->mutex);
5006 : :
5007 : 12 : spdk_for_each_channel(nbdev,
5008 : : _bdev_nvme_set_preferred_path,
5009 : : ctx,
5010 : : bdev_nvme_set_preferred_path_done);
5011 : 12 : return;
5012 : :
5013 : 0 : err_bdev:
5014 : 0 : spdk_bdev_close(ctx->desc);
5015 : 0 : err_open:
5016 : 0 : free(ctx);
5017 : 0 : err_alloc:
5018 : 0 : cb_fn(cb_arg, rc);
5019 : : }
5020 : :
5021 : : struct bdev_nvme_set_multipath_policy_ctx {
5022 : : struct spdk_bdev_desc *desc;
5023 : : bdev_nvme_set_multipath_policy_cb cb_fn;
5024 : : void *cb_arg;
5025 : : };
5026 : :
5027 : : static void
5028 : 12 : bdev_nvme_set_multipath_policy_done(struct spdk_io_channel_iter *i, int status)
5029 : : {
5030 : 12 : struct bdev_nvme_set_multipath_policy_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
5031 : :
5032 [ - + ]: 12 : assert(ctx != NULL);
5033 [ - + ]: 12 : assert(ctx->desc != NULL);
5034 [ - + ]: 12 : assert(ctx->cb_fn != NULL);
5035 : :
5036 : 12 : spdk_bdev_close(ctx->desc);
5037 : :
5038 : 12 : ctx->cb_fn(ctx->cb_arg, status);
5039 : :
5040 : 12 : free(ctx);
5041 : 12 : }
5042 : :
5043 : : static void
5044 : 4 : _bdev_nvme_set_multipath_policy(struct spdk_io_channel_iter *i)
5045 : : {
5046 : 4 : struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
5047 : 4 : struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(_ch);
5048 : 4 : struct nvme_bdev *nbdev = spdk_io_channel_get_io_device(_ch);
5049 : :
5050 : 4 : nbdev_ch->mp_policy = nbdev->mp_policy;
5051 : 4 : nbdev_ch->mp_selector = nbdev->mp_selector;
5052 : 4 : nbdev_ch->rr_min_io = nbdev->rr_min_io;
5053 : 4 : bdev_nvme_clear_current_io_path(nbdev_ch);
5054 : :
5055 : 4 : spdk_for_each_channel_continue(i, 0);
5056 : 4 : }
5057 : :
5058 : : void
5059 : 12 : bdev_nvme_set_multipath_policy(const char *name, enum bdev_nvme_multipath_policy policy,
5060 : : enum bdev_nvme_multipath_selector selector, uint32_t rr_min_io,
5061 : : bdev_nvme_set_multipath_policy_cb cb_fn, void *cb_arg)
5062 : : {
5063 : : struct bdev_nvme_set_multipath_policy_ctx *ctx;
5064 : : struct spdk_bdev *bdev;
5065 : : struct nvme_bdev *nbdev;
5066 : : int rc;
5067 : :
5068 [ - + ]: 12 : assert(cb_fn != NULL);
5069 : :
5070 [ + + + + ]: 12 : if (policy == BDEV_NVME_MP_POLICY_ACTIVE_ACTIVE && selector == BDEV_NVME_MP_SELECTOR_ROUND_ROBIN) {
5071 [ - + ]: 4 : if (rr_min_io == UINT32_MAX) {
5072 : 0 : rr_min_io = 1;
5073 [ - + ]: 4 : } else if (rr_min_io == 0) {
5074 : 0 : rc = -EINVAL;
5075 : 0 : goto exit;
5076 : : }
5077 [ - + ]: 8 : } else if (rr_min_io != UINT32_MAX) {
5078 : 0 : rc = -EINVAL;
5079 : 0 : goto exit;
5080 : : }
5081 : :
5082 : 12 : ctx = calloc(1, sizeof(*ctx));
5083 [ - + ]: 12 : if (ctx == NULL) {
5084 : 0 : SPDK_ERRLOG("Failed to alloc context.\n");
5085 : 0 : rc = -ENOMEM;
5086 : 0 : goto exit;
5087 : : }
5088 : :
5089 : 12 : ctx->cb_fn = cb_fn;
5090 : 12 : ctx->cb_arg = cb_arg;
5091 : :
5092 : 12 : rc = spdk_bdev_open_ext(name, false, dummy_bdev_event_cb, NULL, &ctx->desc);
5093 [ - + ]: 12 : if (rc != 0) {
5094 : 0 : SPDK_ERRLOG("Failed to open bdev %s.\n", name);
5095 : 0 : rc = -ENODEV;
5096 : 0 : goto err_open;
5097 : : }
5098 : :
5099 : 12 : bdev = spdk_bdev_desc_get_bdev(ctx->desc);
5100 [ - + ]: 12 : if (bdev->module != &nvme_if) {
5101 : 0 : SPDK_ERRLOG("bdev %s is not registered in this module.\n", name);
5102 : 0 : rc = -ENODEV;
5103 : 0 : goto err_module;
5104 : : }
5105 : 12 : nbdev = SPDK_CONTAINEROF(bdev, struct nvme_bdev, disk);
5106 : :
5107 [ - + ]: 12 : pthread_mutex_lock(&nbdev->mutex);
5108 : 12 : nbdev->mp_policy = policy;
5109 : 12 : nbdev->mp_selector = selector;
5110 : 12 : nbdev->rr_min_io = rr_min_io;
5111 [ - + ]: 12 : pthread_mutex_unlock(&nbdev->mutex);
5112 : :
5113 : 12 : spdk_for_each_channel(nbdev,
5114 : : _bdev_nvme_set_multipath_policy,
5115 : : ctx,
5116 : : bdev_nvme_set_multipath_policy_done);
5117 : 12 : return;
5118 : :
5119 : 0 : err_module:
5120 : 0 : spdk_bdev_close(ctx->desc);
5121 : 0 : err_open:
5122 : 0 : free(ctx);
5123 : 0 : exit:
5124 : 0 : cb_fn(cb_arg, rc);
5125 : : }
5126 : :
5127 : : static void
5128 : 40 : aer_cb(void *arg, const struct spdk_nvme_cpl *cpl)
5129 : : {
5130 : 40 : struct nvme_ctrlr *nvme_ctrlr = arg;
5131 : : union spdk_nvme_async_event_completion event;
5132 : :
5133 [ + - - + ]: 40 : if (spdk_nvme_cpl_is_error(cpl)) {
5134 : 0 : SPDK_WARNLOG("AER request execute failed\n");
5135 : 0 : return;
5136 : : }
5137 : :
5138 : 40 : event.raw = cpl->cdw0;
5139 [ + - ]: 40 : if ((event.bits.async_event_type == SPDK_NVME_ASYNC_EVENT_TYPE_NOTICE) &&
5140 [ + + ]: 40 : (event.bits.async_event_info == SPDK_NVME_ASYNC_EVENT_NS_ATTR_CHANGED)) {
5141 : 16 : nvme_ctrlr_populate_namespaces(nvme_ctrlr, NULL);
5142 [ + - ]: 24 : } else if ((event.bits.async_event_type == SPDK_NVME_ASYNC_EVENT_TYPE_NOTICE) &&
5143 [ + - ]: 24 : (event.bits.async_event_info == SPDK_NVME_ASYNC_EVENT_ANA_CHANGE)) {
5144 : 24 : nvme_ctrlr_read_ana_log_page(nvme_ctrlr);
5145 : : }
5146 : : }
5147 : :
5148 : : static void
5149 : 1032 : populate_namespaces_cb(struct nvme_async_probe_ctx *ctx, int rc)
5150 : : {
5151 [ + - ]: 1032 : if (ctx->cb_fn) {
5152 : 1032 : ctx->cb_fn(ctx->cb_ctx, ctx->reported_bdevs, rc);
5153 : : }
5154 : :
5155 : 1032 : ctx->namespaces_populated = true;
5156 [ + + + + ]: 1032 : if (ctx->probe_done) {
5157 : : /* The probe was already completed, so we need to free the context
5158 : : * here. This can happen for cases like OCSSD, where we need to
5159 : : * send additional commands to the SSD after attach.
5160 : : */
5161 : 145 : free(ctx);
5162 : : }
5163 : 1032 : }
5164 : :
5165 : : static void
5166 : 1054 : nvme_ctrlr_create_done(struct nvme_ctrlr *nvme_ctrlr,
5167 : : struct nvme_async_probe_ctx *ctx)
5168 : : {
5169 : 1054 : spdk_io_device_register(nvme_ctrlr,
5170 : : bdev_nvme_create_ctrlr_channel_cb,
5171 : : bdev_nvme_destroy_ctrlr_channel_cb,
5172 : : sizeof(struct nvme_ctrlr_channel),
5173 : 1054 : nvme_ctrlr->nbdev_ctrlr->name);
5174 : :
5175 : 1054 : nvme_ctrlr_populate_namespaces(nvme_ctrlr, ctx);
5176 : 1054 : }
5177 : :
5178 : : static void
5179 : 124 : nvme_ctrlr_init_ana_log_page_done(void *_ctx, const struct spdk_nvme_cpl *cpl)
5180 : : {
5181 : 124 : struct nvme_ctrlr *nvme_ctrlr = _ctx;
5182 : 124 : struct nvme_async_probe_ctx *ctx = nvme_ctrlr->probe_ctx;
5183 : :
5184 : 124 : nvme_ctrlr->probe_ctx = NULL;
5185 : :
5186 [ + - - + ]: 124 : if (spdk_nvme_cpl_is_error(cpl)) {
5187 : 0 : nvme_ctrlr_delete(nvme_ctrlr);
5188 : :
5189 [ # # ]: 0 : if (ctx != NULL) {
5190 : 0 : ctx->reported_bdevs = 0;
5191 : 0 : populate_namespaces_cb(ctx, -1);
5192 : : }
5193 : 0 : return;
5194 : : }
5195 : :
5196 : 124 : nvme_ctrlr_create_done(nvme_ctrlr, ctx);
5197 : : }
5198 : :
5199 : : static int
5200 : 124 : nvme_ctrlr_init_ana_log_page(struct nvme_ctrlr *nvme_ctrlr,
5201 : : struct nvme_async_probe_ctx *ctx)
5202 : : {
5203 : 124 : struct spdk_nvme_ctrlr *ctrlr = nvme_ctrlr->ctrlr;
5204 : : const struct spdk_nvme_ctrlr_data *cdata;
5205 : : uint32_t ana_log_page_size;
5206 : :
5207 : 124 : cdata = spdk_nvme_ctrlr_get_data(ctrlr);
5208 : :
5209 : : /* Set buffer size enough to include maximum number of allowed namespaces. */
5210 : 124 : ana_log_page_size = sizeof(struct spdk_nvme_ana_page) + cdata->nanagrpid *
5211 : 124 : sizeof(struct spdk_nvme_ana_group_descriptor) + cdata->mnan *
5212 : : sizeof(uint32_t);
5213 : :
5214 : 124 : nvme_ctrlr->ana_log_page = spdk_zmalloc(ana_log_page_size, 64, NULL,
5215 : : SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
5216 [ - + ]: 124 : if (nvme_ctrlr->ana_log_page == NULL) {
5217 : 0 : SPDK_ERRLOG("could not allocate ANA log page buffer\n");
5218 : 0 : return -ENXIO;
5219 : : }
5220 : :
5221 : : /* Each descriptor in a ANA log page is not ensured to be 8-bytes aligned.
5222 : : * Hence copy each descriptor to a temporary area when parsing it.
5223 : : *
5224 : : * Allocate a buffer whose size is as large as ANA log page buffer because
5225 : : * we do not know the size of a descriptor until actually reading it.
5226 : : */
5227 : 124 : nvme_ctrlr->copied_ana_desc = calloc(1, ana_log_page_size);
5228 [ - + ]: 124 : if (nvme_ctrlr->copied_ana_desc == NULL) {
5229 : 0 : SPDK_ERRLOG("could not allocate a buffer to parse ANA descriptor\n");
5230 : 0 : return -ENOMEM;
5231 : : }
5232 : :
5233 : 124 : nvme_ctrlr->max_ana_log_page_size = ana_log_page_size;
5234 : :
5235 : 124 : nvme_ctrlr->probe_ctx = ctx;
5236 : :
5237 : : /* Then, set the read size only to include the current active namespaces. */
5238 : 124 : ana_log_page_size = nvme_ctrlr_get_ana_log_page_size(nvme_ctrlr);
5239 : :
5240 [ - + ]: 124 : if (ana_log_page_size > nvme_ctrlr->max_ana_log_page_size) {
5241 : 0 : SPDK_ERRLOG("ANA log page size %" PRIu32 " is larger than allowed %" PRIu32 "\n",
5242 : : ana_log_page_size, nvme_ctrlr->max_ana_log_page_size);
5243 : 0 : return -EINVAL;
5244 : : }
5245 : :
5246 : 124 : return spdk_nvme_ctrlr_cmd_get_log_page(ctrlr,
5247 : : SPDK_NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS,
5248 : : SPDK_NVME_GLOBAL_NS_TAG,
5249 : 124 : nvme_ctrlr->ana_log_page,
5250 : : ana_log_page_size, 0,
5251 : : nvme_ctrlr_init_ana_log_page_done,
5252 : : nvme_ctrlr);
5253 : : }
5254 : :
5255 : : /* hostnqn and subnqn were already verified before attaching a controller.
5256 : : * Hence check only the multipath capability and cntlid here.
5257 : : */
5258 : : static bool
5259 : 71 : bdev_nvme_check_multipath(struct nvme_bdev_ctrlr *nbdev_ctrlr, struct spdk_nvme_ctrlr *ctrlr)
5260 : : {
5261 : : struct nvme_ctrlr *tmp;
5262 : : const struct spdk_nvme_ctrlr_data *cdata, *tmp_cdata;
5263 : :
5264 : 71 : cdata = spdk_nvme_ctrlr_get_data(ctrlr);
5265 : :
5266 [ - + ]: 71 : if (!cdata->cmic.multi_ctrlr) {
5267 : 0 : SPDK_ERRLOG("Ctrlr%u does not support multipath.\n", cdata->cntlid);
5268 : 0 : return false;
5269 : : }
5270 : :
5271 [ + + ]: 146 : TAILQ_FOREACH(tmp, &nbdev_ctrlr->ctrlrs, tailq) {
5272 : 79 : tmp_cdata = spdk_nvme_ctrlr_get_data(tmp->ctrlr);
5273 : :
5274 [ - + ]: 79 : if (!tmp_cdata->cmic.multi_ctrlr) {
5275 : 0 : SPDK_ERRLOG("Ctrlr%u does not support multipath.\n", cdata->cntlid);
5276 : 0 : return false;
5277 : : }
5278 [ + + ]: 79 : if (cdata->cntlid == tmp_cdata->cntlid) {
5279 : 4 : SPDK_ERRLOG("cntlid %u are duplicated.\n", tmp_cdata->cntlid);
5280 : 4 : return false;
5281 : : }
5282 : : }
5283 : :
5284 : 67 : return true;
5285 : : }
5286 : :
5287 : : static int
5288 : 1058 : nvme_bdev_ctrlr_create(const char *name, struct nvme_ctrlr *nvme_ctrlr)
5289 : : {
5290 : : struct nvme_bdev_ctrlr *nbdev_ctrlr;
5291 : 1058 : struct spdk_nvme_ctrlr *ctrlr = nvme_ctrlr->ctrlr;
5292 : 1058 : int rc = 0;
5293 : :
5294 [ - + ]: 1058 : pthread_mutex_lock(&g_bdev_nvme_mutex);
5295 : :
5296 : 1058 : nbdev_ctrlr = nvme_bdev_ctrlr_get_by_name(name);
5297 [ + + ]: 1058 : if (nbdev_ctrlr != NULL) {
5298 [ + + ]: 71 : if (!bdev_nvme_check_multipath(nbdev_ctrlr, ctrlr)) {
5299 : 4 : rc = -EINVAL;
5300 : 4 : goto exit;
5301 : : }
5302 : : } else {
5303 : 987 : nbdev_ctrlr = calloc(1, sizeof(*nbdev_ctrlr));
5304 [ - + ]: 987 : if (nbdev_ctrlr == NULL) {
5305 : 0 : SPDK_ERRLOG("Failed to allocate nvme_bdev_ctrlr.\n");
5306 : 0 : rc = -ENOMEM;
5307 : 0 : goto exit;
5308 : : }
5309 [ - + ]: 987 : nbdev_ctrlr->name = strdup(name);
5310 [ - + ]: 987 : if (nbdev_ctrlr->name == NULL) {
5311 : 0 : SPDK_ERRLOG("Failed to allocate name of nvme_bdev_ctrlr.\n");
5312 : 0 : free(nbdev_ctrlr);
5313 : 0 : goto exit;
5314 : : }
5315 : 987 : TAILQ_INIT(&nbdev_ctrlr->ctrlrs);
5316 : 987 : TAILQ_INIT(&nbdev_ctrlr->bdevs);
5317 : 987 : TAILQ_INSERT_TAIL(&g_nvme_bdev_ctrlrs, nbdev_ctrlr, tailq);
5318 : : }
5319 : 1054 : nvme_ctrlr->nbdev_ctrlr = nbdev_ctrlr;
5320 : 1054 : TAILQ_INSERT_TAIL(&nbdev_ctrlr->ctrlrs, nvme_ctrlr, tailq);
5321 : 1058 : exit:
5322 [ - + ]: 1058 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
5323 : 1058 : return rc;
5324 : : }
5325 : :
5326 : : static int
5327 : 1058 : nvme_ctrlr_create(struct spdk_nvme_ctrlr *ctrlr,
5328 : : const char *name,
5329 : : const struct spdk_nvme_transport_id *trid,
5330 : : struct nvme_async_probe_ctx *ctx)
5331 : : {
5332 : : struct nvme_ctrlr *nvme_ctrlr;
5333 : : struct nvme_path_id *path_id;
5334 : : const struct spdk_nvme_ctrlr_data *cdata;
5335 : : int rc;
5336 : :
5337 : 1058 : nvme_ctrlr = calloc(1, sizeof(*nvme_ctrlr));
5338 [ - + ]: 1058 : if (nvme_ctrlr == NULL) {
5339 : 0 : SPDK_ERRLOG("Failed to allocate device struct\n");
5340 : 0 : return -ENOMEM;
5341 : : }
5342 : :
5343 [ - + ]: 1058 : rc = pthread_mutex_init(&nvme_ctrlr->mutex, NULL);
5344 [ - + ]: 1058 : if (rc != 0) {
5345 : 0 : free(nvme_ctrlr);
5346 : 0 : return rc;
5347 : : }
5348 : :
5349 : 1058 : TAILQ_INIT(&nvme_ctrlr->trids);
5350 : :
5351 : 1058 : RB_INIT(&nvme_ctrlr->namespaces);
5352 : :
5353 : 1058 : path_id = calloc(1, sizeof(*path_id));
5354 [ - + ]: 1058 : if (path_id == NULL) {
5355 : 0 : SPDK_ERRLOG("Failed to allocate trid entry pointer\n");
5356 : 0 : rc = -ENOMEM;
5357 : 0 : goto err;
5358 : : }
5359 : :
5360 : 1058 : path_id->trid = *trid;
5361 [ + + ]: 1058 : if (ctx != NULL) {
5362 [ - + - + ]: 978 : memcpy(path_id->hostid.hostaddr, ctx->drv_opts.src_addr, sizeof(path_id->hostid.hostaddr));
5363 [ - + - + ]: 978 : memcpy(path_id->hostid.hostsvcid, ctx->drv_opts.src_svcid, sizeof(path_id->hostid.hostsvcid));
5364 : : }
5365 : 1058 : nvme_ctrlr->active_path_id = path_id;
5366 [ - + ]: 1058 : TAILQ_INSERT_HEAD(&nvme_ctrlr->trids, path_id, link);
5367 : :
5368 : 1058 : nvme_ctrlr->thread = spdk_get_thread();
5369 : 1058 : nvme_ctrlr->ctrlr = ctrlr;
5370 : 1058 : nvme_ctrlr->ref = 1;
5371 : :
5372 [ - + ]: 1058 : if (spdk_nvme_ctrlr_is_ocssd_supported(ctrlr)) {
5373 : 0 : SPDK_ERRLOG("OCSSDs are not supported");
5374 : 0 : rc = -ENOTSUP;
5375 : 0 : goto err;
5376 : : }
5377 : :
5378 [ + + ]: 1058 : if (ctx != NULL) {
5379 [ - + - + ]: 978 : memcpy(&nvme_ctrlr->opts, &ctx->bdev_opts, sizeof(ctx->bdev_opts));
5380 : : } else {
5381 : 80 : bdev_nvme_get_default_ctrlr_opts(&nvme_ctrlr->opts);
5382 : : }
5383 : :
5384 : 1058 : nvme_ctrlr->adminq_timer_poller = SPDK_POLLER_REGISTER(bdev_nvme_poll_adminq, nvme_ctrlr,
5385 : : g_opts.nvme_adminq_poll_period_us);
5386 : :
5387 [ - + ]: 1058 : if (g_opts.timeout_us > 0) {
5388 : : /* Register timeout callback. Timeout values for IO vs. admin reqs can be different. */
5389 : : /* If timeout_admin_us is 0 (not specified), admin uses same timeout as IO. */
5390 : 0 : uint64_t adm_timeout_us = (g_opts.timeout_admin_us == 0) ?
5391 [ # # ]: 0 : g_opts.timeout_us : g_opts.timeout_admin_us;
5392 : 0 : spdk_nvme_ctrlr_register_timeout_callback(ctrlr, g_opts.timeout_us,
5393 : : adm_timeout_us, timeout_cb, nvme_ctrlr);
5394 : : }
5395 : :
5396 : 1058 : spdk_nvme_ctrlr_register_aer_callback(ctrlr, aer_cb, nvme_ctrlr);
5397 : 1058 : spdk_nvme_ctrlr_set_remove_cb(ctrlr, remove_cb, nvme_ctrlr);
5398 : :
5399 [ + + ]: 1058 : if (spdk_nvme_ctrlr_get_flags(ctrlr) &
5400 : : SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) {
5401 : 36 : nvme_ctrlr->opal_dev = spdk_opal_dev_construct(ctrlr);
5402 : : }
5403 : :
5404 : 1058 : rc = nvme_bdev_ctrlr_create(name, nvme_ctrlr);
5405 [ + + ]: 1058 : if (rc != 0) {
5406 : 4 : goto err;
5407 : : }
5408 : :
5409 : 1054 : cdata = spdk_nvme_ctrlr_get_data(ctrlr);
5410 : :
5411 [ + + ]: 1054 : if (cdata->cmic.ana_reporting) {
5412 : 124 : rc = nvme_ctrlr_init_ana_log_page(nvme_ctrlr, ctx);
5413 [ + - ]: 124 : if (rc == 0) {
5414 : 124 : return 0;
5415 : : }
5416 : : } else {
5417 : 930 : nvme_ctrlr_create_done(nvme_ctrlr, ctx);
5418 : 930 : return 0;
5419 : : }
5420 : :
5421 : 4 : err:
5422 : 4 : nvme_ctrlr_delete(nvme_ctrlr);
5423 : 4 : return rc;
5424 : : }
5425 : :
5426 : : void
5427 : 1050 : bdev_nvme_get_default_ctrlr_opts(struct nvme_ctrlr_opts *opts)
5428 : : {
5429 : 1050 : opts->prchk_flags = 0;
5430 : 1050 : opts->ctrlr_loss_timeout_sec = g_opts.ctrlr_loss_timeout_sec;
5431 : 1050 : opts->reconnect_delay_sec = g_opts.reconnect_delay_sec;
5432 : 1050 : opts->fast_io_fail_timeout_sec = g_opts.fast_io_fail_timeout_sec;
5433 : 1050 : }
5434 : :
5435 : : static void
5436 : 24 : attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
5437 : : struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *drv_opts)
5438 : : {
5439 : : char *name;
5440 : :
5441 : 24 : name = spdk_sprintf_alloc("HotInNvme%d", g_hot_insert_nvme_controller_index++);
5442 [ - + ]: 24 : if (!name) {
5443 : 0 : SPDK_ERRLOG("Failed to assign name to NVMe device\n");
5444 : 0 : return;
5445 : : }
5446 : :
5447 [ + - ]: 24 : if (nvme_ctrlr_create(ctrlr, name, trid, NULL) == 0) {
5448 [ - + - + ]: 24 : SPDK_DEBUGLOG(bdev_nvme, "Attached to %s (%s)\n", trid->traddr, name);
5449 : : } else {
5450 : 0 : SPDK_ERRLOG("Failed to attach to %s (%s)\n", trid->traddr, name);
5451 : : }
5452 : :
5453 : 24 : free(name);
5454 : : }
5455 : :
5456 : : static void
5457 : 1054 : _nvme_ctrlr_destruct(void *ctx)
5458 : : {
5459 : 1054 : struct nvme_ctrlr *nvme_ctrlr = ctx;
5460 : :
5461 : 1054 : nvme_ctrlr_depopulate_namespaces(nvme_ctrlr);
5462 : 1054 : nvme_ctrlr_release(nvme_ctrlr);
5463 : 1054 : }
5464 : :
5465 : : static int
5466 : 365 : bdev_nvme_delete_ctrlr_unsafe(struct nvme_ctrlr *nvme_ctrlr, bool hotplug)
5467 : : {
5468 : : struct nvme_probe_skip_entry *entry;
5469 : :
5470 : : /* The controller's destruction was already started */
5471 [ - + ]: 365 : if (nvme_ctrlr->destruct) {
5472 : 0 : return -EALREADY;
5473 : : }
5474 : :
5475 [ + + ]: 365 : if (!hotplug &&
5476 [ + + ]: 341 : nvme_ctrlr->active_path_id->trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
5477 : 59 : entry = calloc(1, sizeof(*entry));
5478 [ - + ]: 59 : if (!entry) {
5479 : 0 : return -ENOMEM;
5480 : : }
5481 : 59 : entry->trid = nvme_ctrlr->active_path_id->trid;
5482 : 59 : TAILQ_INSERT_TAIL(&g_skipped_nvme_ctrlrs, entry, tailq);
5483 : : }
5484 : :
5485 : 365 : nvme_ctrlr->destruct = true;
5486 : 365 : return 0;
5487 : : }
5488 : :
5489 : : static int
5490 : 39 : bdev_nvme_delete_ctrlr(struct nvme_ctrlr *nvme_ctrlr, bool hotplug)
5491 : : {
5492 : : int rc;
5493 : :
5494 [ - + ]: 39 : pthread_mutex_lock(&nvme_ctrlr->mutex);
5495 : 39 : rc = bdev_nvme_delete_ctrlr_unsafe(nvme_ctrlr, hotplug);
5496 [ - + ]: 39 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
5497 : :
5498 [ + - ]: 39 : if (rc == 0) {
5499 : 39 : _nvme_ctrlr_destruct(nvme_ctrlr);
5500 [ # # ]: 0 : } else if (rc == -EALREADY) {
5501 : 0 : rc = 0;
5502 : : }
5503 : :
5504 : 39 : return rc;
5505 : : }
5506 : :
5507 : : static void
5508 : 24 : remove_cb(void *cb_ctx, struct spdk_nvme_ctrlr *ctrlr)
5509 : : {
5510 : 24 : struct nvme_ctrlr *nvme_ctrlr = cb_ctx;
5511 : :
5512 : 24 : bdev_nvme_delete_ctrlr(nvme_ctrlr, true);
5513 : 24 : }
5514 : :
5515 : : static int
5516 : 15884 : bdev_nvme_hotplug_probe(void *arg)
5517 : : {
5518 [ - + ]: 15884 : if (g_hotplug_probe_ctx == NULL) {
5519 : 0 : spdk_poller_unregister(&g_hotplug_probe_poller);
5520 : 0 : return SPDK_POLLER_IDLE;
5521 : : }
5522 : :
5523 [ + + ]: 15884 : if (spdk_nvme_probe_poll_async(g_hotplug_probe_ctx) != -EAGAIN) {
5524 : 2868 : g_hotplug_probe_ctx = NULL;
5525 : 2868 : spdk_poller_unregister(&g_hotplug_probe_poller);
5526 : : }
5527 : :
5528 : 15884 : return SPDK_POLLER_BUSY;
5529 : : }
5530 : :
5531 : : static int
5532 : 2995 : bdev_nvme_hotplug(void *arg)
5533 : : {
5534 : 0 : struct spdk_nvme_transport_id trid_pcie;
5535 : :
5536 [ + + ]: 2995 : if (g_hotplug_probe_ctx) {
5537 : 127 : return SPDK_POLLER_BUSY;
5538 : : }
5539 : :
5540 [ - + ]: 2868 : memset(&trid_pcie, 0, sizeof(trid_pcie));
5541 : 2868 : spdk_nvme_trid_populate_transport(&trid_pcie, SPDK_NVME_TRANSPORT_PCIE);
5542 : :
5543 : 2868 : g_hotplug_probe_ctx = spdk_nvme_probe_async(&trid_pcie, NULL,
5544 : : hotplug_probe_cb, attach_cb, NULL);
5545 : :
5546 [ + - ]: 2868 : if (g_hotplug_probe_ctx) {
5547 [ - + ]: 2868 : assert(g_hotplug_probe_poller == NULL);
5548 : 2868 : g_hotplug_probe_poller = SPDK_POLLER_REGISTER(bdev_nvme_hotplug_probe, NULL, 1000);
5549 : : }
5550 : :
5551 : 2868 : return SPDK_POLLER_BUSY;
5552 : : }
5553 : :
5554 : : void
5555 : 342 : bdev_nvme_get_opts(struct spdk_bdev_nvme_opts *opts)
5556 : : {
5557 : 342 : *opts = g_opts;
5558 : 342 : }
5559 : :
5560 : : static bool bdev_nvme_check_io_error_resiliency_params(int32_t ctrlr_loss_timeout_sec,
5561 : : uint32_t reconnect_delay_sec,
5562 : : uint32_t fast_io_fail_timeout_sec);
5563 : :
5564 : : static int
5565 : 342 : bdev_nvme_validate_opts(const struct spdk_bdev_nvme_opts *opts)
5566 : : {
5567 [ + + - + ]: 342 : if ((opts->timeout_us == 0) && (opts->timeout_admin_us != 0)) {
5568 : : /* Can't set timeout_admin_us without also setting timeout_us */
5569 : 0 : SPDK_WARNLOG("Invalid options: Can't have (timeout_us == 0) with (timeout_admin_us > 0)\n");
5570 : 0 : return -EINVAL;
5571 : : }
5572 : :
5573 [ - + ]: 342 : if (opts->bdev_retry_count < -1) {
5574 : 0 : SPDK_WARNLOG("Invalid option: bdev_retry_count can't be less than -1.\n");
5575 : 0 : return -EINVAL;
5576 : : }
5577 : :
5578 [ - + ]: 342 : if (!bdev_nvme_check_io_error_resiliency_params(opts->ctrlr_loss_timeout_sec,
5579 : 302 : opts->reconnect_delay_sec,
5580 : 302 : opts->fast_io_fail_timeout_sec)) {
5581 : 0 : return -EINVAL;
5582 : : }
5583 : :
5584 : 342 : return 0;
5585 : : }
5586 : :
5587 : : int
5588 : 342 : bdev_nvme_set_opts(const struct spdk_bdev_nvme_opts *opts)
5589 : : {
5590 : : int ret;
5591 : :
5592 : 342 : ret = bdev_nvme_validate_opts(opts);
5593 [ - + ]: 342 : if (ret) {
5594 : 0 : SPDK_WARNLOG("Failed to set nvme opts.\n");
5595 : 0 : return ret;
5596 : : }
5597 : :
5598 [ + + ]: 342 : if (g_bdev_nvme_init_thread != NULL) {
5599 [ - + ]: 36 : if (!TAILQ_EMPTY(&g_nvme_bdev_ctrlrs)) {
5600 : 0 : return -EPERM;
5601 : : }
5602 : : }
5603 : :
5604 [ + - ]: 342 : if (opts->rdma_srq_size != 0 ||
5605 [ - + ]: 342 : opts->rdma_max_cq_size != 0) {
5606 : 0 : struct spdk_nvme_transport_opts drv_opts;
5607 : :
5608 : 0 : spdk_nvme_transport_get_opts(&drv_opts, sizeof(drv_opts));
5609 [ # # ]: 0 : if (opts->rdma_srq_size != 0) {
5610 : 0 : drv_opts.rdma_srq_size = opts->rdma_srq_size;
5611 : : }
5612 [ # # ]: 0 : if (opts->rdma_max_cq_size != 0) {
5613 : 0 : drv_opts.rdma_max_cq_size = opts->rdma_max_cq_size;
5614 : : }
5615 : :
5616 : 0 : ret = spdk_nvme_transport_set_opts(&drv_opts, sizeof(drv_opts));
5617 [ # # ]: 0 : if (ret) {
5618 : 0 : SPDK_ERRLOG("Failed to set NVMe transport opts.\n");
5619 : 0 : return ret;
5620 : : }
5621 : : }
5622 : :
5623 : 342 : g_opts = *opts;
5624 : :
5625 : 342 : return 0;
5626 : : }
5627 : :
5628 : : struct set_nvme_hotplug_ctx {
5629 : : uint64_t period_us;
5630 : : bool enabled;
5631 : : spdk_msg_fn fn;
5632 : : void *fn_ctx;
5633 : : };
5634 : :
5635 : : static void
5636 : 243 : set_nvme_hotplug_period_cb(void *_ctx)
5637 : : {
5638 : 243 : struct set_nvme_hotplug_ctx *ctx = _ctx;
5639 : :
5640 : 243 : spdk_poller_unregister(&g_hotplug_poller);
5641 [ + + + + ]: 243 : if (ctx->enabled) {
5642 : 6 : g_hotplug_poller = SPDK_POLLER_REGISTER(bdev_nvme_hotplug, NULL, ctx->period_us);
5643 : : }
5644 : :
5645 : 243 : g_nvme_hotplug_poll_period_us = ctx->period_us;
5646 [ - + ]: 243 : g_nvme_hotplug_enabled = ctx->enabled;
5647 [ + - ]: 243 : if (ctx->fn) {
5648 : 243 : ctx->fn(ctx->fn_ctx);
5649 : : }
5650 : :
5651 : 243 : free(ctx);
5652 : 243 : }
5653 : :
5654 : : int
5655 : 243 : bdev_nvme_set_hotplug(bool enabled, uint64_t period_us, spdk_msg_fn cb, void *cb_ctx)
5656 : : {
5657 : : struct set_nvme_hotplug_ctx *ctx;
5658 : :
5659 [ + + - + ]: 243 : if (enabled == true && !spdk_process_is_primary()) {
5660 : 0 : return -EPERM;
5661 : : }
5662 : :
5663 : 243 : ctx = calloc(1, sizeof(*ctx));
5664 [ - + ]: 243 : if (ctx == NULL) {
5665 : 0 : return -ENOMEM;
5666 : : }
5667 : :
5668 [ + + ]: 243 : period_us = period_us == 0 ? NVME_HOTPLUG_POLL_PERIOD_DEFAULT : period_us;
5669 : 243 : ctx->period_us = spdk_min(period_us, NVME_HOTPLUG_POLL_PERIOD_MAX);
5670 : 243 : ctx->enabled = enabled;
5671 : 243 : ctx->fn = cb;
5672 : 243 : ctx->fn_ctx = cb_ctx;
5673 : :
5674 : 243 : spdk_thread_send_msg(g_bdev_nvme_init_thread, set_nvme_hotplug_period_cb, ctx);
5675 : 243 : return 0;
5676 : : }
5677 : :
5678 : : static void
5679 : 974 : nvme_ctrlr_populate_namespaces_done(struct nvme_ctrlr *nvme_ctrlr,
5680 : : struct nvme_async_probe_ctx *ctx)
5681 : : {
5682 : : struct nvme_ns *nvme_ns;
5683 : : struct nvme_bdev *nvme_bdev;
5684 : : size_t j;
5685 : :
5686 [ - + ]: 974 : assert(nvme_ctrlr != NULL);
5687 : :
5688 [ + + ]: 974 : if (ctx->names == NULL) {
5689 : 37 : ctx->reported_bdevs = 0;
5690 : 37 : populate_namespaces_cb(ctx, 0);
5691 : 37 : return;
5692 : : }
5693 : :
5694 : : /*
5695 : : * Report the new bdevs that were created in this call.
5696 : : * There can be more than one bdev per NVMe controller.
5697 : : */
5698 : 937 : j = 0;
5699 : 937 : nvme_ns = nvme_ctrlr_get_first_active_ns(nvme_ctrlr);
5700 [ + + ]: 1975 : while (nvme_ns != NULL) {
5701 : 1038 : nvme_bdev = nvme_ns->bdev;
5702 [ + - ]: 1038 : if (j < ctx->max_bdevs) {
5703 : 1038 : ctx->names[j] = nvme_bdev->disk.name;
5704 : 1038 : j++;
5705 : : } else {
5706 : 0 : SPDK_ERRLOG("Maximum number of namespaces supported per NVMe controller is %du. Unable to return all names of created bdevs\n",
5707 : : ctx->max_bdevs);
5708 : 0 : ctx->reported_bdevs = 0;
5709 : 0 : populate_namespaces_cb(ctx, -ERANGE);
5710 : 0 : return;
5711 : : }
5712 : :
5713 : 1038 : nvme_ns = nvme_ctrlr_get_next_active_ns(nvme_ctrlr, nvme_ns);
5714 : : }
5715 : :
5716 : 937 : ctx->reported_bdevs = j;
5717 : 937 : populate_namespaces_cb(ctx, 0);
5718 : : }
5719 : :
5720 : : static int
5721 : 58 : bdev_nvme_check_secondary_trid(struct nvme_ctrlr *nvme_ctrlr,
5722 : : struct spdk_nvme_ctrlr *new_ctrlr,
5723 : : struct spdk_nvme_transport_id *trid)
5724 : : {
5725 : : struct nvme_path_id *tmp_trid;
5726 : :
5727 [ - + ]: 58 : if (trid->trtype == SPDK_NVME_TRANSPORT_PCIE) {
5728 : 0 : SPDK_ERRLOG("PCIe failover is not supported.\n");
5729 : 0 : return -ENOTSUP;
5730 : : }
5731 : :
5732 : : /* Currently we only support failover to the same transport type. */
5733 [ - + ]: 58 : if (nvme_ctrlr->active_path_id->trid.trtype != trid->trtype) {
5734 : 0 : SPDK_WARNLOG("Failover from trtype: %s to a different trtype: %s is not supported currently\n",
5735 : : spdk_nvme_transport_id_trtype_str(nvme_ctrlr->active_path_id->trid.trtype),
5736 : : spdk_nvme_transport_id_trtype_str(trid->trtype));
5737 : 0 : return -EINVAL;
5738 : : }
5739 : :
5740 : :
5741 : : /* Currently we only support failover to the same NQN. */
5742 [ - + - + : 58 : if (strncmp(trid->subnqn, nvme_ctrlr->active_path_id->trid.subnqn, SPDK_NVMF_NQN_MAX_LEN)) {
- + ]
5743 : 0 : SPDK_WARNLOG("Failover from subnqn: %s to a different subnqn: %s is not supported currently\n",
5744 : : nvme_ctrlr->active_path_id->trid.subnqn, trid->subnqn);
5745 : 0 : return -EINVAL;
5746 : : }
5747 : :
5748 : : /* Skip all the other checks if we've already registered this path. */
5749 [ + + ]: 138 : TAILQ_FOREACH(tmp_trid, &nvme_ctrlr->trids, link) {
5750 [ - + ]: 80 : if (!spdk_nvme_transport_id_compare(&tmp_trid->trid, trid)) {
5751 : 0 : SPDK_WARNLOG("This path (traddr: %s subnqn: %s) is already registered\n", trid->traddr,
5752 : : trid->subnqn);
5753 : 0 : return -EEXIST;
5754 : : }
5755 : : }
5756 : :
5757 : 58 : return 0;
5758 : : }
5759 : :
5760 : : static int
5761 : 58 : bdev_nvme_check_secondary_namespace(struct nvme_ctrlr *nvme_ctrlr,
5762 : : struct spdk_nvme_ctrlr *new_ctrlr)
5763 : : {
5764 : : struct nvme_ns *nvme_ns;
5765 : : struct spdk_nvme_ns *new_ns;
5766 : :
5767 : 58 : nvme_ns = nvme_ctrlr_get_first_active_ns(nvme_ctrlr);
5768 [ + + ]: 80 : while (nvme_ns != NULL) {
5769 : 22 : new_ns = spdk_nvme_ctrlr_get_ns(new_ctrlr, nvme_ns->id);
5770 [ - + ]: 22 : assert(new_ns != NULL);
5771 : :
5772 [ - + ]: 22 : if (!bdev_nvme_compare_ns(nvme_ns->ns, new_ns)) {
5773 : 0 : return -EINVAL;
5774 : : }
5775 : :
5776 : 22 : nvme_ns = nvme_ctrlr_get_next_active_ns(nvme_ctrlr, nvme_ns);
5777 : : }
5778 : :
5779 : 58 : return 0;
5780 : : }
5781 : :
5782 : : static int
5783 : 58 : _bdev_nvme_add_secondary_trid(struct nvme_ctrlr *nvme_ctrlr,
5784 : : struct spdk_nvme_transport_id *trid)
5785 : : {
5786 : : struct nvme_path_id *active_id, *new_trid, *tmp_trid;
5787 : :
5788 : 58 : new_trid = calloc(1, sizeof(*new_trid));
5789 [ - + ]: 58 : if (new_trid == NULL) {
5790 : 0 : return -ENOMEM;
5791 : : }
5792 : 58 : new_trid->trid = *trid;
5793 : :
5794 : 58 : active_id = nvme_ctrlr->active_path_id;
5795 [ - + ]: 58 : assert(active_id != NULL);
5796 [ - + ]: 58 : assert(active_id == TAILQ_FIRST(&nvme_ctrlr->trids));
5797 : :
5798 : : /* Skip the active trid not to replace it until it is failed. */
5799 : 58 : tmp_trid = TAILQ_NEXT(active_id, link);
5800 [ + + ]: 58 : if (tmp_trid == NULL) {
5801 : 36 : goto add_tail;
5802 : : }
5803 : :
5804 : : /* It means the trid is faled if its last failed time is non-zero.
5805 : : * Insert the new alternate trid before any failed trid.
5806 : : */
5807 [ - + + + ]: 35 : TAILQ_FOREACH_FROM(tmp_trid, &nvme_ctrlr->trids, link) {
5808 [ + + ]: 22 : if (tmp_trid->last_failed_tsc != 0) {
5809 : 9 : TAILQ_INSERT_BEFORE(tmp_trid, new_trid, link);
5810 : 9 : return 0;
5811 : : }
5812 : : }
5813 : :
5814 : 13 : add_tail:
5815 : 49 : TAILQ_INSERT_TAIL(&nvme_ctrlr->trids, new_trid, link);
5816 : 49 : return 0;
5817 : : }
5818 : :
5819 : : /* This is the case that a secondary path is added to an existing
5820 : : * nvme_ctrlr for failover. After checking if it can access the same
5821 : : * namespaces as the primary path, it is disconnected until failover occurs.
5822 : : */
5823 : : static int
5824 : 58 : bdev_nvme_add_secondary_trid(struct nvme_ctrlr *nvme_ctrlr,
5825 : : struct spdk_nvme_ctrlr *new_ctrlr,
5826 : : struct spdk_nvme_transport_id *trid)
5827 : : {
5828 : : int rc;
5829 : :
5830 [ - + ]: 58 : assert(nvme_ctrlr != NULL);
5831 : :
5832 [ - + ]: 58 : pthread_mutex_lock(&nvme_ctrlr->mutex);
5833 : :
5834 : 58 : rc = bdev_nvme_check_secondary_trid(nvme_ctrlr, new_ctrlr, trid);
5835 [ - + ]: 58 : if (rc != 0) {
5836 : 0 : goto exit;
5837 : : }
5838 : :
5839 : 58 : rc = bdev_nvme_check_secondary_namespace(nvme_ctrlr, new_ctrlr);
5840 [ - + ]: 58 : if (rc != 0) {
5841 : 0 : goto exit;
5842 : : }
5843 : :
5844 : 58 : rc = _bdev_nvme_add_secondary_trid(nvme_ctrlr, trid);
5845 : :
5846 : 58 : exit:
5847 [ - + ]: 58 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
5848 : :
5849 : 58 : spdk_nvme_detach(new_ctrlr);
5850 : :
5851 : 58 : return rc;
5852 : : }
5853 : :
5854 : : static void
5855 : 978 : connect_attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
5856 : : struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
5857 : : {
5858 : 978 : struct spdk_nvme_ctrlr_opts *user_opts = cb_ctx;
5859 : : struct nvme_async_probe_ctx *ctx;
5860 : : int rc;
5861 : :
5862 : 978 : ctx = SPDK_CONTAINEROF(user_opts, struct nvme_async_probe_ctx, drv_opts);
5863 : 978 : ctx->ctrlr_attached = true;
5864 : :
5865 : 978 : rc = nvme_ctrlr_create(ctrlr, ctx->base_name, &ctx->trid, ctx);
5866 [ + + ]: 978 : if (rc != 0) {
5867 : 4 : ctx->reported_bdevs = 0;
5868 : 4 : populate_namespaces_cb(ctx, rc);
5869 : : }
5870 : 978 : }
5871 : :
5872 : : static void
5873 : 38 : connect_set_failover_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
5874 : : struct spdk_nvme_ctrlr *ctrlr,
5875 : : const struct spdk_nvme_ctrlr_opts *opts)
5876 : : {
5877 : 38 : struct spdk_nvme_ctrlr_opts *user_opts = cb_ctx;
5878 : : struct nvme_ctrlr *nvme_ctrlr;
5879 : : struct nvme_async_probe_ctx *ctx;
5880 : : int rc;
5881 : :
5882 : 38 : ctx = SPDK_CONTAINEROF(user_opts, struct nvme_async_probe_ctx, drv_opts);
5883 : 38 : ctx->ctrlr_attached = true;
5884 : :
5885 : 38 : nvme_ctrlr = nvme_ctrlr_get_by_name(ctx->base_name);
5886 [ + - ]: 38 : if (nvme_ctrlr) {
5887 : 38 : rc = bdev_nvme_add_secondary_trid(nvme_ctrlr, ctrlr, &ctx->trid);
5888 : : } else {
5889 : 0 : rc = -ENODEV;
5890 : : }
5891 : :
5892 : 38 : ctx->reported_bdevs = 0;
5893 : 38 : populate_namespaces_cb(ctx, rc);
5894 : 38 : }
5895 : :
5896 : : static int
5897 : 170949 : bdev_nvme_async_poll(void *arg)
5898 : : {
5899 : 170949 : struct nvme_async_probe_ctx *ctx = arg;
5900 : : int rc;
5901 : :
5902 : 170949 : rc = spdk_nvme_probe_poll_async(ctx->probe_ctx);
5903 [ + + ]: 170949 : if (spdk_unlikely(rc != -EAGAIN)) {
5904 : 1032 : ctx->probe_done = true;
5905 : 1032 : spdk_poller_unregister(&ctx->poller);
5906 [ + + + + ]: 1032 : if (!ctx->ctrlr_attached) {
5907 : : /* The probe is done, but no controller was attached.
5908 : : * That means we had a failure, so report -EIO back to
5909 : : * the caller (usually the RPC). populate_namespaces_cb()
5910 : : * will take care of freeing the nvme_async_probe_ctx.
5911 : : */
5912 : 16 : ctx->reported_bdevs = 0;
5913 : 16 : populate_namespaces_cb(ctx, -EIO);
5914 [ + + + + ]: 1016 : } else if (ctx->namespaces_populated) {
5915 : : /* The namespaces for the attached controller were all
5916 : : * populated and the response was already sent to the
5917 : : * caller (usually the RPC). So free the context here.
5918 : : */
5919 : 887 : free(ctx);
5920 : : }
5921 : : }
5922 : :
5923 : 170949 : return SPDK_POLLER_BUSY;
5924 : : }
5925 : :
5926 : : static bool
5927 : 1282 : bdev_nvme_check_io_error_resiliency_params(int32_t ctrlr_loss_timeout_sec,
5928 : : uint32_t reconnect_delay_sec,
5929 : : uint32_t fast_io_fail_timeout_sec)
5930 : : {
5931 [ + + ]: 1282 : if (ctrlr_loss_timeout_sec < -1) {
5932 : 4 : SPDK_ERRLOG("ctrlr_loss_timeout_sec can't be less than -1.\n");
5933 : 4 : return false;
5934 [ + + ]: 1278 : } else if (ctrlr_loss_timeout_sec == -1) {
5935 [ + + ]: 56 : if (reconnect_delay_sec == 0) {
5936 : 4 : SPDK_ERRLOG("reconnect_delay_sec can't be 0 if ctrlr_loss_timeout_sec is not 0.\n");
5937 : 4 : return false;
5938 [ + + + + ]: 52 : } else if (fast_io_fail_timeout_sec != 0 &&
5939 : : fast_io_fail_timeout_sec < reconnect_delay_sec) {
5940 : 4 : SPDK_ERRLOG("reconnect_delay_sec can't be more than fast_io-fail_timeout_sec.\n");
5941 : 4 : return false;
5942 : : }
5943 [ + + ]: 1222 : } else if (ctrlr_loss_timeout_sec != 0) {
5944 [ + + ]: 56 : if (reconnect_delay_sec == 0) {
5945 : 4 : SPDK_ERRLOG("reconnect_delay_sec can't be 0 if ctrlr_loss_timeout_sec is not 0.\n");
5946 : 4 : return false;
5947 [ + + ]: 52 : } else if (reconnect_delay_sec > (uint32_t)ctrlr_loss_timeout_sec) {
5948 : 4 : SPDK_ERRLOG("reconnect_delay_sec can't be more than ctrlr_loss_timeout_sec.\n");
5949 : 4 : return false;
5950 [ + + ]: 48 : } else if (fast_io_fail_timeout_sec != 0) {
5951 [ + + ]: 32 : if (fast_io_fail_timeout_sec < reconnect_delay_sec) {
5952 : 4 : SPDK_ERRLOG("reconnect_delay_sec can't be more than fast_io_fail_timeout_sec.\n");
5953 : 4 : return false;
5954 [ + + ]: 28 : } else if (fast_io_fail_timeout_sec > (uint32_t)ctrlr_loss_timeout_sec) {
5955 : 4 : SPDK_ERRLOG("fast_io_fail_timeout_sec can't be more than ctrlr_loss_timeout_sec.\n");
5956 : 4 : return false;
5957 : : }
5958 : : }
5959 [ + + + + ]: 1166 : } else if (reconnect_delay_sec != 0 || fast_io_fail_timeout_sec != 0) {
5960 : 8 : SPDK_ERRLOG("Both reconnect_delay_sec and fast_io_fail_timeout_sec must be 0 if ctrlr_loss_timeout_sec is 0.\n");
5961 : 8 : return false;
5962 : : }
5963 : :
5964 : 1246 : return true;
5965 : : }
5966 : :
5967 : : int
5968 : 1032 : bdev_nvme_create(struct spdk_nvme_transport_id *trid,
5969 : : const char *base_name,
5970 : : const char **names,
5971 : : uint32_t count,
5972 : : spdk_bdev_create_nvme_fn cb_fn,
5973 : : void *cb_ctx,
5974 : : struct spdk_nvme_ctrlr_opts *drv_opts,
5975 : : struct nvme_ctrlr_opts *bdev_opts,
5976 : : bool multipath)
5977 : : {
5978 : : struct nvme_probe_skip_entry *entry, *tmp;
5979 : : struct nvme_async_probe_ctx *ctx;
5980 : : spdk_nvme_attach_cb attach_cb;
5981 : :
5982 : : /* TODO expand this check to include both the host and target TRIDs.
5983 : : * Only if both are the same should we fail.
5984 : : */
5985 [ - + ]: 1032 : if (nvme_ctrlr_get(trid) != NULL) {
5986 : 0 : SPDK_ERRLOG("A controller with the provided trid (traddr: %s) already exists.\n", trid->traddr);
5987 : 0 : return -EEXIST;
5988 : : }
5989 : :
5990 [ + + ]: 1032 : if (bdev_opts != NULL &&
5991 [ - + ]: 864 : !bdev_nvme_check_io_error_resiliency_params(bdev_opts->ctrlr_loss_timeout_sec,
5992 : : bdev_opts->reconnect_delay_sec,
5993 : : bdev_opts->fast_io_fail_timeout_sec)) {
5994 : 0 : return -EINVAL;
5995 : : }
5996 : :
5997 : 1032 : ctx = calloc(1, sizeof(*ctx));
5998 [ - + ]: 1032 : if (!ctx) {
5999 : 0 : return -ENOMEM;
6000 : : }
6001 : 1032 : ctx->base_name = base_name;
6002 : 1032 : ctx->names = names;
6003 : 1032 : ctx->max_bdevs = count;
6004 : 1032 : ctx->cb_fn = cb_fn;
6005 : 1032 : ctx->cb_ctx = cb_ctx;
6006 : 1032 : ctx->trid = *trid;
6007 : :
6008 [ + + ]: 1032 : if (bdev_opts) {
6009 [ - + - + ]: 864 : memcpy(&ctx->bdev_opts, bdev_opts, sizeof(*bdev_opts));
6010 : : } else {
6011 : 168 : bdev_nvme_get_default_ctrlr_opts(&ctx->bdev_opts);
6012 : : }
6013 : :
6014 [ + + ]: 1032 : if (trid->trtype == SPDK_NVME_TRANSPORT_PCIE) {
6015 [ + + ]: 519 : TAILQ_FOREACH_SAFE(entry, &g_skipped_nvme_ctrlrs, tailq, tmp) {
6016 [ + - ]: 2 : if (spdk_nvme_transport_id_compare(trid, &entry->trid) == 0) {
6017 [ - + ]: 2 : TAILQ_REMOVE(&g_skipped_nvme_ctrlrs, entry, tailq);
6018 : 2 : free(entry);
6019 : 2 : break;
6020 : : }
6021 : : }
6022 : : }
6023 : :
6024 [ + + ]: 1032 : if (drv_opts) {
6025 [ - + - + ]: 828 : memcpy(&ctx->drv_opts, drv_opts, sizeof(*drv_opts));
6026 : : } else {
6027 : 204 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&ctx->drv_opts, sizeof(ctx->drv_opts));
6028 : : }
6029 : :
6030 : 1032 : ctx->drv_opts.transport_retry_count = g_opts.transport_retry_count;
6031 : 1032 : ctx->drv_opts.transport_ack_timeout = g_opts.transport_ack_timeout;
6032 : 1032 : ctx->drv_opts.keep_alive_timeout_ms = g_opts.keep_alive_timeout_ms;
6033 : 1032 : ctx->drv_opts.disable_read_ana_log_page = true;
6034 : 1032 : ctx->drv_opts.transport_tos = g_opts.transport_tos;
6035 : :
6036 [ + + + + ]: 1032 : if (nvme_bdev_ctrlr_get_by_name(base_name) == NULL || multipath) {
6037 : 994 : attach_cb = connect_attach_cb;
6038 : : } else {
6039 : 38 : attach_cb = connect_set_failover_cb;
6040 : : }
6041 : :
6042 : 1032 : ctx->probe_ctx = spdk_nvme_connect_async(trid, &ctx->drv_opts, attach_cb);
6043 [ - + ]: 1032 : if (ctx->probe_ctx == NULL) {
6044 : 0 : SPDK_ERRLOG("No controller was found with provided trid (traddr: %s)\n", trid->traddr);
6045 : 0 : free(ctx);
6046 : 0 : return -ENODEV;
6047 : : }
6048 : 1032 : ctx->poller = SPDK_POLLER_REGISTER(bdev_nvme_async_poll, ctx, 1000);
6049 : :
6050 : 1032 : return 0;
6051 : : }
6052 : :
6053 : : struct bdev_nvme_delete_ctx {
6054 : : char *name;
6055 : : struct nvme_path_id path_id;
6056 : : bdev_nvme_delete_done_fn delete_done;
6057 : : void *delete_done_ctx;
6058 : : uint64_t timeout_ticks;
6059 : : struct spdk_poller *poller;
6060 : : };
6061 : :
6062 : : static void
6063 : 96 : free_bdev_nvme_delete_ctx(struct bdev_nvme_delete_ctx *ctx)
6064 : : {
6065 [ + + ]: 96 : if (ctx != NULL) {
6066 : 92 : free(ctx->name);
6067 : 92 : free(ctx);
6068 : : }
6069 : 96 : }
6070 : :
6071 : : static bool
6072 : 30494 : nvme_path_id_compare(struct nvme_path_id *p, const struct nvme_path_id *path_id)
6073 : : {
6074 [ + + ]: 30494 : if (path_id->trid.trtype != 0) {
6075 [ - + ]: 208 : if (path_id->trid.trtype == SPDK_NVME_TRANSPORT_CUSTOM) {
6076 [ # # # # : 0 : if (strcasecmp(path_id->trid.trstring, p->trid.trstring) != 0) {
# # ]
6077 : 0 : return false;
6078 : : }
6079 : : } else {
6080 [ - + ]: 208 : if (path_id->trid.trtype != p->trid.trtype) {
6081 : 0 : return false;
6082 : : }
6083 : : }
6084 : : }
6085 : :
6086 [ + + ]: 30494 : if (!spdk_mem_all_zero(path_id->trid.traddr, sizeof(path_id->trid.traddr))) {
6087 [ + + - + : 208 : if (strcasecmp(path_id->trid.traddr, p->trid.traddr) != 0) {
+ + ]
6088 : 44 : return false;
6089 : : }
6090 : : }
6091 : :
6092 [ + + ]: 30450 : if (path_id->trid.adrfam != 0) {
6093 [ - + ]: 124 : if (path_id->trid.adrfam != p->trid.adrfam) {
6094 : 0 : return false;
6095 : : }
6096 : : }
6097 : :
6098 [ + + ]: 30450 : if (!spdk_mem_all_zero(path_id->trid.trsvcid, sizeof(path_id->trid.trsvcid))) {
6099 [ - + - + : 164 : if (strcasecmp(path_id->trid.trsvcid, p->trid.trsvcid) != 0) {
+ + ]
6100 : 39 : return false;
6101 : : }
6102 : : }
6103 : :
6104 [ + + ]: 30411 : if (!spdk_mem_all_zero(path_id->trid.subnqn, sizeof(path_id->trid.subnqn))) {
6105 [ - + - + : 125 : if (strcmp(path_id->trid.subnqn, p->trid.subnqn) != 0) {
- + ]
6106 : 0 : return false;
6107 : : }
6108 : : }
6109 : :
6110 [ - + ]: 30411 : if (!spdk_mem_all_zero(path_id->hostid.hostaddr, sizeof(path_id->hostid.hostaddr))) {
6111 [ # # # # : 0 : if (strcmp(path_id->hostid.hostaddr, p->hostid.hostaddr) != 0) {
# # ]
6112 : 0 : return false;
6113 : : }
6114 : : }
6115 : :
6116 [ - + ]: 30411 : if (!spdk_mem_all_zero(path_id->hostid.hostsvcid, sizeof(path_id->hostid.hostsvcid))) {
6117 [ # # # # : 0 : if (strcmp(path_id->hostid.hostsvcid, p->hostid.hostsvcid) != 0) {
# # ]
6118 : 0 : return false;
6119 : : }
6120 : : }
6121 : :
6122 : 30411 : return true;
6123 : : }
6124 : :
6125 : : static bool
6126 : 30133 : nvme_path_id_exists(const char *name, const struct nvme_path_id *path_id)
6127 : : {
6128 : : struct nvme_bdev_ctrlr *nbdev_ctrlr;
6129 : : struct nvme_ctrlr *ctrlr;
6130 : : struct nvme_path_id *p;
6131 : :
6132 [ - + ]: 30133 : pthread_mutex_lock(&g_bdev_nvme_mutex);
6133 : 30133 : nbdev_ctrlr = nvme_bdev_ctrlr_get_by_name(name);
6134 [ + + ]: 30133 : if (!nbdev_ctrlr) {
6135 [ - + ]: 80 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
6136 : 80 : return false;
6137 : : }
6138 : :
6139 [ + + ]: 30065 : TAILQ_FOREACH(ctrlr, &nbdev_ctrlr->ctrlrs, tailq) {
6140 [ - + ]: 30053 : pthread_mutex_lock(&ctrlr->mutex);
6141 [ + + ]: 30070 : TAILQ_FOREACH(p, &ctrlr->trids, link) {
6142 [ + + ]: 30058 : if (nvme_path_id_compare(p, path_id)) {
6143 [ - + ]: 30041 : pthread_mutex_unlock(&ctrlr->mutex);
6144 [ - + ]: 30041 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
6145 : 30041 : return true;
6146 : : }
6147 : : }
6148 [ - + ]: 12 : pthread_mutex_unlock(&ctrlr->mutex);
6149 : : }
6150 [ - + ]: 12 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
6151 : :
6152 : 12 : return false;
6153 : : }
6154 : :
6155 : : static int
6156 : 30133 : bdev_nvme_delete_complete_poll(void *arg)
6157 : : {
6158 : 30133 : struct bdev_nvme_delete_ctx *ctx = arg;
6159 : 30133 : int rc = 0;
6160 : :
6161 [ + + ]: 30133 : if (nvme_path_id_exists(ctx->name, &ctx->path_id)) {
6162 [ + - ]: 30041 : if (ctx->timeout_ticks > spdk_get_ticks()) {
6163 : 30041 : return SPDK_POLLER_BUSY;
6164 : : }
6165 : :
6166 : 0 : SPDK_ERRLOG("NVMe path '%s' still exists after delete\n", ctx->name);
6167 : 0 : rc = -ETIMEDOUT;
6168 : : }
6169 : :
6170 : 92 : spdk_poller_unregister(&ctx->poller);
6171 : :
6172 : 92 : ctx->delete_done(ctx->delete_done_ctx, rc);
6173 : 92 : free_bdev_nvme_delete_ctx(ctx);
6174 : :
6175 : 92 : return SPDK_POLLER_BUSY;
6176 : : }
6177 : :
6178 : : static int
6179 : 379 : _bdev_nvme_delete(struct nvme_ctrlr *nvme_ctrlr, const struct nvme_path_id *path_id)
6180 : : {
6181 : : struct nvme_path_id *p, *t;
6182 : : spdk_msg_fn msg_fn;
6183 : 379 : int rc = -ENXIO;
6184 : :
6185 [ - + ]: 379 : pthread_mutex_lock(&nvme_ctrlr->mutex);
6186 : :
6187 [ + - ]: 436 : TAILQ_FOREACH_REVERSE_SAFE(p, &nvme_ctrlr->trids, nvme_paths, link, t) {
6188 [ + + ]: 436 : if (p == TAILQ_FIRST(&nvme_ctrlr->trids)) {
6189 : 379 : break;
6190 : : }
6191 : :
6192 [ + + ]: 57 : if (!nvme_path_id_compare(p, path_id)) {
6193 : 22 : continue;
6194 : : }
6195 : :
6196 : : /* We are not using the specified path. */
6197 [ + + ]: 35 : TAILQ_REMOVE(&nvme_ctrlr->trids, p, link);
6198 : 35 : free(p);
6199 : 35 : rc = 0;
6200 : : }
6201 : :
6202 [ + - + + ]: 379 : if (p == NULL || !nvme_path_id_compare(p, path_id)) {
6203 [ - + ]: 44 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
6204 : 44 : return rc;
6205 : : }
6206 : :
6207 : : /* If we made it here, then this path is a match! Now we need to remove it. */
6208 : :
6209 : : /* This is the active path in use right now. The active path is always the first in the list. */
6210 [ - + ]: 335 : assert(p == nvme_ctrlr->active_path_id);
6211 : :
6212 [ + + ]: 335 : if (!TAILQ_NEXT(p, link)) {
6213 : : /* The current path is the only path. */
6214 : 326 : msg_fn = _nvme_ctrlr_destruct;
6215 : 326 : rc = bdev_nvme_delete_ctrlr_unsafe(nvme_ctrlr, false);
6216 : : } else {
6217 : : /* There is an alternative path. */
6218 : 9 : msg_fn = _bdev_nvme_reset_ctrlr;
6219 : 9 : rc = bdev_nvme_failover_ctrlr_unsafe(nvme_ctrlr, true);
6220 : : }
6221 : :
6222 [ - + ]: 335 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
6223 : :
6224 [ + - ]: 335 : if (rc == 0) {
6225 : 335 : spdk_thread_send_msg(nvme_ctrlr->thread, msg_fn, nvme_ctrlr);
6226 [ # # ]: 0 : } else if (rc == -EALREADY) {
6227 : 0 : rc = 0;
6228 : : }
6229 : :
6230 : 335 : return rc;
6231 : : }
6232 : :
6233 : : int
6234 : 314 : bdev_nvme_delete(const char *name, const struct nvme_path_id *path_id,
6235 : : bdev_nvme_delete_done_fn delete_done, void *delete_done_ctx)
6236 : : {
6237 : : struct nvme_bdev_ctrlr *nbdev_ctrlr;
6238 : : struct nvme_ctrlr *nvme_ctrlr, *tmp_nvme_ctrlr;
6239 : 314 : struct bdev_nvme_delete_ctx *ctx = NULL;
6240 : 314 : int rc = -ENXIO, _rc;
6241 : :
6242 [ + - - + ]: 314 : if (name == NULL || path_id == NULL) {
6243 : 0 : rc = -EINVAL;
6244 : 0 : goto exit;
6245 : : }
6246 : :
6247 [ - + ]: 314 : pthread_mutex_lock(&g_bdev_nvme_mutex);
6248 : :
6249 : 314 : nbdev_ctrlr = nvme_bdev_ctrlr_get_by_name(name);
6250 [ - + ]: 314 : if (nbdev_ctrlr == NULL) {
6251 [ # # ]: 0 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
6252 : :
6253 : 0 : SPDK_ERRLOG("Failed to find NVMe bdev controller\n");
6254 : 0 : rc = -ENODEV;
6255 : 0 : goto exit;
6256 : : }
6257 : :
6258 [ + + ]: 693 : TAILQ_FOREACH_SAFE(nvme_ctrlr, &nbdev_ctrlr->ctrlrs, tailq, tmp_nvme_ctrlr) {
6259 : 379 : _rc = _bdev_nvme_delete(nvme_ctrlr, path_id);
6260 [ + + - + ]: 379 : if (_rc < 0 && _rc != -ENXIO) {
6261 [ # # ]: 0 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
6262 : 0 : rc = _rc;
6263 : 0 : goto exit;
6264 [ + + ]: 379 : } else if (_rc == 0) {
6265 : : /* We traverse all remaining nvme_ctrlrs even if one nvme_ctrlr
6266 : : * was deleted successfully. To remember the successful deletion,
6267 : : * overwrite rc only if _rc is zero.
6268 : : */
6269 : 350 : rc = 0;
6270 : : }
6271 : : }
6272 : :
6273 [ - + ]: 314 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
6274 : :
6275 [ + + + + ]: 314 : if (rc != 0 || delete_done == NULL) {
6276 : 222 : goto exit;
6277 : : }
6278 : :
6279 : 92 : ctx = calloc(1, sizeof(*ctx));
6280 [ - + ]: 92 : if (ctx == NULL) {
6281 : 0 : SPDK_ERRLOG("Failed to allocate context for bdev_nvme_delete\n");
6282 : 0 : rc = -ENOMEM;
6283 : 0 : goto exit;
6284 : : }
6285 : :
6286 [ - + ]: 92 : ctx->name = strdup(name);
6287 [ - + ]: 92 : if (ctx->name == NULL) {
6288 : 0 : SPDK_ERRLOG("Failed to copy controller name for deletion\n");
6289 : 0 : rc = -ENOMEM;
6290 : 0 : goto exit;
6291 : : }
6292 : :
6293 : 92 : ctx->delete_done = delete_done;
6294 : 92 : ctx->delete_done_ctx = delete_done_ctx;
6295 : 92 : ctx->path_id = *path_id;
6296 : 92 : ctx->timeout_ticks = spdk_get_ticks() + 10 * spdk_get_ticks_hz();
6297 : 92 : ctx->poller = SPDK_POLLER_REGISTER(bdev_nvme_delete_complete_poll, ctx, 1000);
6298 [ + - ]: 92 : if (ctx->poller == NULL) {
6299 : 0 : SPDK_ERRLOG("Failed to register bdev_nvme_delete poller\n");
6300 : 0 : rc = -ENOMEM;
6301 : 0 : goto exit;
6302 : : }
6303 : :
6304 : 92 : exit:
6305 [ + + ]: 314 : if (rc != 0) {
6306 : 4 : free_bdev_nvme_delete_ctx(ctx);
6307 : : }
6308 : :
6309 : 314 : return rc;
6310 : : }
6311 : :
6312 : : #define DISCOVERY_INFOLOG(ctx, format, ...) \
6313 : : SPDK_INFOLOG(bdev_nvme, "Discovery[%s:%s] " format, ctx->trid.traddr, ctx->trid.trsvcid, ##__VA_ARGS__);
6314 : :
6315 : : #define DISCOVERY_ERRLOG(ctx, format, ...) \
6316 : : SPDK_ERRLOG("Discovery[%s:%s] " format, ctx->trid.traddr, ctx->trid.trsvcid, ##__VA_ARGS__);
6317 : :
6318 : : struct discovery_entry_ctx {
6319 : : char name[128];
6320 : : struct spdk_nvme_transport_id trid;
6321 : : struct spdk_nvme_ctrlr_opts drv_opts;
6322 : : struct spdk_nvmf_discovery_log_page_entry entry;
6323 : : TAILQ_ENTRY(discovery_entry_ctx) tailq;
6324 : : struct discovery_ctx *ctx;
6325 : : };
6326 : :
6327 : : struct discovery_ctx {
6328 : : char *name;
6329 : : spdk_bdev_nvme_start_discovery_fn start_cb_fn;
6330 : : spdk_bdev_nvme_stop_discovery_fn stop_cb_fn;
6331 : : void *cb_ctx;
6332 : : struct spdk_nvme_probe_ctx *probe_ctx;
6333 : : struct spdk_nvme_detach_ctx *detach_ctx;
6334 : : struct spdk_nvme_ctrlr *ctrlr;
6335 : : struct spdk_nvme_transport_id trid;
6336 : : struct discovery_entry_ctx *entry_ctx_in_use;
6337 : : struct spdk_poller *poller;
6338 : : struct spdk_nvme_ctrlr_opts drv_opts;
6339 : : struct nvme_ctrlr_opts bdev_opts;
6340 : : struct spdk_nvmf_discovery_log_page *log_page;
6341 : : TAILQ_ENTRY(discovery_ctx) tailq;
6342 : : TAILQ_HEAD(, discovery_entry_ctx) nvm_entry_ctxs;
6343 : : TAILQ_HEAD(, discovery_entry_ctx) discovery_entry_ctxs;
6344 : : int rc;
6345 : : bool wait_for_attach;
6346 : : uint64_t timeout_ticks;
6347 : : /* Denotes that the discovery service is being started. We're waiting
6348 : : * for the initial connection to the discovery controller to be
6349 : : * established and attach discovered NVM ctrlrs.
6350 : : */
6351 : : bool initializing;
6352 : : /* Denotes if a discovery is currently in progress for this context.
6353 : : * That includes connecting to newly discovered subsystems. Used to
6354 : : * ensure we do not start a new discovery until an existing one is
6355 : : * complete.
6356 : : */
6357 : : bool in_progress;
6358 : :
6359 : : /* Denotes if another discovery is needed after the one in progress
6360 : : * completes. Set when we receive an AER completion while a discovery
6361 : : * is already in progress.
6362 : : */
6363 : : bool pending;
6364 : :
6365 : : /* Signal to the discovery context poller that it should stop the
6366 : : * discovery service, including detaching from the current discovery
6367 : : * controller.
6368 : : */
6369 : : bool stop;
6370 : :
6371 : : struct spdk_thread *calling_thread;
6372 : : uint32_t index;
6373 : : uint32_t attach_in_progress;
6374 : : char *hostnqn;
6375 : :
6376 : : /* Denotes if the discovery service was started by the mdns discovery.
6377 : : */
6378 : : bool from_mdns_discovery_service;
6379 : : };
6380 : :
6381 : : TAILQ_HEAD(discovery_ctxs, discovery_ctx);
6382 : : static struct discovery_ctxs g_discovery_ctxs = TAILQ_HEAD_INITIALIZER(g_discovery_ctxs);
6383 : :
6384 : : static void get_discovery_log_page(struct discovery_ctx *ctx);
6385 : :
6386 : : static void
6387 : 34 : free_discovery_ctx(struct discovery_ctx *ctx)
6388 : : {
6389 : 34 : free(ctx->log_page);
6390 : 34 : free(ctx->hostnqn);
6391 : 34 : free(ctx->name);
6392 : 34 : free(ctx);
6393 : 34 : }
6394 : :
6395 : : static void
6396 : 47 : discovery_complete(struct discovery_ctx *ctx)
6397 : : {
6398 : 47 : ctx->initializing = false;
6399 : 47 : ctx->in_progress = false;
6400 [ - + + + ]: 47 : if (ctx->pending) {
6401 : 4 : ctx->pending = false;
6402 : 4 : get_discovery_log_page(ctx);
6403 : : }
6404 : 47 : }
6405 : :
6406 : : static void
6407 : 157 : build_trid_from_log_page_entry(struct spdk_nvme_transport_id *trid,
6408 : : struct spdk_nvmf_discovery_log_page_entry *entry)
6409 : : {
6410 : : char *space;
6411 : :
6412 : 157 : trid->trtype = entry->trtype;
6413 : 157 : trid->adrfam = entry->adrfam;
6414 [ - + - + ]: 157 : memcpy(trid->traddr, entry->traddr, sizeof(entry->traddr));
6415 [ - + - + ]: 157 : memcpy(trid->trsvcid, entry->trsvcid, sizeof(entry->trsvcid));
6416 : : /* Because the source buffer (entry->subnqn) is longer than trid->subnqn, and
6417 : : * before call to this function trid->subnqn is zeroed out, we need
6418 : : * to copy sizeof(trid->subnqn) minus one byte to make sure the last character
6419 : : * remains 0. Then we can shorten the string (replace ' ' with 0) if required
6420 : : */
6421 [ - + - + ]: 157 : memcpy(trid->subnqn, entry->subnqn, sizeof(trid->subnqn) - 1);
6422 : :
6423 : : /* We want the traddr, trsvcid and subnqn fields to be NULL-terminated.
6424 : : * But the log page entries typically pad them with spaces, not zeroes.
6425 : : * So add a NULL terminator to each of these fields at the appropriate
6426 : : * location.
6427 : : */
6428 [ - + ]: 157 : space = strchr(trid->traddr, ' ');
6429 [ + - ]: 157 : if (space) {
6430 : 157 : *space = 0;
6431 : : }
6432 [ - + ]: 157 : space = strchr(trid->trsvcid, ' ');
6433 [ + - ]: 157 : if (space) {
6434 : 157 : *space = 0;
6435 : : }
6436 [ - + ]: 157 : space = strchr(trid->subnqn, ' ');
6437 [ - + ]: 157 : if (space) {
6438 : 0 : *space = 0;
6439 : : }
6440 : 157 : }
6441 : :
6442 : : static void
6443 : 36 : _stop_discovery(void *_ctx)
6444 : : {
6445 : 36 : struct discovery_ctx *ctx = _ctx;
6446 : :
6447 [ - + ]: 36 : if (ctx->attach_in_progress > 0) {
6448 : 0 : spdk_thread_send_msg(spdk_get_thread(), _stop_discovery, ctx);
6449 : 0 : return;
6450 : : }
6451 : :
6452 : 36 : ctx->stop = true;
6453 : :
6454 [ + + ]: 65 : while (!TAILQ_EMPTY(&ctx->nvm_entry_ctxs)) {
6455 : : struct discovery_entry_ctx *entry_ctx;
6456 : 29 : struct nvme_path_id path = {};
6457 : :
6458 : 29 : entry_ctx = TAILQ_FIRST(&ctx->nvm_entry_ctxs);
6459 : 29 : path.trid = entry_ctx->trid;
6460 : 29 : bdev_nvme_delete(entry_ctx->name, &path, NULL, NULL);
6461 [ - + ]: 29 : TAILQ_REMOVE(&ctx->nvm_entry_ctxs, entry_ctx, tailq);
6462 : 29 : free(entry_ctx);
6463 : : }
6464 : :
6465 [ + + ]: 79 : while (!TAILQ_EMPTY(&ctx->discovery_entry_ctxs)) {
6466 : : struct discovery_entry_ctx *entry_ctx;
6467 : :
6468 : 43 : entry_ctx = TAILQ_FIRST(&ctx->discovery_entry_ctxs);
6469 [ + + ]: 43 : TAILQ_REMOVE(&ctx->discovery_entry_ctxs, entry_ctx, tailq);
6470 : 43 : free(entry_ctx);
6471 : : }
6472 : :
6473 : 36 : free(ctx->entry_ctx_in_use);
6474 : 36 : ctx->entry_ctx_in_use = NULL;
6475 : : }
6476 : :
6477 : : static void
6478 : 36 : stop_discovery(struct discovery_ctx *ctx, spdk_bdev_nvme_stop_discovery_fn cb_fn, void *cb_ctx)
6479 : : {
6480 : 36 : ctx->stop_cb_fn = cb_fn;
6481 : 36 : ctx->cb_ctx = cb_ctx;
6482 : :
6483 [ - + ]: 36 : if (ctx->attach_in_progress > 0) {
6484 [ # # # # ]: 0 : DISCOVERY_INFOLOG(ctx, "stopping discovery with attach_in_progress: %"PRIu32"\n",
6485 : : ctx->attach_in_progress);
6486 : : }
6487 : :
6488 : 36 : _stop_discovery(ctx);
6489 : 36 : }
6490 : :
6491 : : static void
6492 : 15 : remove_discovery_entry(struct nvme_ctrlr *nvme_ctrlr)
6493 : : {
6494 : : struct discovery_ctx *d_ctx;
6495 : : struct nvme_path_id *path_id;
6496 : 15 : struct spdk_nvme_transport_id trid = {};
6497 : : struct discovery_entry_ctx *entry_ctx, *tmp;
6498 : :
6499 : 15 : path_id = TAILQ_FIRST(&nvme_ctrlr->trids);
6500 : :
6501 [ + + ]: 18 : TAILQ_FOREACH(d_ctx, &g_discovery_ctxs, tailq) {
6502 [ + + ]: 6 : TAILQ_FOREACH_SAFE(entry_ctx, &d_ctx->nvm_entry_ctxs, tailq, tmp) {
6503 : 3 : build_trid_from_log_page_entry(&trid, &entry_ctx->entry);
6504 [ - + ]: 3 : if (spdk_nvme_transport_id_compare(&trid, &path_id->trid) != 0) {
6505 : 0 : continue;
6506 : : }
6507 : :
6508 [ - + ]: 3 : TAILQ_REMOVE(&d_ctx->nvm_entry_ctxs, entry_ctx, tailq);
6509 : 3 : free(entry_ctx);
6510 [ - + + - ]: 3 : DISCOVERY_INFOLOG(d_ctx, "Remove discovery entry: %s:%s:%s\n",
6511 : : trid.subnqn, trid.traddr, trid.trsvcid);
6512 : :
6513 : : /* Fail discovery ctrlr to force reattach attempt */
6514 : 3 : spdk_nvme_ctrlr_fail(d_ctx->ctrlr);
6515 : : }
6516 : : }
6517 : 15 : }
6518 : :
6519 : : static void
6520 : 47 : discovery_remove_controllers(struct discovery_ctx *ctx)
6521 : : {
6522 : 47 : struct spdk_nvmf_discovery_log_page *log_page = ctx->log_page;
6523 : : struct discovery_entry_ctx *entry_ctx, *tmp;
6524 : : struct spdk_nvmf_discovery_log_page_entry *new_entry, *old_entry;
6525 : 47 : struct spdk_nvme_transport_id old_trid = {};
6526 : : uint64_t numrec, i;
6527 : : bool found;
6528 : :
6529 : 47 : numrec = from_le64(&log_page->numrec);
6530 [ + + ]: 105 : TAILQ_FOREACH_SAFE(entry_ctx, &ctx->nvm_entry_ctxs, tailq, tmp) {
6531 : 58 : found = false;
6532 : 58 : old_entry = &entry_ctx->entry;
6533 : 58 : build_trid_from_log_page_entry(&old_trid, old_entry);
6534 [ + + ]: 139 : for (i = 0; i < numrec; i++) {
6535 : 134 : new_entry = &log_page->entries[i];
6536 [ - + - + : 134 : if (!memcmp(old_entry, new_entry, sizeof(*old_entry))) {
+ + ]
6537 [ - + + + ]: 53 : DISCOVERY_INFOLOG(ctx, "NVM %s:%s:%s found again\n",
6538 : : old_trid.subnqn, old_trid.traddr, old_trid.trsvcid);
6539 : 53 : found = true;
6540 : 53 : break;
6541 : : }
6542 : : }
6543 [ + + ]: 58 : if (!found) {
6544 : 5 : struct nvme_path_id path = {};
6545 : :
6546 [ - + + - ]: 5 : DISCOVERY_INFOLOG(ctx, "NVM %s:%s:%s not found\n",
6547 : : old_trid.subnqn, old_trid.traddr, old_trid.trsvcid);
6548 : :
6549 : 5 : path.trid = entry_ctx->trid;
6550 : 5 : bdev_nvme_delete(entry_ctx->name, &path, NULL, NULL);
6551 [ + - ]: 5 : TAILQ_REMOVE(&ctx->nvm_entry_ctxs, entry_ctx, tailq);
6552 : 5 : free(entry_ctx);
6553 : : }
6554 : : }
6555 : 47 : free(log_page);
6556 : 47 : ctx->log_page = NULL;
6557 : 47 : discovery_complete(ctx);
6558 : 47 : }
6559 : :
6560 : : static void
6561 : 42 : complete_discovery_start(struct discovery_ctx *ctx, int status)
6562 : : {
6563 : 42 : ctx->timeout_ticks = 0;
6564 : 42 : ctx->rc = status;
6565 [ + + ]: 42 : if (ctx->start_cb_fn) {
6566 : 27 : ctx->start_cb_fn(ctx->cb_ctx, status);
6567 : 27 : ctx->start_cb_fn = NULL;
6568 : 27 : ctx->cb_ctx = NULL;
6569 : : }
6570 : 42 : }
6571 : :
6572 : : static void
6573 : 37 : discovery_attach_controller_done(void *cb_ctx, size_t bdev_count, int rc)
6574 : : {
6575 : 37 : struct discovery_entry_ctx *entry_ctx = cb_ctx;
6576 : 37 : struct discovery_ctx *ctx = entry_ctx->ctx;
6577 : :
6578 [ - + + + ]: 37 : DISCOVERY_INFOLOG(ctx, "attach %s done\n", entry_ctx->name);
6579 : 37 : ctx->attach_in_progress--;
6580 [ + - ]: 37 : if (ctx->attach_in_progress == 0) {
6581 : 37 : complete_discovery_start(ctx, ctx->rc);
6582 [ - + + + : 37 : if (ctx->initializing && ctx->rc != 0) {
- + ]
6583 : 0 : DISCOVERY_ERRLOG(ctx, "stopping discovery due to errors: %d\n", ctx->rc);
6584 : 0 : stop_discovery(ctx, NULL, ctx->cb_ctx);
6585 : : } else {
6586 : 37 : discovery_remove_controllers(ctx);
6587 : : }
6588 : : }
6589 : 37 : }
6590 : :
6591 : : static struct discovery_entry_ctx *
6592 : 93 : create_discovery_entry_ctx(struct discovery_ctx *ctx, struct spdk_nvme_transport_id *trid)
6593 : : {
6594 : : struct discovery_entry_ctx *new_ctx;
6595 : :
6596 : 93 : new_ctx = calloc(1, sizeof(*new_ctx));
6597 [ - + ]: 93 : if (new_ctx == NULL) {
6598 : 0 : DISCOVERY_ERRLOG(ctx, "could not allocate new entry_ctx\n");
6599 : 0 : return NULL;
6600 : : }
6601 : :
6602 : 93 : new_ctx->ctx = ctx;
6603 [ - + - + ]: 93 : memcpy(&new_ctx->trid, trid, sizeof(*trid));
6604 : 93 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&new_ctx->drv_opts, sizeof(new_ctx->drv_opts));
6605 [ - + ]: 93 : snprintf(new_ctx->drv_opts.hostnqn, sizeof(new_ctx->drv_opts.hostnqn), "%s", ctx->hostnqn);
6606 : 93 : return new_ctx;
6607 : : }
6608 : :
6609 : : static void
6610 : 47 : discovery_log_page_cb(void *cb_arg, int rc, const struct spdk_nvme_cpl *cpl,
6611 : : struct spdk_nvmf_discovery_log_page *log_page)
6612 : : {
6613 : 47 : struct discovery_ctx *ctx = cb_arg;
6614 : : struct discovery_entry_ctx *entry_ctx, *tmp;
6615 : : struct spdk_nvmf_discovery_log_page_entry *new_entry, *old_entry;
6616 : : uint64_t numrec, i;
6617 : : bool found;
6618 : :
6619 [ + - + - : 47 : if (rc || spdk_nvme_cpl_is_error(cpl)) {
- + ]
6620 : 0 : DISCOVERY_ERRLOG(ctx, "could not get discovery log page\n");
6621 : 0 : return;
6622 : : }
6623 : :
6624 : 47 : ctx->log_page = log_page;
6625 [ - + ]: 47 : assert(ctx->attach_in_progress == 0);
6626 : 47 : numrec = from_le64(&log_page->numrec);
6627 [ + + ]: 67 : TAILQ_FOREACH_SAFE(entry_ctx, &ctx->discovery_entry_ctxs, tailq, tmp) {
6628 [ + + ]: 20 : TAILQ_REMOVE(&ctx->discovery_entry_ctxs, entry_ctx, tailq);
6629 : 20 : free(entry_ctx);
6630 : : }
6631 [ + + ]: 159 : for (i = 0; i < numrec; i++) {
6632 : 112 : found = false;
6633 : 112 : new_entry = &log_page->entries[i];
6634 [ + + ]: 112 : if (new_entry->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY_CURRENT ||
6635 [ - + ]: 53 : new_entry->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY) {
6636 : : struct discovery_entry_ctx *new_ctx;
6637 : 59 : struct spdk_nvme_transport_id trid = {};
6638 : :
6639 : 59 : build_trid_from_log_page_entry(&trid, new_entry);
6640 : 59 : new_ctx = create_discovery_entry_ctx(ctx, &trid);
6641 [ - + ]: 59 : if (new_ctx == NULL) {
6642 : 0 : DISCOVERY_ERRLOG(ctx, "could not allocate new entry_ctx\n");
6643 : 0 : break;
6644 : : }
6645 : :
6646 : 59 : TAILQ_INSERT_TAIL(&ctx->discovery_entry_ctxs, new_ctx, tailq);
6647 : 59 : continue;
6648 : : }
6649 [ + + ]: 65 : TAILQ_FOREACH(entry_ctx, &ctx->nvm_entry_ctxs, tailq) {
6650 : 28 : old_entry = &entry_ctx->entry;
6651 [ - + - + : 28 : if (!memcmp(new_entry, old_entry, sizeof(*new_entry))) {
+ + ]
6652 : 16 : found = true;
6653 : 16 : break;
6654 : : }
6655 : : }
6656 [ + + ]: 53 : if (!found) {
6657 : 37 : struct discovery_entry_ctx *subnqn_ctx = NULL, *new_ctx;
6658 : : struct discovery_ctx *d_ctx;
6659 : :
6660 [ + + ]: 77 : TAILQ_FOREACH(d_ctx, &g_discovery_ctxs, tailq) {
6661 [ + + ]: 51 : TAILQ_FOREACH(subnqn_ctx, &d_ctx->nvm_entry_ctxs, tailq) {
6662 [ - + - + : 11 : if (!memcmp(subnqn_ctx->entry.subnqn, new_entry->subnqn,
+ + ]
6663 : : sizeof(new_entry->subnqn))) {
6664 : 5 : break;
6665 : : }
6666 : : }
6667 [ + + ]: 45 : if (subnqn_ctx) {
6668 : 5 : break;
6669 : : }
6670 : : }
6671 : :
6672 : 37 : new_ctx = calloc(1, sizeof(*new_ctx));
6673 [ - + ]: 37 : if (new_ctx == NULL) {
6674 : 0 : DISCOVERY_ERRLOG(ctx, "could not allocate new entry_ctx\n");
6675 : 0 : break;
6676 : : }
6677 : :
6678 : 37 : new_ctx->ctx = ctx;
6679 [ - + - + ]: 37 : memcpy(&new_ctx->entry, new_entry, sizeof(*new_entry));
6680 : 37 : build_trid_from_log_page_entry(&new_ctx->trid, new_entry);
6681 [ + + ]: 37 : if (subnqn_ctx) {
6682 : 5 : snprintf(new_ctx->name, sizeof(new_ctx->name), "%s", subnqn_ctx->name);
6683 [ - + + - ]: 5 : DISCOVERY_INFOLOG(ctx, "NVM %s:%s:%s new path for %s\n",
6684 : : new_ctx->trid.subnqn, new_ctx->trid.traddr, new_ctx->trid.trsvcid,
6685 : : new_ctx->name);
6686 : : } else {
6687 : 32 : snprintf(new_ctx->name, sizeof(new_ctx->name), "%s%d", ctx->name, ctx->index++);
6688 [ - + + + ]: 32 : DISCOVERY_INFOLOG(ctx, "NVM %s:%s:%s new subsystem %s\n",
6689 : : new_ctx->trid.subnqn, new_ctx->trid.traddr, new_ctx->trid.trsvcid,
6690 : : new_ctx->name);
6691 : : }
6692 : 37 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&new_ctx->drv_opts, sizeof(new_ctx->drv_opts));
6693 : 37 : snprintf(new_ctx->drv_opts.hostnqn, sizeof(new_ctx->drv_opts.hostnqn), "%s", ctx->hostnqn);
6694 : 37 : rc = bdev_nvme_create(&new_ctx->trid, new_ctx->name, NULL, 0,
6695 : : discovery_attach_controller_done, new_ctx,
6696 : : &new_ctx->drv_opts, &ctx->bdev_opts, true);
6697 [ + - ]: 37 : if (rc == 0) {
6698 : 37 : TAILQ_INSERT_TAIL(&ctx->nvm_entry_ctxs, new_ctx, tailq);
6699 : 37 : ctx->attach_in_progress++;
6700 : : } else {
6701 : 0 : DISCOVERY_ERRLOG(ctx, "bdev_nvme_create failed (%s)\n", spdk_strerror(-rc));
6702 : : }
6703 : : }
6704 : : }
6705 : :
6706 [ + + ]: 47 : if (ctx->attach_in_progress == 0) {
6707 : 10 : discovery_remove_controllers(ctx);
6708 : : }
6709 : : }
6710 : :
6711 : : static void
6712 : 47 : get_discovery_log_page(struct discovery_ctx *ctx)
6713 : : {
6714 : : int rc;
6715 : :
6716 [ - + - + ]: 47 : assert(ctx->in_progress == false);
6717 : 47 : ctx->in_progress = true;
6718 : 47 : rc = spdk_nvme_ctrlr_get_discovery_log_page(ctx->ctrlr, discovery_log_page_cb, ctx);
6719 [ - + ]: 47 : if (rc != 0) {
6720 : 0 : DISCOVERY_ERRLOG(ctx, "could not get discovery log page\n");
6721 : : }
6722 [ - + + + ]: 47 : DISCOVERY_INFOLOG(ctx, "sent discovery log page command\n");
6723 : 47 : }
6724 : :
6725 : : static void
6726 : 14 : discovery_aer_cb(void *arg, const struct spdk_nvme_cpl *cpl)
6727 : : {
6728 : 14 : struct discovery_ctx *ctx = arg;
6729 : 14 : uint32_t log_page_id = (cpl->cdw0 & 0xFF0000) >> 16;
6730 : :
6731 [ + - - + ]: 14 : if (spdk_nvme_cpl_is_error(cpl)) {
6732 : 0 : DISCOVERY_ERRLOG(ctx, "aer failed\n");
6733 : 0 : return;
6734 : : }
6735 : :
6736 [ - + ]: 14 : if (log_page_id != SPDK_NVME_LOG_DISCOVERY) {
6737 : 0 : DISCOVERY_ERRLOG(ctx, "unexpected log page 0x%x\n", log_page_id);
6738 : 0 : return;
6739 : : }
6740 : :
6741 [ - + + - ]: 14 : DISCOVERY_INFOLOG(ctx, "got aer\n");
6742 [ - + + + ]: 14 : if (ctx->in_progress) {
6743 : 4 : ctx->pending = true;
6744 : 4 : return;
6745 : : }
6746 : :
6747 : 10 : get_discovery_log_page(ctx);
6748 : : }
6749 : :
6750 : : static void
6751 : 33 : discovery_attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
6752 : : struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
6753 : : {
6754 : 33 : struct spdk_nvme_ctrlr_opts *user_opts = cb_ctx;
6755 : : struct discovery_ctx *ctx;
6756 : :
6757 : 33 : ctx = SPDK_CONTAINEROF(user_opts, struct discovery_ctx, drv_opts);
6758 : :
6759 [ - + + + ]: 33 : DISCOVERY_INFOLOG(ctx, "discovery ctrlr attached\n");
6760 : 33 : ctx->probe_ctx = NULL;
6761 : 33 : ctx->ctrlr = ctrlr;
6762 : :
6763 [ - + ]: 33 : if (ctx->rc != 0) {
6764 : 0 : DISCOVERY_ERRLOG(ctx, "encountered error while attaching discovery ctrlr: %d\n",
6765 : : ctx->rc);
6766 : 0 : return;
6767 : : }
6768 : :
6769 : 33 : spdk_nvme_ctrlr_register_aer_callback(ctx->ctrlr, discovery_aer_cb, ctx);
6770 : : }
6771 : :
6772 : : static int
6773 : 107879 : discovery_poller(void *arg)
6774 : : {
6775 : 107879 : struct discovery_ctx *ctx = arg;
6776 : : struct spdk_nvme_transport_id *trid;
6777 : : int rc;
6778 : :
6779 [ + + ]: 107879 : if (ctx->detach_ctx) {
6780 : 243 : rc = spdk_nvme_detach_poll_async(ctx->detach_ctx);
6781 [ + + ]: 243 : if (rc != -EAGAIN) {
6782 : 33 : ctx->detach_ctx = NULL;
6783 : 33 : ctx->ctrlr = NULL;
6784 : : }
6785 [ - + + + ]: 107636 : } else if (ctx->stop) {
6786 [ + + ]: 60 : if (ctx->ctrlr != NULL) {
6787 : 30 : rc = spdk_nvme_detach_async(ctx->ctrlr, &ctx->detach_ctx);
6788 [ + - ]: 30 : if (rc == 0) {
6789 : 30 : return SPDK_POLLER_BUSY;
6790 : : }
6791 : 0 : DISCOVERY_ERRLOG(ctx, "could not detach discovery ctrlr\n");
6792 : : }
6793 : 30 : spdk_poller_unregister(&ctx->poller);
6794 [ + + ]: 30 : TAILQ_REMOVE(&g_discovery_ctxs, ctx, tailq);
6795 [ - + ]: 30 : assert(ctx->start_cb_fn == NULL);
6796 [ + + ]: 30 : if (ctx->stop_cb_fn != NULL) {
6797 : 27 : ctx->stop_cb_fn(ctx->cb_ctx);
6798 : : }
6799 : 30 : free_discovery_ctx(ctx);
6800 [ + + + + ]: 107576 : } else if (ctx->probe_ctx == NULL && ctx->ctrlr == NULL) {
6801 [ + + + + ]: 47 : if (ctx->timeout_ticks != 0 && ctx->timeout_ticks < spdk_get_ticks()) {
6802 : 4 : DISCOVERY_ERRLOG(ctx, "timed out while attaching discovery ctrlr\n");
6803 [ - + - + ]: 4 : assert(ctx->initializing);
6804 : 4 : spdk_poller_unregister(&ctx->poller);
6805 [ - + ]: 4 : TAILQ_REMOVE(&g_discovery_ctxs, ctx, tailq);
6806 : 4 : complete_discovery_start(ctx, -ETIMEDOUT);
6807 : 4 : stop_discovery(ctx, NULL, NULL);
6808 : 4 : free_discovery_ctx(ctx);
6809 : 4 : return SPDK_POLLER_BUSY;
6810 : : }
6811 : :
6812 [ - + ]: 43 : assert(ctx->entry_ctx_in_use == NULL);
6813 : 43 : ctx->entry_ctx_in_use = TAILQ_FIRST(&ctx->discovery_entry_ctxs);
6814 [ + + ]: 43 : TAILQ_REMOVE(&ctx->discovery_entry_ctxs, ctx->entry_ctx_in_use, tailq);
6815 : 43 : trid = &ctx->entry_ctx_in_use->trid;
6816 : 43 : ctx->probe_ctx = spdk_nvme_connect_async(trid, &ctx->drv_opts, discovery_attach_cb);
6817 [ + + ]: 43 : if (ctx->probe_ctx) {
6818 : 33 : spdk_poller_unregister(&ctx->poller);
6819 : 33 : ctx->poller = SPDK_POLLER_REGISTER(discovery_poller, ctx, 1000);
6820 : : } else {
6821 : 10 : DISCOVERY_ERRLOG(ctx, "could not start discovery connect\n");
6822 : 10 : TAILQ_INSERT_TAIL(&ctx->discovery_entry_ctxs, ctx->entry_ctx_in_use, tailq);
6823 : 10 : ctx->entry_ctx_in_use = NULL;
6824 : : }
6825 [ + + ]: 107529 : } else if (ctx->probe_ctx) {
6826 [ + + - + ]: 33 : if (ctx->timeout_ticks != 0 && ctx->timeout_ticks < spdk_get_ticks()) {
6827 : 0 : DISCOVERY_ERRLOG(ctx, "timed out while attaching discovery ctrlr\n");
6828 : 0 : complete_discovery_start(ctx, -ETIMEDOUT);
6829 : 0 : return SPDK_POLLER_BUSY;
6830 : : }
6831 : :
6832 : 33 : rc = spdk_nvme_probe_poll_async(ctx->probe_ctx);
6833 [ + - ]: 33 : if (rc != -EAGAIN) {
6834 [ - + ]: 33 : if (ctx->rc != 0) {
6835 [ # # # # ]: 0 : assert(ctx->initializing);
6836 : 0 : stop_discovery(ctx, NULL, ctx->cb_ctx);
6837 : : } else {
6838 [ - + ]: 33 : assert(rc == 0);
6839 [ - + + + ]: 33 : DISCOVERY_INFOLOG(ctx, "discovery ctrlr connected\n");
6840 : 33 : ctx->rc = rc;
6841 : 33 : get_discovery_log_page(ctx);
6842 : : }
6843 : : }
6844 : : } else {
6845 [ + + + + ]: 107496 : if (ctx->timeout_ticks != 0 && ctx->timeout_ticks < spdk_get_ticks()) {
6846 : 1 : DISCOVERY_ERRLOG(ctx, "timed out while attaching NVM ctrlrs\n");
6847 : 1 : complete_discovery_start(ctx, -ETIMEDOUT);
6848 : : /* We need to wait until all NVM ctrlrs are attached before we stop the
6849 : : * discovery service to make sure we don't detach a ctrlr that is still
6850 : : * being attached.
6851 : : */
6852 [ + - ]: 1 : if (ctx->attach_in_progress == 0) {
6853 : 1 : stop_discovery(ctx, NULL, ctx->cb_ctx);
6854 : 1 : return SPDK_POLLER_BUSY;
6855 : : }
6856 : : }
6857 : :
6858 : 107495 : rc = spdk_nvme_ctrlr_process_admin_completions(ctx->ctrlr);
6859 [ + + ]: 107495 : if (rc < 0) {
6860 : 3 : spdk_poller_unregister(&ctx->poller);
6861 : 3 : ctx->poller = SPDK_POLLER_REGISTER(discovery_poller, ctx, 1000 * 1000);
6862 : 3 : TAILQ_INSERT_TAIL(&ctx->discovery_entry_ctxs, ctx->entry_ctx_in_use, tailq);
6863 : 3 : ctx->entry_ctx_in_use = NULL;
6864 : :
6865 : 3 : rc = spdk_nvme_detach_async(ctx->ctrlr, &ctx->detach_ctx);
6866 [ - + ]: 3 : if (rc != 0) {
6867 : 0 : DISCOVERY_ERRLOG(ctx, "could not detach discovery ctrlr\n");
6868 : 0 : ctx->ctrlr = NULL;
6869 : : }
6870 : : }
6871 : : }
6872 : :
6873 : 107844 : return SPDK_POLLER_BUSY;
6874 : : }
6875 : :
6876 : : static void
6877 : 34 : start_discovery_poller(void *arg)
6878 : : {
6879 : 34 : struct discovery_ctx *ctx = arg;
6880 : :
6881 : 34 : TAILQ_INSERT_TAIL(&g_discovery_ctxs, ctx, tailq);
6882 : 34 : ctx->poller = SPDK_POLLER_REGISTER(discovery_poller, ctx, 1000 * 1000);
6883 : 34 : }
6884 : :
6885 : : int
6886 : 40 : bdev_nvme_start_discovery(struct spdk_nvme_transport_id *trid,
6887 : : const char *base_name,
6888 : : struct spdk_nvme_ctrlr_opts *drv_opts,
6889 : : struct nvme_ctrlr_opts *bdev_opts,
6890 : : uint64_t attach_timeout,
6891 : : bool from_mdns,
6892 : : spdk_bdev_nvme_start_discovery_fn cb_fn, void *cb_ctx)
6893 : : {
6894 : : struct discovery_ctx *ctx;
6895 : : struct discovery_entry_ctx *discovery_entry_ctx;
6896 : :
6897 : 40 : snprintf(trid->subnqn, sizeof(trid->subnqn), "%s", SPDK_NVMF_DISCOVERY_NQN);
6898 [ + + ]: 50 : TAILQ_FOREACH(ctx, &g_discovery_ctxs, tailq) {
6899 [ - + - + : 16 : if (strcmp(ctx->name, base_name) == 0) {
+ + ]
6900 : 3 : return -EEXIST;
6901 : : }
6902 : :
6903 [ + + ]: 13 : if (ctx->entry_ctx_in_use != NULL) {
6904 [ + + ]: 11 : if (!spdk_nvme_transport_id_compare(trid, &ctx->entry_ctx_in_use->trid)) {
6905 : 3 : return -EEXIST;
6906 : : }
6907 : : }
6908 : :
6909 [ + + ]: 20 : TAILQ_FOREACH(discovery_entry_ctx, &ctx->discovery_entry_ctxs, tailq) {
6910 [ - + ]: 10 : if (!spdk_nvme_transport_id_compare(trid, &discovery_entry_ctx->trid)) {
6911 : 0 : return -EEXIST;
6912 : : }
6913 : : }
6914 : : }
6915 : :
6916 : 34 : ctx = calloc(1, sizeof(*ctx));
6917 [ - + ]: 34 : if (ctx == NULL) {
6918 : 0 : return -ENOMEM;
6919 : : }
6920 : :
6921 [ - + ]: 34 : ctx->name = strdup(base_name);
6922 [ - + ]: 34 : if (ctx->name == NULL) {
6923 : 0 : free_discovery_ctx(ctx);
6924 : 0 : return -ENOMEM;
6925 : : }
6926 [ - + - + ]: 34 : memcpy(&ctx->drv_opts, drv_opts, sizeof(*drv_opts));
6927 [ - + - + ]: 34 : memcpy(&ctx->bdev_opts, bdev_opts, sizeof(*bdev_opts));
6928 : 34 : ctx->from_mdns_discovery_service = from_mdns;
6929 : 34 : ctx->bdev_opts.from_discovery_service = true;
6930 : 34 : ctx->calling_thread = spdk_get_thread();
6931 : 34 : ctx->start_cb_fn = cb_fn;
6932 : 34 : ctx->cb_ctx = cb_ctx;
6933 : 34 : ctx->initializing = true;
6934 [ + + ]: 34 : if (ctx->start_cb_fn) {
6935 : : /* We can use this when dumping json to denote if this RPC parameter
6936 : : * was specified or not.
6937 : : */
6938 : 27 : ctx->wait_for_attach = true;
6939 : : }
6940 [ + + ]: 34 : if (attach_timeout != 0) {
6941 : 42 : ctx->timeout_ticks = spdk_get_ticks() + attach_timeout *
6942 : 21 : spdk_get_ticks_hz() / 1000ull;
6943 : : }
6944 : 34 : TAILQ_INIT(&ctx->nvm_entry_ctxs);
6945 : 34 : TAILQ_INIT(&ctx->discovery_entry_ctxs);
6946 [ - + - + ]: 34 : memcpy(&ctx->trid, trid, sizeof(*trid));
6947 : : /* Even if user did not specify hostnqn, we can still strdup("\0"); */
6948 [ - + ]: 34 : ctx->hostnqn = strdup(ctx->drv_opts.hostnqn);
6949 [ - + ]: 34 : if (ctx->hostnqn == NULL) {
6950 : 0 : free_discovery_ctx(ctx);
6951 : 0 : return -ENOMEM;
6952 : : }
6953 : 34 : discovery_entry_ctx = create_discovery_entry_ctx(ctx, trid);
6954 [ - + ]: 34 : if (discovery_entry_ctx == NULL) {
6955 : 0 : DISCOVERY_ERRLOG(ctx, "could not allocate new entry_ctx\n");
6956 : 0 : free_discovery_ctx(ctx);
6957 : 0 : return -ENOMEM;
6958 : : }
6959 : :
6960 : 34 : TAILQ_INSERT_TAIL(&ctx->discovery_entry_ctxs, discovery_entry_ctx, tailq);
6961 : 34 : spdk_thread_send_msg(g_bdev_nvme_init_thread, start_discovery_poller, ctx);
6962 : 34 : return 0;
6963 : : }
6964 : :
6965 : : int
6966 : 23 : bdev_nvme_stop_discovery(const char *name, spdk_bdev_nvme_stop_discovery_fn cb_fn, void *cb_ctx)
6967 : : {
6968 : : struct discovery_ctx *ctx;
6969 : :
6970 [ + - ]: 26 : TAILQ_FOREACH(ctx, &g_discovery_ctxs, tailq) {
6971 [ - + - + : 26 : if (strcmp(name, ctx->name) == 0) {
+ + ]
6972 [ - + - + ]: 23 : if (ctx->stop) {
6973 : 0 : return -EALREADY;
6974 : : }
6975 : : /* If we're still starting the discovery service and ->rc is non-zero, we're
6976 : : * going to stop it as soon as we can
6977 : : */
6978 [ - + - + : 23 : if (ctx->initializing && ctx->rc != 0) {
- - ]
6979 : 0 : return -EALREADY;
6980 : : }
6981 : 23 : stop_discovery(ctx, cb_fn, cb_ctx);
6982 : 23 : return 0;
6983 : : }
6984 : : }
6985 : :
6986 : 0 : return -ENOENT;
6987 : : }
6988 : :
6989 : : static int
6990 : 1894 : bdev_nvme_library_init(void)
6991 : : {
6992 : 1894 : g_bdev_nvme_init_thread = spdk_get_thread();
6993 : :
6994 : 1894 : spdk_io_device_register(&g_nvme_bdev_ctrlrs, bdev_nvme_create_poll_group_cb,
6995 : : bdev_nvme_destroy_poll_group_cb,
6996 : : sizeof(struct nvme_poll_group), "nvme_poll_groups");
6997 : :
6998 : 1894 : return 0;
6999 : : }
7000 : :
7001 : : static void
7002 : 1894 : bdev_nvme_fini_destruct_ctrlrs(void)
7003 : : {
7004 : : struct nvme_bdev_ctrlr *nbdev_ctrlr;
7005 : : struct nvme_ctrlr *nvme_ctrlr;
7006 : :
7007 [ - + ]: 1894 : pthread_mutex_lock(&g_bdev_nvme_mutex);
7008 [ + + ]: 2569 : TAILQ_FOREACH(nbdev_ctrlr, &g_nvme_bdev_ctrlrs, tailq) {
7009 [ + + ]: 1352 : TAILQ_FOREACH(nvme_ctrlr, &nbdev_ctrlr->ctrlrs, tailq) {
7010 [ - + ]: 677 : pthread_mutex_lock(&nvme_ctrlr->mutex);
7011 [ - + ]: 677 : if (nvme_ctrlr->destruct) {
7012 : : /* This controller's destruction was already started
7013 : : * before the application started shutting down
7014 : : */
7015 [ # # ]: 0 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
7016 : 0 : continue;
7017 : : }
7018 : 677 : nvme_ctrlr->destruct = true;
7019 [ - + ]: 677 : pthread_mutex_unlock(&nvme_ctrlr->mutex);
7020 : :
7021 : 677 : spdk_thread_send_msg(nvme_ctrlr->thread, _nvme_ctrlr_destruct,
7022 : : nvme_ctrlr);
7023 : : }
7024 : : }
7025 : :
7026 : 1894 : g_bdev_nvme_module_finish = true;
7027 [ + + ]: 1894 : if (TAILQ_EMPTY(&g_nvme_bdev_ctrlrs)) {
7028 [ - + ]: 1384 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
7029 : 1384 : spdk_io_device_unregister(&g_nvme_bdev_ctrlrs, NULL);
7030 : 1384 : spdk_bdev_module_fini_done();
7031 : 1384 : return;
7032 : : }
7033 : :
7034 [ - + ]: 510 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
7035 : : }
7036 : :
7037 : : static void
7038 : 8 : check_discovery_fini(void *arg)
7039 : : {
7040 [ + + ]: 8 : if (TAILQ_EMPTY(&g_discovery_ctxs)) {
7041 : 7 : bdev_nvme_fini_destruct_ctrlrs();
7042 : : }
7043 : 8 : }
7044 : :
7045 : : static void
7046 : 1894 : bdev_nvme_library_fini(void)
7047 : : {
7048 : : struct nvme_probe_skip_entry *entry, *entry_tmp;
7049 : : struct discovery_ctx *ctx;
7050 : :
7051 : 1894 : spdk_poller_unregister(&g_hotplug_poller);
7052 : 1894 : free(g_hotplug_probe_ctx);
7053 : 1894 : g_hotplug_probe_ctx = NULL;
7054 : :
7055 [ + + ]: 1951 : TAILQ_FOREACH_SAFE(entry, &g_skipped_nvme_ctrlrs, tailq, entry_tmp) {
7056 [ + + ]: 57 : TAILQ_REMOVE(&g_skipped_nvme_ctrlrs, entry, tailq);
7057 : 57 : free(entry);
7058 : : }
7059 : :
7060 [ - + ]: 1894 : assert(spdk_get_thread() == g_bdev_nvme_init_thread);
7061 [ + + ]: 1894 : if (TAILQ_EMPTY(&g_discovery_ctxs)) {
7062 : 1887 : bdev_nvme_fini_destruct_ctrlrs();
7063 : : } else {
7064 [ + + ]: 15 : TAILQ_FOREACH(ctx, &g_discovery_ctxs, tailq) {
7065 : 8 : stop_discovery(ctx, check_discovery_fini, NULL);
7066 : : }
7067 : : }
7068 : 1894 : }
7069 : :
7070 : : static void
7071 : 0 : bdev_nvme_verify_pi_error(struct nvme_bdev_io *bio)
7072 : : {
7073 : 0 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
7074 : 0 : struct spdk_bdev *bdev = bdev_io->bdev;
7075 : 0 : struct spdk_dif_ctx dif_ctx;
7076 : 0 : struct spdk_dif_error err_blk = {};
7077 : : int rc;
7078 : 0 : struct spdk_dif_ctx_init_ext_opts dif_opts;
7079 : :
7080 : 0 : dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
7081 : 0 : dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
7082 : 0 : rc = spdk_dif_ctx_init(&dif_ctx,
7083 [ # # ]: 0 : bdev->blocklen, bdev->md_len, bdev->md_interleave,
7084 [ # # ]: 0 : bdev->dif_is_head_of_md, bdev->dif_type, bdev->dif_check_flags,
7085 : 0 : bdev_io->u.bdev.offset_blocks, 0, 0, 0, 0, &dif_opts);
7086 [ # # ]: 0 : if (rc != 0) {
7087 : 0 : SPDK_ERRLOG("Initialization of DIF context failed\n");
7088 : 0 : return;
7089 : : }
7090 : :
7091 [ # # # # ]: 0 : if (bdev->md_interleave) {
7092 : 0 : rc = spdk_dif_verify(bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
7093 : 0 : bdev_io->u.bdev.num_blocks, &dif_ctx, &err_blk);
7094 : : } else {
7095 : 0 : struct iovec md_iov = {
7096 : 0 : .iov_base = bdev_io->u.bdev.md_buf,
7097 : 0 : .iov_len = bdev_io->u.bdev.num_blocks * bdev->md_len,
7098 : : };
7099 : :
7100 : 0 : rc = spdk_dix_verify(bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
7101 : 0 : &md_iov, bdev_io->u.bdev.num_blocks, &dif_ctx, &err_blk);
7102 : : }
7103 : :
7104 [ # # ]: 0 : if (rc != 0) {
7105 : 0 : SPDK_ERRLOG("DIF error detected. type=%d, offset=%" PRIu32 "\n",
7106 : : err_blk.err_type, err_blk.err_offset);
7107 : : } else {
7108 : 0 : SPDK_ERRLOG("Hardware reported PI error but SPDK could not find any.\n");
7109 : : }
7110 : : }
7111 : :
7112 : : static void
7113 : 0 : bdev_nvme_no_pi_readv_done(void *ref, const struct spdk_nvme_cpl *cpl)
7114 : : {
7115 : 0 : struct nvme_bdev_io *bio = ref;
7116 : :
7117 [ # # # # ]: 0 : if (spdk_nvme_cpl_is_success(cpl)) {
7118 : : /* Run PI verification for read data buffer. */
7119 : 0 : bdev_nvme_verify_pi_error(bio);
7120 : : }
7121 : :
7122 : : /* Return original completion status */
7123 : 0 : bdev_nvme_io_complete_nvme_status(bio, &bio->cpl);
7124 : 0 : }
7125 : :
7126 : : static void
7127 : 17883981 : bdev_nvme_readv_done(void *ref, const struct spdk_nvme_cpl *cpl)
7128 : : {
7129 : 17883981 : struct nvme_bdev_io *bio = ref;
7130 : 17883981 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
7131 : : int ret;
7132 : :
7133 [ - + - - : 17883981 : if (spdk_unlikely(spdk_nvme_cpl_is_pi_error(cpl))) {
- - - - -
- - - ]
7134 : 0 : SPDK_ERRLOG("readv completed with PI error (sct=%d, sc=%d)\n",
7135 : : cpl->status.sct, cpl->status.sc);
7136 : :
7137 : : /* Save completion status to use after verifying PI error. */
7138 : 0 : bio->cpl = *cpl;
7139 : :
7140 [ # # ]: 0 : if (spdk_likely(nvme_io_path_is_available(bio->io_path))) {
7141 : : /* Read without PI checking to verify PI error. */
7142 : 0 : ret = bdev_nvme_no_pi_readv(bio,
7143 : : bdev_io->u.bdev.iovs,
7144 : : bdev_io->u.bdev.iovcnt,
7145 : : bdev_io->u.bdev.md_buf,
7146 : : bdev_io->u.bdev.num_blocks,
7147 : : bdev_io->u.bdev.offset_blocks);
7148 [ # # ]: 0 : if (ret == 0) {
7149 : 0 : return;
7150 : : }
7151 : : }
7152 : : }
7153 : :
7154 : 17883981 : bdev_nvme_io_complete_nvme_status(bio, cpl);
7155 : : }
7156 : :
7157 : : static void
7158 : 16523063 : bdev_nvme_writev_done(void *ref, const struct spdk_nvme_cpl *cpl)
7159 : : {
7160 : 16523063 : struct nvme_bdev_io *bio = ref;
7161 : :
7162 [ - + - - : 16523063 : if (spdk_unlikely(spdk_nvme_cpl_is_pi_error(cpl))) {
- - - - -
- - - ]
7163 : 0 : SPDK_ERRLOG("writev completed with PI error (sct=%d, sc=%d)\n",
7164 : : cpl->status.sct, cpl->status.sc);
7165 : : /* Run PI verification for write data buffer if PI error is detected. */
7166 : 0 : bdev_nvme_verify_pi_error(bio);
7167 : : }
7168 : :
7169 : 16523063 : bdev_nvme_io_complete_nvme_status(bio, cpl);
7170 : 16523063 : }
7171 : :
7172 : : static void
7173 : 251867 : bdev_nvme_zone_appendv_done(void *ref, const struct spdk_nvme_cpl *cpl)
7174 : : {
7175 : 251867 : struct nvme_bdev_io *bio = ref;
7176 : 251867 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
7177 : :
7178 : : /* spdk_bdev_io_get_append_location() requires that the ALBA is stored in offset_blocks.
7179 : : * Additionally, offset_blocks has to be set before calling bdev_nvme_verify_pi_error().
7180 : : */
7181 : 251867 : bdev_io->u.bdev.offset_blocks = *(uint64_t *)&cpl->cdw0;
7182 : :
7183 [ - + - - : 251867 : if (spdk_nvme_cpl_is_pi_error(cpl)) {
- - - - ]
7184 : 0 : SPDK_ERRLOG("zone append completed with PI error (sct=%d, sc=%d)\n",
7185 : : cpl->status.sct, cpl->status.sc);
7186 : : /* Run PI verification for zone append data buffer if PI error is detected. */
7187 : 0 : bdev_nvme_verify_pi_error(bio);
7188 : : }
7189 : :
7190 : 251867 : bdev_nvme_io_complete_nvme_status(bio, cpl);
7191 : 251867 : }
7192 : :
7193 : : static void
7194 : 52 : bdev_nvme_comparev_done(void *ref, const struct spdk_nvme_cpl *cpl)
7195 : : {
7196 : 52 : struct nvme_bdev_io *bio = ref;
7197 : :
7198 [ + + + - : 52 : if (spdk_nvme_cpl_is_pi_error(cpl)) {
+ - - + ]
7199 : 0 : SPDK_ERRLOG("comparev completed with PI error (sct=%d, sc=%d)\n",
7200 : : cpl->status.sct, cpl->status.sc);
7201 : : /* Run PI verification for compare data buffer if PI error is detected. */
7202 : 0 : bdev_nvme_verify_pi_error(bio);
7203 : : }
7204 : :
7205 : 52 : bdev_nvme_io_complete_nvme_status(bio, cpl);
7206 : 52 : }
7207 : :
7208 : : static void
7209 : 96 : bdev_nvme_comparev_and_writev_done(void *ref, const struct spdk_nvme_cpl *cpl)
7210 : : {
7211 : 96 : struct nvme_bdev_io *bio = ref;
7212 : :
7213 : : /* Compare operation completion */
7214 [ + + + + ]: 96 : if (!bio->first_fused_completed) {
7215 : : /* Save compare result for write callback */
7216 : 48 : bio->cpl = *cpl;
7217 : 48 : bio->first_fused_completed = true;
7218 : 48 : return;
7219 : : }
7220 : :
7221 : : /* Write operation completion */
7222 [ + + - + ]: 48 : if (spdk_nvme_cpl_is_error(&bio->cpl)) {
7223 : : /* If bio->cpl is already an error, it means the compare operation failed. In that case,
7224 : : * complete the IO with the compare operation's status.
7225 : : */
7226 [ + + + - ]: 36 : if (!spdk_nvme_cpl_is_error(cpl)) {
7227 : 4 : SPDK_ERRLOG("Unexpected write success after compare failure.\n");
7228 : : }
7229 : :
7230 : 36 : bdev_nvme_io_complete_nvme_status(bio, &bio->cpl);
7231 : : } else {
7232 : 12 : bdev_nvme_io_complete_nvme_status(bio, cpl);
7233 : : }
7234 : : }
7235 : :
7236 : : static void
7237 : 916418 : bdev_nvme_queued_done(void *ref, const struct spdk_nvme_cpl *cpl)
7238 : : {
7239 : 916418 : struct nvme_bdev_io *bio = ref;
7240 : :
7241 : 916418 : bdev_nvme_io_complete_nvme_status(bio, cpl);
7242 : 916418 : }
7243 : :
7244 : : static int
7245 : 40 : fill_zone_from_report(struct spdk_bdev_zone_info *info, struct spdk_nvme_zns_zone_desc *desc)
7246 : : {
7247 [ + - ]: 40 : switch (desc->zt) {
7248 : 40 : case SPDK_NVME_ZONE_TYPE_SEQWR:
7249 : 40 : info->type = SPDK_BDEV_ZONE_TYPE_SEQWR;
7250 : 40 : break;
7251 : 0 : default:
7252 : 0 : SPDK_ERRLOG("Invalid zone type: %#x in zone report\n", desc->zt);
7253 : 0 : return -EIO;
7254 : : }
7255 : :
7256 [ + - - - : 40 : switch (desc->zs) {
- - - - ]
7257 : 40 : case SPDK_NVME_ZONE_STATE_EMPTY:
7258 : 40 : info->state = SPDK_BDEV_ZONE_STATE_EMPTY;
7259 : 40 : break;
7260 : 0 : case SPDK_NVME_ZONE_STATE_IOPEN:
7261 : 0 : info->state = SPDK_BDEV_ZONE_STATE_IMP_OPEN;
7262 : 0 : break;
7263 : 0 : case SPDK_NVME_ZONE_STATE_EOPEN:
7264 : 0 : info->state = SPDK_BDEV_ZONE_STATE_EXP_OPEN;
7265 : 0 : break;
7266 : 0 : case SPDK_NVME_ZONE_STATE_CLOSED:
7267 : 0 : info->state = SPDK_BDEV_ZONE_STATE_CLOSED;
7268 : 0 : break;
7269 : 0 : case SPDK_NVME_ZONE_STATE_RONLY:
7270 : 0 : info->state = SPDK_BDEV_ZONE_STATE_READ_ONLY;
7271 : 0 : break;
7272 : 0 : case SPDK_NVME_ZONE_STATE_FULL:
7273 : 0 : info->state = SPDK_BDEV_ZONE_STATE_FULL;
7274 : 0 : break;
7275 : 0 : case SPDK_NVME_ZONE_STATE_OFFLINE:
7276 : 0 : info->state = SPDK_BDEV_ZONE_STATE_OFFLINE;
7277 : 0 : break;
7278 : 0 : default:
7279 : 0 : SPDK_ERRLOG("Invalid zone state: %#x in zone report\n", desc->zs);
7280 : 0 : return -EIO;
7281 : : }
7282 : :
7283 : 40 : info->zone_id = desc->zslba;
7284 : 40 : info->write_pointer = desc->wp;
7285 : 40 : info->capacity = desc->zcap;
7286 : :
7287 : 40 : return 0;
7288 : : }
7289 : :
7290 : : static void
7291 : 1 : bdev_nvme_get_zone_info_done(void *ref, const struct spdk_nvme_cpl *cpl)
7292 : : {
7293 : 1 : struct nvme_bdev_io *bio = ref;
7294 : 1 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
7295 : 1 : uint64_t zone_id = bdev_io->u.zone_mgmt.zone_id;
7296 : 1 : uint32_t zones_to_copy = bdev_io->u.zone_mgmt.num_zones;
7297 : 1 : struct spdk_bdev_zone_info *info = bdev_io->u.zone_mgmt.buf;
7298 : : uint64_t max_zones_per_buf, i;
7299 : : uint32_t zone_report_bufsize;
7300 : : struct spdk_nvme_ns *ns;
7301 : : struct spdk_nvme_qpair *qpair;
7302 : : int ret;
7303 : :
7304 [ + - - + ]: 1 : if (spdk_nvme_cpl_is_error(cpl)) {
7305 : 0 : goto out_complete_io_nvme_cpl;
7306 : : }
7307 : :
7308 [ - + ]: 1 : if (spdk_unlikely(!nvme_io_path_is_available(bio->io_path))) {
7309 : 0 : ret = -ENXIO;
7310 : 0 : goto out_complete_io_ret;
7311 : : }
7312 : :
7313 : 1 : ns = bio->io_path->nvme_ns->ns;
7314 : 1 : qpair = bio->io_path->qpair->qpair;
7315 : :
7316 : 1 : zone_report_bufsize = spdk_nvme_ns_get_max_io_xfer_size(ns);
7317 : 1 : max_zones_per_buf = (zone_report_bufsize - sizeof(*bio->zone_report_buf)) /
7318 : : sizeof(bio->zone_report_buf->descs[0]);
7319 : :
7320 [ - + ]: 1 : if (bio->zone_report_buf->nr_zones > max_zones_per_buf) {
7321 : 0 : ret = -EINVAL;
7322 : 0 : goto out_complete_io_ret;
7323 : : }
7324 : :
7325 [ - + ]: 1 : if (!bio->zone_report_buf->nr_zones) {
7326 : 0 : ret = -EINVAL;
7327 : 0 : goto out_complete_io_ret;
7328 : : }
7329 : :
7330 [ + + + - ]: 41 : for (i = 0; i < bio->zone_report_buf->nr_zones && bio->handled_zones < zones_to_copy; i++) {
7331 : 40 : ret = fill_zone_from_report(&info[bio->handled_zones],
7332 : 40 : &bio->zone_report_buf->descs[i]);
7333 [ - + ]: 40 : if (ret) {
7334 : 0 : goto out_complete_io_ret;
7335 : : }
7336 : 40 : bio->handled_zones++;
7337 : : }
7338 : :
7339 [ - + ]: 1 : if (bio->handled_zones < zones_to_copy) {
7340 : 0 : uint64_t zone_size_lba = spdk_nvme_zns_ns_get_zone_size_sectors(ns);
7341 : 0 : uint64_t slba = zone_id + (zone_size_lba * bio->handled_zones);
7342 : :
7343 [ # # ]: 0 : memset(bio->zone_report_buf, 0, zone_report_bufsize);
7344 : 0 : ret = spdk_nvme_zns_report_zones(ns, qpair,
7345 : 0 : bio->zone_report_buf, zone_report_bufsize,
7346 : : slba, SPDK_NVME_ZRA_LIST_ALL, true,
7347 : : bdev_nvme_get_zone_info_done, bio);
7348 [ # # ]: 0 : if (!ret) {
7349 : 0 : return;
7350 : : } else {
7351 : 0 : goto out_complete_io_ret;
7352 : : }
7353 : : }
7354 : :
7355 : 1 : out_complete_io_nvme_cpl:
7356 : 1 : free(bio->zone_report_buf);
7357 : 1 : bio->zone_report_buf = NULL;
7358 : 1 : bdev_nvme_io_complete_nvme_status(bio, cpl);
7359 : 1 : return;
7360 : :
7361 : 0 : out_complete_io_ret:
7362 : 0 : free(bio->zone_report_buf);
7363 : 0 : bio->zone_report_buf = NULL;
7364 : 0 : bdev_nvme_io_complete(bio, ret);
7365 : : }
7366 : :
7367 : : static void
7368 : 43 : bdev_nvme_zone_management_done(void *ref, const struct spdk_nvme_cpl *cpl)
7369 : : {
7370 : 43 : struct nvme_bdev_io *bio = ref;
7371 : :
7372 : 43 : bdev_nvme_io_complete_nvme_status(bio, cpl);
7373 : 43 : }
7374 : :
7375 : : static void
7376 : 46 : bdev_nvme_admin_passthru_complete_nvme_status(void *ctx)
7377 : : {
7378 : 46 : struct nvme_bdev_io *bio = ctx;
7379 : 46 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
7380 : 46 : const struct spdk_nvme_cpl *cpl = &bio->cpl;
7381 : :
7382 [ - + ]: 46 : assert(bdev_nvme_io_type_is_admin(bdev_io->type));
7383 : :
7384 : 46 : __bdev_nvme_io_complete(bdev_io, 0, cpl);
7385 : 46 : }
7386 : :
7387 : : static void
7388 : 7142 : bdev_nvme_abort_complete(void *ctx)
7389 : : {
7390 : 7142 : struct nvme_bdev_io *bio = ctx;
7391 : 7142 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
7392 : :
7393 [ + - + - : 7142 : if (spdk_nvme_cpl_is_abort_success(&bio->cpl)) {
+ + ]
7394 : 12 : __bdev_nvme_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS, NULL);
7395 : : } else {
7396 : 7130 : __bdev_nvme_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED, NULL);
7397 : : }
7398 : 7142 : }
7399 : :
7400 : : static void
7401 : 7142 : bdev_nvme_abort_done(void *ref, const struct spdk_nvme_cpl *cpl)
7402 : : {
7403 : 7142 : struct nvme_bdev_io *bio = ref;
7404 : 7142 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
7405 : :
7406 : 7142 : bio->cpl = *cpl;
7407 : 7142 : spdk_thread_send_msg(spdk_bdev_io_get_thread(bdev_io), bdev_nvme_abort_complete, bio);
7408 : 7142 : }
7409 : :
7410 : : static void
7411 : 46 : bdev_nvme_admin_passthru_done(void *ref, const struct spdk_nvme_cpl *cpl)
7412 : : {
7413 : 46 : struct nvme_bdev_io *bio = ref;
7414 : 46 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
7415 : :
7416 : 46 : bio->cpl = *cpl;
7417 : 46 : spdk_thread_send_msg(spdk_bdev_io_get_thread(bdev_io),
7418 : : bdev_nvme_admin_passthru_complete_nvme_status, bio);
7419 : 46 : }
7420 : :
7421 : : static void
7422 : 5892812 : bdev_nvme_queued_reset_sgl(void *ref, uint32_t sgl_offset)
7423 : : {
7424 : 5892812 : struct nvme_bdev_io *bio = ref;
7425 : : struct iovec *iov;
7426 : :
7427 : 5892812 : bio->iov_offset = sgl_offset;
7428 [ + - ]: 9247909 : for (bio->iovpos = 0; bio->iovpos < bio->iovcnt; bio->iovpos++) {
7429 : 9247909 : iov = &bio->iovs[bio->iovpos];
7430 [ + + ]: 9247909 : if (bio->iov_offset < iov->iov_len) {
7431 : 5892812 : break;
7432 : : }
7433 : :
7434 : 3355097 : bio->iov_offset -= iov->iov_len;
7435 : : }
7436 : 5892812 : }
7437 : :
7438 : : static int
7439 : 21742539 : bdev_nvme_queued_next_sge(void *ref, void **address, uint32_t *length)
7440 : : {
7441 : 21742539 : struct nvme_bdev_io *bio = ref;
7442 : : struct iovec *iov;
7443 : :
7444 [ - + ]: 21742539 : assert(bio->iovpos < bio->iovcnt);
7445 : :
7446 : 21742539 : iov = &bio->iovs[bio->iovpos];
7447 : :
7448 : 21742539 : *address = iov->iov_base;
7449 : 21742539 : *length = iov->iov_len;
7450 : :
7451 [ + + ]: 21742539 : if (bio->iov_offset) {
7452 [ - + ]: 107740 : assert(bio->iov_offset <= iov->iov_len);
7453 : 107740 : *address += bio->iov_offset;
7454 : 107740 : *length -= bio->iov_offset;
7455 : : }
7456 : :
7457 : 21742539 : bio->iov_offset += *length;
7458 [ + - ]: 21742539 : if (bio->iov_offset == iov->iov_len) {
7459 : 21742539 : bio->iovpos++;
7460 : 21742539 : bio->iov_offset = 0;
7461 : : }
7462 : :
7463 : 21742539 : return 0;
7464 : : }
7465 : :
7466 : : static void
7467 : 80 : bdev_nvme_queued_reset_fused_sgl(void *ref, uint32_t sgl_offset)
7468 : : {
7469 : 80 : struct nvme_bdev_io *bio = ref;
7470 : : struct iovec *iov;
7471 : :
7472 : 80 : bio->fused_iov_offset = sgl_offset;
7473 [ + - ]: 80 : for (bio->fused_iovpos = 0; bio->fused_iovpos < bio->fused_iovcnt; bio->fused_iovpos++) {
7474 : 80 : iov = &bio->fused_iovs[bio->fused_iovpos];
7475 [ + - ]: 80 : if (bio->fused_iov_offset < iov->iov_len) {
7476 : 80 : break;
7477 : : }
7478 : :
7479 : 0 : bio->fused_iov_offset -= iov->iov_len;
7480 : : }
7481 : 80 : }
7482 : :
7483 : : static int
7484 : 80 : bdev_nvme_queued_next_fused_sge(void *ref, void **address, uint32_t *length)
7485 : : {
7486 : 80 : struct nvme_bdev_io *bio = ref;
7487 : : struct iovec *iov;
7488 : :
7489 [ - + ]: 80 : assert(bio->fused_iovpos < bio->fused_iovcnt);
7490 : :
7491 : 80 : iov = &bio->fused_iovs[bio->fused_iovpos];
7492 : :
7493 : 80 : *address = iov->iov_base;
7494 : 80 : *length = iov->iov_len;
7495 : :
7496 [ - + ]: 80 : if (bio->fused_iov_offset) {
7497 [ # # ]: 0 : assert(bio->fused_iov_offset <= iov->iov_len);
7498 : 0 : *address += bio->fused_iov_offset;
7499 : 0 : *length -= bio->fused_iov_offset;
7500 : : }
7501 : :
7502 : 80 : bio->fused_iov_offset += *length;
7503 [ + - ]: 80 : if (bio->fused_iov_offset == iov->iov_len) {
7504 : 80 : bio->fused_iovpos++;
7505 : 80 : bio->fused_iov_offset = 0;
7506 : : }
7507 : :
7508 : 80 : return 0;
7509 : : }
7510 : :
7511 : : static int
7512 : 0 : bdev_nvme_no_pi_readv(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
7513 : : void *md, uint64_t lba_count, uint64_t lba)
7514 : : {
7515 : : int rc;
7516 : :
7517 [ # # # # ]: 0 : SPDK_DEBUGLOG(bdev_nvme, "read %" PRIu64 " blocks with offset %#" PRIx64 " without PI check\n",
7518 : : lba_count, lba);
7519 : :
7520 : 0 : bio->iovs = iov;
7521 : 0 : bio->iovcnt = iovcnt;
7522 : 0 : bio->iovpos = 0;
7523 : 0 : bio->iov_offset = 0;
7524 : :
7525 : 0 : rc = spdk_nvme_ns_cmd_readv_with_md(bio->io_path->nvme_ns->ns,
7526 : 0 : bio->io_path->qpair->qpair,
7527 : : lba, lba_count,
7528 : : bdev_nvme_no_pi_readv_done, bio, 0,
7529 : : bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge,
7530 : : md, 0, 0);
7531 : :
7532 [ # # # # ]: 0 : if (rc != 0 && rc != -ENOMEM) {
7533 : 0 : SPDK_ERRLOG("no_pi_readv failed: rc = %d\n", rc);
7534 : : }
7535 : 0 : return rc;
7536 : : }
7537 : :
7538 : : static int
7539 : 18007886 : bdev_nvme_readv(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
7540 : : void *md, uint64_t lba_count, uint64_t lba, uint32_t flags,
7541 : : struct spdk_memory_domain *domain, void *domain_ctx,
7542 : : struct spdk_accel_sequence *seq)
7543 : : {
7544 : 18007886 : struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
7545 : 18007886 : struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
7546 : : int rc;
7547 : :
7548 [ - + + + ]: 18007886 : SPDK_DEBUGLOG(bdev_nvme, "read %" PRIu64 " blocks with offset %#" PRIx64 "\n",
7549 : : lba_count, lba);
7550 : :
7551 : 18007886 : bio->iovs = iov;
7552 : 18007886 : bio->iovcnt = iovcnt;
7553 : 18007886 : bio->iovpos = 0;
7554 : 18007886 : bio->iov_offset = 0;
7555 : :
7556 [ + + + + ]: 18007886 : if (domain != NULL || seq != NULL) {
7557 : 694266 : bio->ext_opts.size = SPDK_SIZEOF(&bio->ext_opts, accel_sequence);
7558 : 694266 : bio->ext_opts.memory_domain = domain;
7559 : 694266 : bio->ext_opts.memory_domain_ctx = domain_ctx;
7560 : 694266 : bio->ext_opts.io_flags = flags;
7561 : 694266 : bio->ext_opts.metadata = md;
7562 : 694266 : bio->ext_opts.accel_sequence = seq;
7563 : :
7564 : 694266 : rc = spdk_nvme_ns_cmd_readv_ext(ns, qpair, lba, lba_count,
7565 : : bdev_nvme_readv_done, bio,
7566 : : bdev_nvme_queued_reset_sgl,
7567 : : bdev_nvme_queued_next_sge,
7568 : : &bio->ext_opts);
7569 [ + + ]: 17313620 : } else if (iovcnt == 1) {
7570 : 16681475 : rc = spdk_nvme_ns_cmd_read_with_md(ns, qpair, iov[0].iov_base,
7571 : : md, lba, lba_count, bdev_nvme_readv_done,
7572 : : bio, flags, 0, 0);
7573 : : } else {
7574 : 632145 : rc = spdk_nvme_ns_cmd_readv_with_md(ns, qpair, lba, lba_count,
7575 : : bdev_nvme_readv_done, bio, flags,
7576 : : bdev_nvme_queued_reset_sgl,
7577 : : bdev_nvme_queued_next_sge, md, 0, 0);
7578 : : }
7579 : :
7580 [ + + - + ]: 18007886 : if (spdk_unlikely(rc != 0 && rc != -ENOMEM)) {
7581 : 0 : SPDK_ERRLOG("readv failed: rc = %d\n", rc);
7582 : : }
7583 : 18007886 : return rc;
7584 : : }
7585 : :
7586 : : static int
7587 : 16588748 : bdev_nvme_writev(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
7588 : : void *md, uint64_t lba_count, uint64_t lba, uint32_t flags,
7589 : : struct spdk_memory_domain *domain, void *domain_ctx,
7590 : : struct spdk_accel_sequence *seq)
7591 : : {
7592 : 16588748 : struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
7593 : 16588748 : struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
7594 : : int rc;
7595 : :
7596 [ - + - + ]: 16588748 : SPDK_DEBUGLOG(bdev_nvme, "write %" PRIu64 " blocks with offset %#" PRIx64 "\n",
7597 : : lba_count, lba);
7598 : :
7599 : 16588748 : bio->iovs = iov;
7600 : 16588748 : bio->iovcnt = iovcnt;
7601 : 16588748 : bio->iovpos = 0;
7602 : 16588748 : bio->iov_offset = 0;
7603 : :
7604 [ + + + + ]: 16588748 : if (domain != NULL || seq != NULL) {
7605 : 306231 : bio->ext_opts.size = SPDK_SIZEOF(&bio->ext_opts, accel_sequence);
7606 : 306231 : bio->ext_opts.memory_domain = domain;
7607 : 306231 : bio->ext_opts.memory_domain_ctx = domain_ctx;
7608 : 306231 : bio->ext_opts.io_flags = flags;
7609 : 306231 : bio->ext_opts.metadata = md;
7610 : 306231 : bio->ext_opts.accel_sequence = seq;
7611 : :
7612 : 306231 : rc = spdk_nvme_ns_cmd_writev_ext(ns, qpair, lba, lba_count,
7613 : : bdev_nvme_writev_done, bio,
7614 : : bdev_nvme_queued_reset_sgl,
7615 : : bdev_nvme_queued_next_sge,
7616 : : &bio->ext_opts);
7617 [ + + ]: 16282517 : } else if (iovcnt == 1) {
7618 : 15397621 : rc = spdk_nvme_ns_cmd_write_with_md(ns, qpair, iov[0].iov_base,
7619 : : md, lba, lba_count, bdev_nvme_writev_done,
7620 : : bio, flags, 0, 0);
7621 : : } else {
7622 : 884896 : rc = spdk_nvme_ns_cmd_writev_with_md(ns, qpair, lba, lba_count,
7623 : : bdev_nvme_writev_done, bio, flags,
7624 : : bdev_nvme_queued_reset_sgl,
7625 : : bdev_nvme_queued_next_sge, md, 0, 0);
7626 : : }
7627 : :
7628 [ + + - + ]: 16588748 : if (spdk_unlikely(rc != 0 && rc != -ENOMEM)) {
7629 : 0 : SPDK_ERRLOG("writev failed: rc = %d\n", rc);
7630 : : }
7631 : 16588748 : return rc;
7632 : : }
7633 : :
7634 : : static int
7635 : 251867 : bdev_nvme_zone_appendv(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
7636 : : void *md, uint64_t lba_count, uint64_t zslba,
7637 : : uint32_t flags)
7638 : : {
7639 : 251867 : struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
7640 : 251867 : struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
7641 : : int rc;
7642 : :
7643 [ - + # # ]: 251867 : SPDK_DEBUGLOG(bdev_nvme, "zone append %" PRIu64 " blocks to zone start lba %#" PRIx64 "\n",
7644 : : lba_count, zslba);
7645 : :
7646 : 251867 : bio->iovs = iov;
7647 : 251867 : bio->iovcnt = iovcnt;
7648 : 251867 : bio->iovpos = 0;
7649 : 251867 : bio->iov_offset = 0;
7650 : :
7651 [ + - ]: 251867 : if (iovcnt == 1) {
7652 : 251867 : rc = spdk_nvme_zns_zone_append_with_md(ns, qpair, iov[0].iov_base, md, zslba,
7653 : : lba_count,
7654 : : bdev_nvme_zone_appendv_done, bio,
7655 : : flags,
7656 : : 0, 0);
7657 : : } else {
7658 : 0 : rc = spdk_nvme_zns_zone_appendv_with_md(ns, qpair, zslba, lba_count,
7659 : : bdev_nvme_zone_appendv_done, bio, flags,
7660 : : bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge,
7661 : : md, 0, 0);
7662 : : }
7663 : :
7664 [ - + - - ]: 251867 : if (rc != 0 && rc != -ENOMEM) {
7665 : 0 : SPDK_ERRLOG("zone append failed: rc = %d\n", rc);
7666 : : }
7667 : 251867 : return rc;
7668 : : }
7669 : :
7670 : : static int
7671 : 52 : bdev_nvme_comparev(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
7672 : : void *md, uint64_t lba_count, uint64_t lba,
7673 : : uint32_t flags)
7674 : : {
7675 : : int rc;
7676 : :
7677 [ - + - + ]: 52 : SPDK_DEBUGLOG(bdev_nvme, "compare %" PRIu64 " blocks with offset %#" PRIx64 "\n",
7678 : : lba_count, lba);
7679 : :
7680 : 52 : bio->iovs = iov;
7681 : 52 : bio->iovcnt = iovcnt;
7682 : 52 : bio->iovpos = 0;
7683 : 52 : bio->iov_offset = 0;
7684 : :
7685 : 52 : rc = spdk_nvme_ns_cmd_comparev_with_md(bio->io_path->nvme_ns->ns,
7686 : 52 : bio->io_path->qpair->qpair,
7687 : : lba, lba_count,
7688 : : bdev_nvme_comparev_done, bio, flags,
7689 : : bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge,
7690 : : md, 0, 0);
7691 : :
7692 [ - + - - ]: 52 : if (rc != 0 && rc != -ENOMEM) {
7693 : 0 : SPDK_ERRLOG("comparev failed: rc = %d\n", rc);
7694 : : }
7695 : 52 : return rc;
7696 : : }
7697 : :
7698 : : static int
7699 : 48 : bdev_nvme_comparev_and_writev(struct nvme_bdev_io *bio, struct iovec *cmp_iov, int cmp_iovcnt,
7700 : : struct iovec *write_iov, int write_iovcnt,
7701 : : void *md, uint64_t lba_count, uint64_t lba, uint32_t flags)
7702 : : {
7703 : 48 : struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
7704 : 48 : struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
7705 : 48 : struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
7706 : : int rc;
7707 : :
7708 [ - + - + ]: 48 : SPDK_DEBUGLOG(bdev_nvme, "compare and write %" PRIu64 " blocks with offset %#" PRIx64 "\n",
7709 : : lba_count, lba);
7710 : :
7711 : 48 : bio->iovs = cmp_iov;
7712 : 48 : bio->iovcnt = cmp_iovcnt;
7713 : 48 : bio->iovpos = 0;
7714 : 48 : bio->iov_offset = 0;
7715 : 48 : bio->fused_iovs = write_iov;
7716 : 48 : bio->fused_iovcnt = write_iovcnt;
7717 : 48 : bio->fused_iovpos = 0;
7718 : 48 : bio->fused_iov_offset = 0;
7719 : :
7720 [ + - ]: 48 : if (bdev_io->num_retries == 0) {
7721 : 48 : bio->first_fused_submitted = false;
7722 : 48 : bio->first_fused_completed = false;
7723 : : }
7724 : :
7725 [ + + + - ]: 48 : if (!bio->first_fused_submitted) {
7726 : 48 : flags |= SPDK_NVME_IO_FLAGS_FUSE_FIRST;
7727 [ - + ]: 48 : memset(&bio->cpl, 0, sizeof(bio->cpl));
7728 : :
7729 : 48 : rc = spdk_nvme_ns_cmd_comparev_with_md(ns, qpair, lba, lba_count,
7730 : : bdev_nvme_comparev_and_writev_done, bio, flags,
7731 : : bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge, md, 0, 0);
7732 [ + - ]: 48 : if (rc == 0) {
7733 : 48 : bio->first_fused_submitted = true;
7734 : 48 : flags &= ~SPDK_NVME_IO_FLAGS_FUSE_FIRST;
7735 : : } else {
7736 [ # # ]: 0 : if (rc != -ENOMEM) {
7737 : 0 : SPDK_ERRLOG("compare failed: rc = %d\n", rc);
7738 : : }
7739 : 0 : return rc;
7740 : : }
7741 : : }
7742 : :
7743 : 48 : flags |= SPDK_NVME_IO_FLAGS_FUSE_SECOND;
7744 : :
7745 : 48 : rc = spdk_nvme_ns_cmd_writev_with_md(ns, qpair, lba, lba_count,
7746 : : bdev_nvme_comparev_and_writev_done, bio, flags,
7747 : : bdev_nvme_queued_reset_fused_sgl, bdev_nvme_queued_next_fused_sge, md, 0, 0);
7748 [ - + - - ]: 48 : if (rc != 0 && rc != -ENOMEM) {
7749 : 0 : SPDK_ERRLOG("write failed: rc = %d\n", rc);
7750 : 0 : rc = 0;
7751 : : }
7752 : :
7753 : 48 : return rc;
7754 : : }
7755 : :
7756 : : static int
7757 : 269290 : bdev_nvme_unmap(struct nvme_bdev_io *bio, uint64_t offset_blocks, uint64_t num_blocks)
7758 : : {
7759 : 172455 : struct spdk_nvme_dsm_range dsm_ranges[SPDK_NVME_DATASET_MANAGEMENT_MAX_RANGES];
7760 : : struct spdk_nvme_dsm_range *range;
7761 : : uint64_t offset, remaining;
7762 : : uint64_t num_ranges_u64;
7763 : : uint16_t num_ranges;
7764 : : int rc;
7765 : :
7766 : 269290 : num_ranges_u64 = (num_blocks + SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS - 1) /
7767 : : SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS;
7768 [ - + ]: 269290 : if (num_ranges_u64 > SPDK_COUNTOF(dsm_ranges)) {
7769 : 0 : SPDK_ERRLOG("Unmap request for %" PRIu64 " blocks is too large\n", num_blocks);
7770 : 0 : return -EINVAL;
7771 : : }
7772 : 269290 : num_ranges = (uint16_t)num_ranges_u64;
7773 : :
7774 : 269290 : offset = offset_blocks;
7775 : 269290 : remaining = num_blocks;
7776 : 269290 : range = &dsm_ranges[0];
7777 : :
7778 : : /* Fill max-size ranges until the remaining blocks fit into one range */
7779 [ - + ]: 269290 : while (remaining > SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS) {
7780 : 0 : range->attributes.raw = 0;
7781 : 0 : range->length = SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS;
7782 : 0 : range->starting_lba = offset;
7783 : :
7784 : 0 : offset += SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS;
7785 : 0 : remaining -= SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS;
7786 : 0 : range++;
7787 : : }
7788 : :
7789 : : /* Final range describes the remaining blocks */
7790 : 269290 : range->attributes.raw = 0;
7791 : 269290 : range->length = remaining;
7792 : 269290 : range->starting_lba = offset;
7793 : :
7794 : 269290 : rc = spdk_nvme_ns_cmd_dataset_management(bio->io_path->nvme_ns->ns,
7795 : 269290 : bio->io_path->qpair->qpair,
7796 : : SPDK_NVME_DSM_ATTR_DEALLOCATE,
7797 : : dsm_ranges, num_ranges,
7798 : : bdev_nvme_queued_done, bio);
7799 : :
7800 : 269290 : return rc;
7801 : : }
7802 : :
7803 : : static int
7804 : 651178 : bdev_nvme_write_zeroes(struct nvme_bdev_io *bio, uint64_t offset_blocks, uint64_t num_blocks)
7805 : : {
7806 [ - + ]: 651178 : if (num_blocks > UINT16_MAX + 1) {
7807 : 0 : SPDK_ERRLOG("NVMe write zeroes is limited to 16-bit block count\n");
7808 : 0 : return -EINVAL;
7809 : : }
7810 : :
7811 : 651178 : return spdk_nvme_ns_cmd_write_zeroes(bio->io_path->nvme_ns->ns,
7812 : 651178 : bio->io_path->qpair->qpair,
7813 : : offset_blocks, num_blocks,
7814 : : bdev_nvme_queued_done, bio,
7815 : : 0);
7816 : : }
7817 : :
7818 : : static int
7819 : 1 : bdev_nvme_get_zone_info(struct nvme_bdev_io *bio, uint64_t zone_id, uint32_t num_zones,
7820 : : struct spdk_bdev_zone_info *info)
7821 : : {
7822 : 1 : struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
7823 : 1 : struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
7824 : 1 : uint32_t zone_report_bufsize = spdk_nvme_ns_get_max_io_xfer_size(ns);
7825 : 1 : uint64_t zone_size = spdk_nvme_zns_ns_get_zone_size_sectors(ns);
7826 : 1 : uint64_t total_zones = spdk_nvme_zns_ns_get_num_zones(ns);
7827 : :
7828 [ - + # # ]: 1 : if (zone_id % zone_size != 0) {
7829 : 0 : return -EINVAL;
7830 : : }
7831 : :
7832 [ + - - + ]: 1 : if (num_zones > total_zones || !num_zones) {
7833 : 0 : return -EINVAL;
7834 : : }
7835 : :
7836 [ - + ]: 1 : assert(!bio->zone_report_buf);
7837 : 1 : bio->zone_report_buf = calloc(1, zone_report_bufsize);
7838 [ - + ]: 1 : if (!bio->zone_report_buf) {
7839 : 0 : return -ENOMEM;
7840 : : }
7841 : :
7842 : 1 : bio->handled_zones = 0;
7843 : :
7844 : 1 : return spdk_nvme_zns_report_zones(ns, qpair, bio->zone_report_buf, zone_report_bufsize,
7845 : : zone_id, SPDK_NVME_ZRA_LIST_ALL, true,
7846 : : bdev_nvme_get_zone_info_done, bio);
7847 : : }
7848 : :
7849 : : static int
7850 : 43 : bdev_nvme_zone_management(struct nvme_bdev_io *bio, uint64_t zone_id,
7851 : : enum spdk_bdev_zone_action action)
7852 : : {
7853 : 43 : struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
7854 : 43 : struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
7855 : :
7856 [ - - - + : 43 : switch (action) {
- - ]
7857 : 0 : case SPDK_BDEV_ZONE_CLOSE:
7858 : 0 : return spdk_nvme_zns_close_zone(ns, qpair, zone_id, false,
7859 : : bdev_nvme_zone_management_done, bio);
7860 : 0 : case SPDK_BDEV_ZONE_FINISH:
7861 : 0 : return spdk_nvme_zns_finish_zone(ns, qpair, zone_id, false,
7862 : : bdev_nvme_zone_management_done, bio);
7863 : 0 : case SPDK_BDEV_ZONE_OPEN:
7864 : 0 : return spdk_nvme_zns_open_zone(ns, qpair, zone_id, false,
7865 : : bdev_nvme_zone_management_done, bio);
7866 : 43 : case SPDK_BDEV_ZONE_RESET:
7867 : 43 : return spdk_nvme_zns_reset_zone(ns, qpair, zone_id, false,
7868 : : bdev_nvme_zone_management_done, bio);
7869 : 0 : case SPDK_BDEV_ZONE_OFFLINE:
7870 : 0 : return spdk_nvme_zns_offline_zone(ns, qpair, zone_id, false,
7871 : : bdev_nvme_zone_management_done, bio);
7872 : 0 : default:
7873 : 0 : return -EINVAL;
7874 : : }
7875 : : }
7876 : :
7877 : : static void
7878 : 50 : bdev_nvme_admin_passthru(struct nvme_bdev_channel *nbdev_ch, struct nvme_bdev_io *bio,
7879 : : struct spdk_nvme_cmd *cmd, void *buf, size_t nbytes)
7880 : : {
7881 : : struct nvme_io_path *io_path;
7882 : : struct nvme_ctrlr *nvme_ctrlr;
7883 : : uint32_t max_xfer_size;
7884 : 50 : int rc = -ENXIO;
7885 : :
7886 : : /* Choose the first ctrlr which is not failed. */
7887 [ + + ]: 62 : STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
7888 : 58 : nvme_ctrlr = io_path->qpair->ctrlr;
7889 : :
7890 : : /* We should skip any unavailable nvme_ctrlr rather than checking
7891 : : * if the return value of spdk_nvme_ctrlr_cmd_admin_raw() is -ENXIO.
7892 : : */
7893 [ + + ]: 58 : if (!nvme_ctrlr_is_available(nvme_ctrlr)) {
7894 : 12 : continue;
7895 : : }
7896 : :
7897 : 46 : max_xfer_size = spdk_nvme_ctrlr_get_max_xfer_size(nvme_ctrlr->ctrlr);
7898 : :
7899 [ - + ]: 46 : if (nbytes > max_xfer_size) {
7900 : 0 : SPDK_ERRLOG("nbytes is greater than MDTS %" PRIu32 ".\n", max_xfer_size);
7901 : 0 : rc = -EINVAL;
7902 : 0 : goto err;
7903 : : }
7904 : :
7905 : 46 : rc = spdk_nvme_ctrlr_cmd_admin_raw(nvme_ctrlr->ctrlr, cmd, buf, (uint32_t)nbytes,
7906 : : bdev_nvme_admin_passthru_done, bio);
7907 [ + - ]: 46 : if (rc == 0) {
7908 : 46 : return;
7909 : : }
7910 : : }
7911 : :
7912 : 4 : err:
7913 : 4 : bdev_nvme_admin_complete(bio, rc);
7914 : : }
7915 : :
7916 : : static int
7917 : 102 : bdev_nvme_io_passthru(struct nvme_bdev_io *bio, struct spdk_nvme_cmd *cmd,
7918 : : void *buf, size_t nbytes)
7919 : : {
7920 : 102 : struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
7921 : 102 : struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
7922 : 102 : uint32_t max_xfer_size = spdk_nvme_ns_get_max_io_xfer_size(ns);
7923 : 102 : struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
7924 : :
7925 [ - + ]: 102 : if (nbytes > max_xfer_size) {
7926 : 0 : SPDK_ERRLOG("nbytes is greater than MDTS %" PRIu32 ".\n", max_xfer_size);
7927 : 0 : return -EINVAL;
7928 : : }
7929 : :
7930 : : /*
7931 : : * Each NVMe bdev is a specific namespace, and all NVMe I/O commands require a nsid,
7932 : : * so fill it out automatically.
7933 : : */
7934 : 102 : cmd->nsid = spdk_nvme_ns_get_id(ns);
7935 : :
7936 : 102 : return spdk_nvme_ctrlr_cmd_io_raw(ctrlr, qpair, cmd, buf,
7937 : : (uint32_t)nbytes, bdev_nvme_queued_done, bio);
7938 : : }
7939 : :
7940 : : static int
7941 : 0 : bdev_nvme_io_passthru_md(struct nvme_bdev_io *bio, struct spdk_nvme_cmd *cmd,
7942 : : void *buf, size_t nbytes, void *md_buf, size_t md_len)
7943 : : {
7944 : 0 : struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
7945 : 0 : struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
7946 [ # # ]: 0 : size_t nr_sectors = nbytes / spdk_nvme_ns_get_extended_sector_size(ns);
7947 : 0 : uint32_t max_xfer_size = spdk_nvme_ns_get_max_io_xfer_size(ns);
7948 : 0 : struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
7949 : :
7950 [ # # ]: 0 : if (nbytes > max_xfer_size) {
7951 : 0 : SPDK_ERRLOG("nbytes is greater than MDTS %" PRIu32 ".\n", max_xfer_size);
7952 : 0 : return -EINVAL;
7953 : : }
7954 : :
7955 [ # # ]: 0 : if (md_len != nr_sectors * spdk_nvme_ns_get_md_size(ns)) {
7956 : 0 : SPDK_ERRLOG("invalid meta data buffer size\n");
7957 : 0 : return -EINVAL;
7958 : : }
7959 : :
7960 : : /*
7961 : : * Each NVMe bdev is a specific namespace, and all NVMe I/O commands require a nsid,
7962 : : * so fill it out automatically.
7963 : : */
7964 : 0 : cmd->nsid = spdk_nvme_ns_get_id(ns);
7965 : :
7966 : 0 : return spdk_nvme_ctrlr_cmd_io_raw_with_md(ctrlr, qpair, cmd, buf,
7967 : : (uint32_t)nbytes, md_buf, bdev_nvme_queued_done, bio);
7968 : : }
7969 : :
7970 : : static int
7971 : 0 : bdev_nvme_iov_passthru_md(struct nvme_bdev_io *bio,
7972 : : struct spdk_nvme_cmd *cmd, struct iovec *iov, int iovcnt,
7973 : : size_t nbytes, void *md_buf, size_t md_len)
7974 : : {
7975 : 0 : struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
7976 : 0 : struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
7977 [ # # ]: 0 : size_t nr_sectors = nbytes / spdk_nvme_ns_get_extended_sector_size(ns);
7978 : 0 : uint32_t max_xfer_size = spdk_nvme_ns_get_max_io_xfer_size(ns);
7979 : 0 : struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
7980 : :
7981 : 0 : bio->iovs = iov;
7982 : 0 : bio->iovcnt = iovcnt;
7983 : 0 : bio->iovpos = 0;
7984 : 0 : bio->iov_offset = 0;
7985 : :
7986 [ # # ]: 0 : if (nbytes > max_xfer_size) {
7987 : 0 : SPDK_ERRLOG("nbytes is greater than MDTS %" PRIu32 ".\n", max_xfer_size);
7988 : 0 : return -EINVAL;
7989 : : }
7990 : :
7991 [ # # ]: 0 : if (md_len != nr_sectors * spdk_nvme_ns_get_md_size(ns)) {
7992 : 0 : SPDK_ERRLOG("invalid meta data buffer size\n");
7993 : 0 : return -EINVAL;
7994 : : }
7995 : :
7996 : : /*
7997 : : * Each NVMe bdev is a specific namespace, and all NVMe I/O commands
7998 : : * require a nsid, so fill it out automatically.
7999 : : */
8000 : 0 : cmd->nsid = spdk_nvme_ns_get_id(ns);
8001 : :
8002 : 0 : return spdk_nvme_ctrlr_cmd_iov_raw_with_md(
8003 : : ctrlr, qpair, cmd, (uint32_t)nbytes, md_buf, bdev_nvme_queued_done, bio,
8004 : : bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge);
8005 : : }
8006 : :
8007 : : static void
8008 : 7154 : bdev_nvme_abort(struct nvme_bdev_channel *nbdev_ch, struct nvme_bdev_io *bio,
8009 : : struct nvme_bdev_io *bio_to_abort)
8010 : : {
8011 : : struct nvme_io_path *io_path;
8012 : 7154 : int rc = 0;
8013 : :
8014 : 7154 : rc = bdev_nvme_abort_retry_io(nbdev_ch, bio_to_abort);
8015 [ + + ]: 7154 : if (rc == 0) {
8016 : 4 : bdev_nvme_admin_complete(bio, 0);
8017 : 4 : return;
8018 : : }
8019 : :
8020 : 7150 : io_path = bio_to_abort->io_path;
8021 [ + + ]: 7150 : if (io_path != NULL) {
8022 : 7142 : rc = spdk_nvme_ctrlr_cmd_abort_ext(io_path->qpair->ctrlr->ctrlr,
8023 : 7142 : io_path->qpair->qpair,
8024 : : bio_to_abort,
8025 : : bdev_nvme_abort_done, bio);
8026 : : } else {
8027 [ + + ]: 12 : STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
8028 : 8 : rc = spdk_nvme_ctrlr_cmd_abort_ext(io_path->qpair->ctrlr->ctrlr,
8029 : : NULL,
8030 : : bio_to_abort,
8031 : : bdev_nvme_abort_done, bio);
8032 : :
8033 [ + + ]: 8 : if (rc != -ENOENT) {
8034 : 4 : break;
8035 : : }
8036 : : }
8037 : : }
8038 : :
8039 [ + + ]: 7150 : if (rc != 0) {
8040 : : /* If no command was found or there was any error, complete the abort
8041 : : * request with failure.
8042 : : */
8043 : 8 : bdev_nvme_admin_complete(bio, rc);
8044 : : }
8045 : : }
8046 : :
8047 : : static int
8048 : 35 : bdev_nvme_copy(struct nvme_bdev_io *bio, uint64_t dst_offset_blocks, uint64_t src_offset_blocks,
8049 : : uint64_t num_blocks)
8050 : : {
8051 : 35 : struct spdk_nvme_scc_source_range range = {
8052 : : .slba = src_offset_blocks,
8053 : 35 : .nlb = num_blocks - 1
8054 : : };
8055 : :
8056 : 43 : return spdk_nvme_ns_cmd_copy(bio->io_path->nvme_ns->ns,
8057 : 35 : bio->io_path->qpair->qpair,
8058 : : &range, 1, dst_offset_blocks,
8059 : : bdev_nvme_queued_done, bio);
8060 : : }
8061 : :
8062 : : static void
8063 : 143 : bdev_nvme_opts_config_json(struct spdk_json_write_ctx *w)
8064 : : {
8065 : : const char *action;
8066 : :
8067 [ - + ]: 143 : if (g_opts.action_on_timeout == SPDK_BDEV_NVME_TIMEOUT_ACTION_RESET) {
8068 : 0 : action = "reset";
8069 [ + + ]: 143 : } else if (g_opts.action_on_timeout == SPDK_BDEV_NVME_TIMEOUT_ACTION_ABORT) {
8070 : 6 : action = "abort";
8071 : : } else {
8072 : 137 : action = "none";
8073 : : }
8074 : :
8075 : 143 : spdk_json_write_object_begin(w);
8076 : :
8077 : 143 : spdk_json_write_named_string(w, "method", "bdev_nvme_set_options");
8078 : :
8079 : 143 : spdk_json_write_named_object_begin(w, "params");
8080 : 143 : spdk_json_write_named_string(w, "action_on_timeout", action);
8081 : 143 : spdk_json_write_named_uint64(w, "timeout_us", g_opts.timeout_us);
8082 : 143 : spdk_json_write_named_uint64(w, "timeout_admin_us", g_opts.timeout_admin_us);
8083 : 143 : spdk_json_write_named_uint32(w, "keep_alive_timeout_ms", g_opts.keep_alive_timeout_ms);
8084 : 143 : spdk_json_write_named_uint32(w, "transport_retry_count", g_opts.transport_retry_count);
8085 : 143 : spdk_json_write_named_uint32(w, "arbitration_burst", g_opts.arbitration_burst);
8086 : 143 : spdk_json_write_named_uint32(w, "low_priority_weight", g_opts.low_priority_weight);
8087 : 143 : spdk_json_write_named_uint32(w, "medium_priority_weight", g_opts.medium_priority_weight);
8088 : 143 : spdk_json_write_named_uint32(w, "high_priority_weight", g_opts.high_priority_weight);
8089 : 143 : spdk_json_write_named_uint64(w, "nvme_adminq_poll_period_us", g_opts.nvme_adminq_poll_period_us);
8090 : 143 : spdk_json_write_named_uint64(w, "nvme_ioq_poll_period_us", g_opts.nvme_ioq_poll_period_us);
8091 : 143 : spdk_json_write_named_uint32(w, "io_queue_requests", g_opts.io_queue_requests);
8092 [ - + ]: 143 : spdk_json_write_named_bool(w, "delay_cmd_submit", g_opts.delay_cmd_submit);
8093 : 143 : spdk_json_write_named_int32(w, "bdev_retry_count", g_opts.bdev_retry_count);
8094 : 143 : spdk_json_write_named_uint8(w, "transport_ack_timeout", g_opts.transport_ack_timeout);
8095 : 143 : spdk_json_write_named_int32(w, "ctrlr_loss_timeout_sec", g_opts.ctrlr_loss_timeout_sec);
8096 : 143 : spdk_json_write_named_uint32(w, "reconnect_delay_sec", g_opts.reconnect_delay_sec);
8097 : 143 : spdk_json_write_named_uint32(w, "fast_io_fail_timeout_sec", g_opts.fast_io_fail_timeout_sec);
8098 [ - + ]: 143 : spdk_json_write_named_bool(w, "generate_uuids", g_opts.generate_uuids);
8099 : 143 : spdk_json_write_named_uint8(w, "transport_tos", g_opts.transport_tos);
8100 [ - + ]: 143 : spdk_json_write_named_bool(w, "io_path_stat", g_opts.io_path_stat);
8101 [ - + ]: 143 : spdk_json_write_named_bool(w, "allow_accel_sequence", g_opts.allow_accel_sequence);
8102 : 143 : spdk_json_write_object_end(w);
8103 : :
8104 : 143 : spdk_json_write_object_end(w);
8105 : 143 : }
8106 : :
8107 : : static void
8108 : 0 : bdev_nvme_discovery_config_json(struct spdk_json_write_ctx *w, struct discovery_ctx *ctx)
8109 : : {
8110 : 0 : struct spdk_nvme_transport_id trid;
8111 : :
8112 : 0 : spdk_json_write_object_begin(w);
8113 : :
8114 : 0 : spdk_json_write_named_string(w, "method", "bdev_nvme_start_discovery");
8115 : :
8116 : 0 : spdk_json_write_named_object_begin(w, "params");
8117 : 0 : spdk_json_write_named_string(w, "name", ctx->name);
8118 : 0 : spdk_json_write_named_string(w, "hostnqn", ctx->hostnqn);
8119 : :
8120 : 0 : trid = ctx->trid;
8121 [ # # ]: 0 : memset(trid.subnqn, 0, sizeof(trid.subnqn));
8122 : 0 : nvme_bdev_dump_trid_json(&trid, w);
8123 : :
8124 [ # # ]: 0 : spdk_json_write_named_bool(w, "wait_for_attach", ctx->wait_for_attach);
8125 : 0 : spdk_json_write_named_int32(w, "ctrlr_loss_timeout_sec", ctx->bdev_opts.ctrlr_loss_timeout_sec);
8126 : 0 : spdk_json_write_named_uint32(w, "reconnect_delay_sec", ctx->bdev_opts.reconnect_delay_sec);
8127 : 0 : spdk_json_write_named_uint32(w, "fast_io_fail_timeout_sec",
8128 : : ctx->bdev_opts.fast_io_fail_timeout_sec);
8129 : 0 : spdk_json_write_object_end(w);
8130 : :
8131 : 0 : spdk_json_write_object_end(w);
8132 : 0 : }
8133 : :
8134 : : #ifdef SPDK_CONFIG_NVME_CUSE
8135 : : static void
8136 : 119 : nvme_ctrlr_cuse_config_json(struct spdk_json_write_ctx *w,
8137 : : struct nvme_ctrlr *nvme_ctrlr)
8138 : 119 : {
8139 : 119 : size_t cuse_name_size = 128;
8140 [ - + ]: 119 : char cuse_name[cuse_name_size];
8141 : :
8142 [ + - ]: 119 : if (spdk_nvme_cuse_get_ctrlr_name(nvme_ctrlr->ctrlr,
8143 : : cuse_name, &cuse_name_size) != 0) {
8144 : 119 : return;
8145 : : }
8146 : :
8147 : 0 : spdk_json_write_object_begin(w);
8148 : :
8149 : 0 : spdk_json_write_named_string(w, "method", "bdev_nvme_cuse_register");
8150 : :
8151 : 0 : spdk_json_write_named_object_begin(w, "params");
8152 : 0 : spdk_json_write_named_string(w, "name", nvme_ctrlr->nbdev_ctrlr->name);
8153 : 0 : spdk_json_write_object_end(w);
8154 : :
8155 : 0 : spdk_json_write_object_end(w);
8156 : : }
8157 : : #endif
8158 : :
8159 : : static void
8160 : 119 : nvme_ctrlr_config_json(struct spdk_json_write_ctx *w,
8161 : : struct nvme_ctrlr *nvme_ctrlr)
8162 : : {
8163 : : struct spdk_nvme_transport_id *trid;
8164 : : const struct spdk_nvme_ctrlr_opts *opts;
8165 : :
8166 [ - + - + ]: 119 : if (nvme_ctrlr->opts.from_discovery_service) {
8167 : : /* Do not emit an RPC for this - it will be implicitly
8168 : : * covered by a separate bdev_nvme_start_discovery or
8169 : : * bdev_nvme_start_mdns_discovery RPC.
8170 : : */
8171 : 0 : return;
8172 : : }
8173 : :
8174 : 119 : trid = &nvme_ctrlr->active_path_id->trid;
8175 : :
8176 : 119 : spdk_json_write_object_begin(w);
8177 : :
8178 : 119 : spdk_json_write_named_string(w, "method", "bdev_nvme_attach_controller");
8179 : :
8180 : 119 : spdk_json_write_named_object_begin(w, "params");
8181 : 119 : spdk_json_write_named_string(w, "name", nvme_ctrlr->nbdev_ctrlr->name);
8182 : 119 : nvme_bdev_dump_trid_json(trid, w);
8183 : 119 : spdk_json_write_named_bool(w, "prchk_reftag",
8184 : 119 : (nvme_ctrlr->opts.prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_REFTAG) != 0);
8185 : 119 : spdk_json_write_named_bool(w, "prchk_guard",
8186 : 119 : (nvme_ctrlr->opts.prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_GUARD) != 0);
8187 : 119 : spdk_json_write_named_int32(w, "ctrlr_loss_timeout_sec", nvme_ctrlr->opts.ctrlr_loss_timeout_sec);
8188 : 119 : spdk_json_write_named_uint32(w, "reconnect_delay_sec", nvme_ctrlr->opts.reconnect_delay_sec);
8189 : 119 : spdk_json_write_named_uint32(w, "fast_io_fail_timeout_sec",
8190 : : nvme_ctrlr->opts.fast_io_fail_timeout_sec);
8191 [ + + ]: 119 : if (nvme_ctrlr->opts.psk_path[0] != '\0') {
8192 : 3 : spdk_json_write_named_string(w, "psk", nvme_ctrlr->opts.psk_path);
8193 : : }
8194 : :
8195 : 119 : opts = spdk_nvme_ctrlr_get_opts(nvme_ctrlr->ctrlr);
8196 : 119 : spdk_json_write_named_string(w, "hostnqn", opts->hostnqn);
8197 [ - + ]: 119 : spdk_json_write_named_bool(w, "hdgst", opts->header_digest);
8198 [ - + ]: 119 : spdk_json_write_named_bool(w, "ddgst", opts->data_digest);
8199 : :
8200 : 119 : spdk_json_write_object_end(w);
8201 : :
8202 : 119 : spdk_json_write_object_end(w);
8203 : : }
8204 : :
8205 : : static void
8206 : 143 : bdev_nvme_hotplug_config_json(struct spdk_json_write_ctx *w)
8207 : : {
8208 : 143 : spdk_json_write_object_begin(w);
8209 : 143 : spdk_json_write_named_string(w, "method", "bdev_nvme_set_hotplug");
8210 : :
8211 : 143 : spdk_json_write_named_object_begin(w, "params");
8212 : 143 : spdk_json_write_named_uint64(w, "period_us", g_nvme_hotplug_poll_period_us);
8213 [ - + ]: 143 : spdk_json_write_named_bool(w, "enable", g_nvme_hotplug_enabled);
8214 : 143 : spdk_json_write_object_end(w);
8215 : :
8216 : 143 : spdk_json_write_object_end(w);
8217 : 143 : }
8218 : :
8219 : : static int
8220 : 143 : bdev_nvme_config_json(struct spdk_json_write_ctx *w)
8221 : : {
8222 : : struct nvme_bdev_ctrlr *nbdev_ctrlr;
8223 : : struct nvme_ctrlr *nvme_ctrlr;
8224 : : struct discovery_ctx *ctx;
8225 : :
8226 : 143 : bdev_nvme_opts_config_json(w);
8227 : :
8228 [ - + ]: 143 : pthread_mutex_lock(&g_bdev_nvme_mutex);
8229 : :
8230 [ + + ]: 262 : TAILQ_FOREACH(nbdev_ctrlr, &g_nvme_bdev_ctrlrs, tailq) {
8231 [ + + ]: 238 : TAILQ_FOREACH(nvme_ctrlr, &nbdev_ctrlr->ctrlrs, tailq) {
8232 : 119 : nvme_ctrlr_config_json(w, nvme_ctrlr);
8233 : :
8234 : : #ifdef SPDK_CONFIG_NVME_CUSE
8235 : 119 : nvme_ctrlr_cuse_config_json(w, nvme_ctrlr);
8236 : : #endif
8237 : : }
8238 : : }
8239 : :
8240 [ - + ]: 143 : TAILQ_FOREACH(ctx, &g_discovery_ctxs, tailq) {
8241 [ # # # # ]: 0 : if (!ctx->from_mdns_discovery_service) {
8242 : 0 : bdev_nvme_discovery_config_json(w, ctx);
8243 : : }
8244 : : }
8245 : :
8246 : 143 : bdev_nvme_mdns_discovery_config_json(w);
8247 : :
8248 : : /* Dump as last parameter to give all NVMe bdevs chance to be constructed
8249 : : * before enabling hotplug poller.
8250 : : */
8251 : 143 : bdev_nvme_hotplug_config_json(w);
8252 : :
8253 [ - + ]: 143 : pthread_mutex_unlock(&g_bdev_nvme_mutex);
8254 : 143 : return 0;
8255 : : }
8256 : :
8257 : : struct spdk_nvme_ctrlr *
8258 : 22 : bdev_nvme_get_ctrlr(struct spdk_bdev *bdev)
8259 : : {
8260 : : struct nvme_bdev *nbdev;
8261 : : struct nvme_ns *nvme_ns;
8262 : :
8263 [ + - - + ]: 22 : if (!bdev || bdev->module != &nvme_if) {
8264 : 0 : return NULL;
8265 : : }
8266 : :
8267 : 22 : nbdev = SPDK_CONTAINEROF(bdev, struct nvme_bdev, disk);
8268 : 22 : nvme_ns = TAILQ_FIRST(&nbdev->nvme_ns_list);
8269 [ - + ]: 22 : assert(nvme_ns != NULL);
8270 : :
8271 : 22 : return nvme_ns->ctrlr->ctrlr;
8272 : : }
8273 : :
8274 : : void
8275 : 0 : nvme_io_path_info_json(struct spdk_json_write_ctx *w, struct nvme_io_path *io_path)
8276 : : {
8277 : 0 : struct nvme_ns *nvme_ns = io_path->nvme_ns;
8278 : 0 : struct nvme_ctrlr *nvme_ctrlr = io_path->qpair->ctrlr;
8279 : : const struct spdk_nvme_ctrlr_data *cdata;
8280 : : const struct spdk_nvme_transport_id *trid;
8281 : : const char *adrfam_str;
8282 : :
8283 : 0 : spdk_json_write_object_begin(w);
8284 : :
8285 : 0 : spdk_json_write_named_string(w, "bdev_name", nvme_ns->bdev->disk.name);
8286 : :
8287 : 0 : cdata = spdk_nvme_ctrlr_get_data(nvme_ctrlr->ctrlr);
8288 : 0 : trid = spdk_nvme_ctrlr_get_transport_id(nvme_ctrlr->ctrlr);
8289 : :
8290 : 0 : spdk_json_write_named_uint32(w, "cntlid", cdata->cntlid);
8291 [ # # ]: 0 : spdk_json_write_named_bool(w, "current", io_path->nbdev_ch != NULL &&
8292 [ # # ]: 0 : io_path == io_path->nbdev_ch->current_io_path);
8293 : 0 : spdk_json_write_named_bool(w, "connected", nvme_qpair_is_connected(io_path->qpair));
8294 : 0 : spdk_json_write_named_bool(w, "accessible", nvme_ns_is_accessible(nvme_ns));
8295 : :
8296 : 0 : spdk_json_write_named_object_begin(w, "transport");
8297 : 0 : spdk_json_write_named_string(w, "trtype", trid->trstring);
8298 : 0 : spdk_json_write_named_string(w, "traddr", trid->traddr);
8299 [ # # ]: 0 : if (trid->trsvcid[0] != '\0') {
8300 : 0 : spdk_json_write_named_string(w, "trsvcid", trid->trsvcid);
8301 : : }
8302 : 0 : adrfam_str = spdk_nvme_transport_id_adrfam_str(trid->adrfam);
8303 [ # # ]: 0 : if (adrfam_str) {
8304 : 0 : spdk_json_write_named_string(w, "adrfam", adrfam_str);
8305 : : }
8306 : 0 : spdk_json_write_object_end(w);
8307 : :
8308 : 0 : spdk_json_write_object_end(w);
8309 : 0 : }
8310 : :
8311 : : void
8312 : 77 : bdev_nvme_get_discovery_info(struct spdk_json_write_ctx *w)
8313 : : {
8314 : : struct discovery_ctx *ctx;
8315 : : struct discovery_entry_ctx *entry_ctx;
8316 : :
8317 : 77 : spdk_json_write_array_begin(w);
8318 [ + + ]: 150 : TAILQ_FOREACH(ctx, &g_discovery_ctxs, tailq) {
8319 : 73 : spdk_json_write_object_begin(w);
8320 : 73 : spdk_json_write_named_string(w, "name", ctx->name);
8321 : :
8322 : 73 : spdk_json_write_named_object_begin(w, "trid");
8323 : 73 : nvme_bdev_dump_trid_json(&ctx->trid, w);
8324 : 73 : spdk_json_write_object_end(w);
8325 : :
8326 : 73 : spdk_json_write_named_array_begin(w, "referrals");
8327 [ + + ]: 171 : TAILQ_FOREACH(entry_ctx, &ctx->discovery_entry_ctxs, tailq) {
8328 : 98 : spdk_json_write_object_begin(w);
8329 : 98 : spdk_json_write_named_object_begin(w, "trid");
8330 : 98 : nvme_bdev_dump_trid_json(&entry_ctx->trid, w);
8331 : 98 : spdk_json_write_object_end(w);
8332 : 98 : spdk_json_write_object_end(w);
8333 : : }
8334 : 73 : spdk_json_write_array_end(w);
8335 : :
8336 : 73 : spdk_json_write_object_end(w);
8337 : : }
8338 : 77 : spdk_json_write_array_end(w);
8339 : 77 : }
8340 : :
8341 : 2042 : SPDK_LOG_REGISTER_COMPONENT(bdev_nvme)
8342 : :
8343 : 3934 : SPDK_TRACE_REGISTER_FN(bdev_nvme_trace, "bdev_nvme", TRACE_GROUP_BDEV_NVME)
8344 : : {
8345 : 1892 : struct spdk_trace_tpoint_opts opts[] = {
8346 : : {
8347 : : "BDEV_NVME_IO_START", TRACE_BDEV_NVME_IO_START,
8348 : : OWNER_NONE, OBJECT_BDEV_NVME_IO, 1,
8349 : : {{ "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 }}
8350 : : },
8351 : : {
8352 : : "BDEV_NVME_IO_DONE", TRACE_BDEV_NVME_IO_DONE,
8353 : : OWNER_NONE, OBJECT_BDEV_NVME_IO, 0,
8354 : : {{ "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 }}
8355 : : }
8356 : : };
8357 : :
8358 : :
8359 : 1892 : spdk_trace_register_object(OBJECT_BDEV_NVME_IO, 'N');
8360 : 1892 : spdk_trace_register_description_ext(opts, SPDK_COUNTOF(opts));
8361 : 1892 : spdk_trace_tpoint_register_relation(TRACE_NVME_PCIE_SUBMIT, OBJECT_BDEV_NVME_IO, 0);
8362 : 1892 : spdk_trace_tpoint_register_relation(TRACE_NVME_TCP_SUBMIT, OBJECT_BDEV_NVME_IO, 0);
8363 : 1892 : spdk_trace_tpoint_register_relation(TRACE_NVME_PCIE_COMPLETE, OBJECT_BDEV_NVME_IO, 0);
8364 : 1892 : spdk_trace_tpoint_register_relation(TRACE_NVME_TCP_COMPLETE, OBJECT_BDEV_NVME_IO, 0);
8365 : 1892 : }
|