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