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