Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2021 Intel Corporation. All rights reserved.
3 : : * Copyright (c) 2021 Mellanox Technologies LTD. All rights reserved.
4 : : * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : : */
6 : :
7 : : /*
8 : : * NVMe over PCIe common library
9 : : */
10 : :
11 : : #include "spdk/stdinc.h"
12 : : #include "spdk/likely.h"
13 : : #include "spdk/string.h"
14 : : #include "nvme_internal.h"
15 : : #include "nvme_pcie_internal.h"
16 : : #include "spdk/trace.h"
17 : :
18 : : #include "spdk_internal/trace_defs.h"
19 : :
20 : : __thread struct nvme_pcie_ctrlr *g_thread_mmio_ctrlr = NULL;
21 : :
22 : : static struct spdk_nvme_pcie_stat g_dummy_stat = {};
23 : :
24 : : static void nvme_pcie_fail_request_bad_vtophys(struct spdk_nvme_qpair *qpair,
25 : : struct nvme_tracker *tr);
26 : :
27 : : static inline uint64_t
28 : 83582056 : nvme_pcie_vtophys(struct spdk_nvme_ctrlr *ctrlr, const void *buf, uint64_t *size)
29 : : {
30 [ + + + - : 83582056 : if (spdk_likely(ctrlr->trid.trtype == SPDK_NVME_TRANSPORT_PCIE)) {
+ - + + ]
31 : 81958552 : return spdk_vtophys(buf, size);
32 : : } else {
33 : : /* vfio-user address translation with IOVA=VA mode */
34 : 1623504 : return (uint64_t)(uintptr_t)buf;
35 : : }
36 : 1224539 : }
37 : :
38 : : int
39 : 5026 : nvme_pcie_qpair_reset(struct spdk_nvme_qpair *qpair)
40 : : {
41 : 5026 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
42 : : uint32_t i;
43 : :
44 : : /* all head/tail vals are set to 0 */
45 [ + - + - : 5026 : pqpair->last_sq_tail = pqpair->sq_tail = pqpair->sq_head = pqpair->cq_head = 0;
+ - + - +
- + - + -
+ - ]
46 : :
47 : : /*
48 : : * First time through the completion queue, HW will set phase
49 : : * bit on completions to 1. So set this to 1 here, indicating
50 : : * we're looking for a 1 to know which entries have completed.
51 : : * we'll toggle the bit each time when the completion queue
52 : : * rolls over.
53 : : */
54 [ + - + - ]: 5026 : pqpair->flags.phase = 1;
55 [ + + + - : 1623294 : for (i = 0; i < pqpair->num_entries; i++) {
+ + ]
56 [ + - + - : 1618268 : pqpair->cpl[i].status.p = 0;
+ - + - +
- + - ]
57 : 52328 : }
58 : :
59 : 5026 : return 0;
60 : : }
61 : :
62 : : int
63 : 5 : nvme_pcie_qpair_get_fd(struct spdk_nvme_qpair *qpair, struct spdk_event_handler_opts *opts)
64 : : {
65 [ # # # # ]: 5 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
66 : 5 : struct spdk_pci_device *devhandle = nvme_ctrlr_proc_get_devhandle(ctrlr);
67 : :
68 [ - + # # ]: 5 : assert(devhandle != NULL);
69 [ - + - + : 5 : if (!ctrlr->opts.enable_interrupts) {
# # # # #
# ]
70 : 0 : return -1;
71 : : }
72 : :
73 [ + + ]: 5 : if (!opts) {
74 [ # # # # ]: 2 : return spdk_pci_device_get_interrupt_efd_by_index(devhandle, qpair->id);
75 : : }
76 : :
77 [ - + # # : 3 : if (!SPDK_FIELD_VALID(opts, fd_type, opts->opts_size)) {
# # ]
78 : 0 : return -EINVAL;
79 : : }
80 : :
81 [ # # # # ]: 3 : spdk_fd_group_get_default_event_handler_opts(opts, opts->opts_size);
82 [ # # # # ]: 3 : opts->fd_type = SPDK_FD_TYPE_EVENTFD;
83 : :
84 [ # # # # ]: 3 : return spdk_pci_device_get_interrupt_efd_by_index(devhandle, qpair->id);
85 : 0 : }
86 : :
87 : : static void
88 : 626067 : nvme_qpair_construct_tracker(struct nvme_tracker *tr, uint16_t cid, uint64_t phys_addr)
89 : : {
90 [ + - + - ]: 626067 : tr->prp_sgl_bus_addr = phys_addr + offsetof(struct nvme_tracker, u.prp);
91 [ + - + - ]: 626067 : tr->cid = cid;
92 [ + - + - ]: 626067 : tr->req = NULL;
93 : 626067 : }
94 : :
95 : : static void *
96 : 16 : nvme_pcie_ctrlr_alloc_cmb(struct spdk_nvme_ctrlr *ctrlr, uint64_t size, uint64_t alignment,
97 : : uint64_t *phys_addr)
98 : : {
99 : 16 : struct nvme_pcie_ctrlr *pctrlr = nvme_pcie_ctrlr(ctrlr);
100 : : uintptr_t addr;
101 : :
102 [ + + # # : 16 : if (pctrlr->cmb.mem_register_addr != NULL) {
# # # # ]
103 : : /* BAR is mapped for data */
104 : 4 : return NULL;
105 : : }
106 : :
107 [ # # # # : 12 : addr = (uintptr_t)pctrlr->cmb.bar_va + pctrlr->cmb.current_offset;
# # # # #
# # # ]
108 : 12 : addr = (addr + (alignment - 1)) & ~(alignment - 1);
109 : :
110 : : /* CMB may only consume part of the BAR, calculate accordingly */
111 [ + + # # : 12 : if (addr + size > ((uintptr_t)pctrlr->cmb.bar_va + pctrlr->cmb.size)) {
# # # # #
# # # #
# ]
112 : 4 : SPDK_ERRLOG("Tried to allocate past valid CMB range!\n");
113 : 4 : return NULL;
114 : : }
115 [ # # # # : 8 : *phys_addr = pctrlr->cmb.bar_pa + addr - (uintptr_t)pctrlr->cmb.bar_va;
# # # # #
# # # #
# ]
116 : :
117 [ # # # # : 8 : pctrlr->cmb.current_offset = (addr + size) - (uintptr_t)pctrlr->cmb.bar_va;
# # # # #
# # # ]
118 : :
119 : 8 : return (void *)addr;
120 : 4 : }
121 : :
122 : : int
123 : 2459 : nvme_pcie_qpair_construct(struct spdk_nvme_qpair *qpair,
124 : : const struct spdk_nvme_io_qpair_opts *opts)
125 : : {
126 [ + - + - ]: 2459 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
127 : 2459 : struct nvme_pcie_ctrlr *pctrlr = nvme_pcie_ctrlr(ctrlr);
128 : 2459 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
129 : : struct nvme_tracker *tr;
130 : : uint16_t i;
131 : : uint16_t num_trackers;
132 : 2459 : size_t page_align = sysconf(_SC_PAGESIZE);
133 : : size_t queue_align, queue_len;
134 : 2459 : uint32_t flags = SPDK_MALLOC_DMA;
135 : : int32_t numa_id;
136 : 2459 : uint64_t sq_paddr = 0;
137 : 2459 : uint64_t cq_paddr = 0;
138 : :
139 [ + + ]: 2459 : if (opts) {
140 [ + - + - : 1699 : pqpair->sq_vaddr = opts->sq.vaddr;
+ - + - +
- ]
141 [ + - + - : 1699 : pqpair->cq_vaddr = opts->cq.vaddr;
+ - + - +
- ]
142 [ + + + - : 1699 : pqpair->flags.disable_pcie_sgl_merge = opts->disable_pcie_sgl_merge;
+ - + - +
- ]
143 [ + - + - : 1699 : sq_paddr = opts->sq.paddr;
+ - ]
144 [ + - + - : 1699 : cq_paddr = opts->cq.paddr;
+ - ]
145 : 50 : }
146 : :
147 [ + - + - : 2459 : pqpair->retry_count = ctrlr->opts.transport_retry_count;
+ - + - +
- ]
148 : :
149 : : /*
150 : : * Limit the maximum number of completions to return per call to prevent wraparound,
151 : : * and calculate how many trackers can be submitted at once without overflowing the
152 : : * completion queue.
153 : : */
154 [ + - + - : 2459 : pqpair->max_completions_cap = pqpair->num_entries / 4;
+ - + - +
- ]
155 [ + + + - : 2459 : pqpair->max_completions_cap = spdk_max(pqpair->max_completions_cap, NVME_MIN_COMPLETIONS);
+ - + - +
- + - +
- ]
156 [ + + + - : 2459 : pqpair->max_completions_cap = spdk_min(pqpair->max_completions_cap, NVME_MAX_COMPLETIONS);
+ + + - +
- + - +
- ]
157 [ + - + - : 2459 : num_trackers = pqpair->num_entries - pqpair->max_completions_cap;
+ - + - ]
158 : :
159 [ + + + + : 2459 : SPDK_INFOLOG(nvme, "max_completions_cap = %" PRIu16 " num_trackers = %" PRIu16 "\n",
+ - # # #
# ]
160 : : pqpair->max_completions_cap, num_trackers);
161 : :
162 [ + + # # ]: 2459 : assert(num_trackers != 0);
163 : :
164 [ + - + - ]: 2459 : pqpair->sq_in_cmb = false;
165 : :
166 [ + + + + ]: 2459 : if (nvme_qpair_is_admin_queue(&pqpair->qpair)) {
167 : 756 : flags |= SPDK_MALLOC_SHARE;
168 : 38 : }
169 : :
170 : : /* cmd and cpl rings must be aligned on page size boundaries. */
171 [ + + + + : 2459 : if (ctrlr->opts.use_cmb_sqs) {
+ - + - +
- ]
172 [ # # # # : 5 : pqpair->cmd = nvme_pcie_ctrlr_alloc_cmb(ctrlr, pqpair->num_entries * sizeof(struct spdk_nvme_cmd),
# # # # ]
173 [ # # ]: 1 : page_align, &pqpair->cmd_bus_addr);
174 [ + - # # : 4 : if (pqpair->cmd != NULL) {
# # ]
175 [ # # # # ]: 4 : pqpair->sq_in_cmb = true;
176 : 1 : }
177 : 1 : }
178 : :
179 [ + + + + : 2459 : if (pqpair->sq_in_cmb == false) {
+ - - + ]
180 [ + + + - : 2455 : if (pqpair->sq_vaddr) {
- + ]
181 [ # # # # : 4 : pqpair->cmd = pqpair->sq_vaddr;
# # # # ]
182 : 1 : } else {
183 : : /* To ensure physical address contiguity we make each ring occupy
184 : : * a single hugepage only. See MAX_IO_QUEUE_ENTRIES.
185 : : */
186 [ + - + - ]: 2451 : queue_len = pqpair->num_entries * sizeof(struct spdk_nvme_cmd);
187 [ + + ]: 2451 : queue_align = spdk_max(spdk_align32pow2(queue_len), page_align);
188 [ + - + - ]: 2451 : pqpair->cmd = spdk_zmalloc(queue_len, queue_align, NULL, SPDK_ENV_NUMA_ID_ANY, flags);
189 [ + + + - : 2451 : if (pqpair->cmd == NULL) {
- + ]
190 : 0 : SPDK_ERRLOG("alloc qpair_cmd failed\n");
191 : 0 : return -ENOMEM;
192 : : }
193 : : }
194 [ + + ]: 2455 : if (sq_paddr) {
195 [ + + # # : 4 : assert(pqpair->sq_vaddr != NULL);
# # # # ]
196 [ # # # # ]: 4 : pqpair->cmd_bus_addr = sq_paddr;
197 : 1 : } else {
198 [ + - + - : 2451 : pqpair->cmd_bus_addr = nvme_pcie_vtophys(ctrlr, pqpair->cmd, NULL);
+ - + - ]
199 [ + + + - : 2451 : if (pqpair->cmd_bus_addr == SPDK_VTOPHYS_ERROR) {
+ - ]
200 : 0 : SPDK_ERRLOG("spdk_vtophys(pqpair->cmd) failed\n");
201 : 0 : return -EFAULT;
202 : : }
203 : : }
204 : 88 : }
205 : :
206 [ + + + - : 2459 : if (pqpair->cq_vaddr) {
- + ]
207 [ # # # # : 8 : pqpair->cpl = pqpair->cq_vaddr;
# # # # ]
208 : 2 : } else {
209 [ + - + - ]: 2451 : queue_len = pqpair->num_entries * sizeof(struct spdk_nvme_cpl);
210 [ + + ]: 2451 : queue_align = spdk_max(spdk_align32pow2(queue_len), page_align);
211 : 2451 : numa_id = spdk_nvme_ctrlr_get_numa_id(ctrlr);
212 [ + - + - ]: 2451 : pqpair->cpl = spdk_zmalloc(queue_len, queue_align, NULL, numa_id, flags);
213 [ + + + - : 2451 : if (pqpair->cpl == NULL) {
+ - ]
214 : 0 : SPDK_ERRLOG("alloc qpair_cpl failed\n");
215 : 0 : return -ENOMEM;
216 : : }
217 : : }
218 [ + + ]: 2459 : if (cq_paddr) {
219 [ + + # # : 8 : assert(pqpair->cq_vaddr != NULL);
# # # # ]
220 [ # # # # ]: 8 : pqpair->cpl_bus_addr = cq_paddr;
221 : 2 : } else {
222 [ + - + - : 2451 : pqpair->cpl_bus_addr = nvme_pcie_vtophys(ctrlr, pqpair->cpl, NULL);
+ - + - ]
223 [ + + + - : 2451 : if (pqpair->cpl_bus_addr == SPDK_VTOPHYS_ERROR) {
+ - ]
224 : 0 : SPDK_ERRLOG("spdk_vtophys(pqpair->cpl) failed\n");
225 : 0 : return -EFAULT;
226 : : }
227 : : }
228 : :
229 [ + - + - : 2459 : pqpair->sq_tdbl = pctrlr->doorbell_base + (2 * qpair->id + 0) * pctrlr->doorbell_stride_u32;
+ - + - +
- + - + -
+ - + - +
- + - ]
230 [ + - + - : 2459 : pqpair->cq_hdbl = pctrlr->doorbell_base + (2 * qpair->id + 1) * pctrlr->doorbell_stride_u32;
+ - + - +
- + - + -
+ - + - +
- + - ]
231 : :
232 : : /*
233 : : * Reserve space for all of the trackers in a single allocation.
234 : : * struct nvme_tracker must be padded so that its size is already a power of 2.
235 : : * This ensures the PRP list embedded in the nvme_tracker object will not span a
236 : : * 4KB boundary, while allowing access to trackers in tr[] via normal array indexing.
237 : : */
238 [ + - + - ]: 2459 : pqpair->tr = spdk_zmalloc(num_trackers * sizeof(*tr), sizeof(*tr), NULL,
239 : : SPDK_ENV_NUMA_ID_ANY, SPDK_MALLOC_SHARE);
240 [ + + + - : 2459 : if (pqpair->tr == NULL) {
+ - ]
241 : 0 : SPDK_ERRLOG("nvme_tr failed\n");
242 : 0 : return -ENOMEM;
243 : : }
244 : :
245 [ + - + - : 2459 : TAILQ_INIT(&pqpair->free_tr);
+ - + - +
- + - + -
+ - ]
246 [ + - + - : 2459 : TAILQ_INIT(&pqpair->outstanding_tr);
+ - + - +
- + - + -
+ - ]
247 [ + - + - : 2459 : pqpair->qpair.queue_depth = 0;
+ - ]
248 : :
249 [ + + ]: 628526 : for (i = 0; i < num_trackers; i++) {
250 [ + - + - : 626067 : tr = &pqpair->tr[i];
+ - ]
251 : 626067 : nvme_qpair_construct_tracker(tr, i, nvme_pcie_vtophys(ctrlr, tr, NULL));
252 [ + + + - : 626067 : TAILQ_INSERT_HEAD(&pqpair->free_tr, tr, tq_list);
+ - + - +
- + - + +
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
253 : 20371 : }
254 : :
255 : 2459 : nvme_pcie_qpair_reset(qpair);
256 : :
257 : 2459 : return 0;
258 : 89 : }
259 : :
260 : : int
261 : 756 : nvme_pcie_ctrlr_construct_admin_qpair(struct spdk_nvme_ctrlr *ctrlr, uint16_t num_entries)
262 : : {
263 : : struct nvme_pcie_qpair *pqpair;
264 : : int rc;
265 : :
266 : 756 : pqpair = spdk_zmalloc(sizeof(*pqpair), 64, NULL, SPDK_ENV_NUMA_ID_ANY, SPDK_MALLOC_SHARE);
267 [ + + ]: 756 : if (pqpair == NULL) {
268 : 0 : return -ENOMEM;
269 : : }
270 : :
271 [ + - + - ]: 756 : pqpair->num_entries = num_entries;
272 [ + - + - ]: 756 : pqpair->flags.delay_cmd_submit = 0;
273 [ + - + - ]: 756 : pqpair->pcie_state = NVME_PCIE_QPAIR_READY;
274 : :
275 [ + - + - : 756 : ctrlr->adminq = &pqpair->qpair;
+ - ]
276 : :
277 [ + - + - ]: 785 : rc = nvme_qpair_init(ctrlr->adminq,
278 : : 0, /* qpair ID */
279 : 38 : ctrlr,
280 : : SPDK_NVME_QPRIO_URGENT,
281 : 38 : num_entries,
282 : : false);
283 [ - + ]: 756 : if (rc != 0) {
284 : 0 : return rc;
285 : : }
286 : :
287 [ + - + - ]: 756 : pqpair->stat = spdk_zmalloc(sizeof(*pqpair->stat), 64, NULL, SPDK_ENV_NUMA_ID_ANY,
288 : : SPDK_MALLOC_SHARE);
289 [ + + + - : 756 : if (!pqpair->stat) {
+ - ]
290 : 0 : SPDK_ERRLOG("Failed to allocate admin qpair statistics\n");
291 : 0 : return -ENOMEM;
292 : : }
293 : :
294 [ - + - + ]: 756 : return nvme_pcie_qpair_construct(ctrlr->adminq, NULL);
295 : 38 : }
296 : :
297 : : /**
298 : : * Note: the ctrlr_lock must be held when calling this function.
299 : : */
300 : : void
301 : 438 : nvme_pcie_qpair_insert_pending_admin_request(struct spdk_nvme_qpair *qpair,
302 : : struct nvme_request *req, struct spdk_nvme_cpl *cpl)
303 : : {
304 [ # # # # ]: 438 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
305 : 438 : struct nvme_request *active_req = req;
306 : : struct spdk_nvme_ctrlr_process *active_proc;
307 : :
308 : : /*
309 : : * The admin request is from another process. Move to the per
310 : : * process list for that process to handle it later.
311 : : */
312 [ - + # # ]: 438 : assert(nvme_qpair_is_admin_queue(qpair));
313 [ - + # # : 438 : assert(active_req->pid != getpid());
# # # # ]
314 : :
315 [ # # # # ]: 438 : active_proc = nvme_ctrlr_get_process(ctrlr, active_req->pid);
316 [ + + ]: 438 : if (active_proc) {
317 : : /* Save the original completion information */
318 [ # # # # : 354 : memcpy(&active_req->cpl, cpl, sizeof(*cpl));
# # ]
319 [ # # # # : 354 : STAILQ_INSERT_TAIL(&active_proc->active_reqs, active_req, stailq);
# # # # #
# # # # #
# # # # #
# # # #
# ]
320 : 0 : } else {
321 [ # # # # ]: 84 : SPDK_ERRLOG("The owning process (pid %d) is not found. Dropping the request.\n",
322 : : active_req->pid);
323 : 84 : nvme_cleanup_user_req(active_req);
324 : 84 : nvme_free_request(active_req);
325 : : }
326 : 438 : }
327 : :
328 : : /**
329 : : * Note: the ctrlr_lock must be held when calling this function.
330 : : */
331 : : void
332 : 40815460 : nvme_pcie_qpair_complete_pending_admin_request(struct spdk_nvme_qpair *qpair)
333 : : {
334 [ + - + - ]: 40815460 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
335 : : struct nvme_request *req, *tmp_req;
336 : 40815460 : pid_t pid = getpid();
337 : : struct spdk_nvme_ctrlr_process *proc;
338 : :
339 : : /*
340 : : * Check whether there is any pending admin request from
341 : : * other active processes.
342 : : */
343 [ + + # # ]: 40815460 : assert(nvme_qpair_is_admin_queue(qpair));
344 : :
345 : 40815460 : proc = nvme_ctrlr_get_current_process(ctrlr);
346 [ + + ]: 40815460 : if (!proc) {
347 : 0 : SPDK_ERRLOG("the active process (pid %d) is not found for this controller.\n", pid);
348 [ # # # # ]: 0 : assert(proc);
349 : 0 : return;
350 : : }
351 : :
352 [ + + + - : 40815814 : STAILQ_FOREACH_SAFE(req, &proc->active_reqs, stailq, tmp_req) {
+ - + - #
# # # # #
- + ]
353 [ + - + + : 354 : STAILQ_REMOVE(&proc->active_reqs, req, nvme_request, stailq);
- - - - #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
354 : :
355 [ - + # # : 354 : assert(req->pid == pid);
# # # # ]
356 : :
357 [ # # # # : 354 : nvme_complete_request(req->cb_fn, req->cb_arg, qpair, req, &req->cpl);
# # # # #
# ]
358 : 0 : }
359 : 505853 : }
360 : :
361 : : int
362 : 1748 : nvme_pcie_ctrlr_cmd_create_io_cq(struct spdk_nvme_ctrlr *ctrlr,
363 : : struct spdk_nvme_qpair *io_que, spdk_nvme_cmd_cb cb_fn,
364 : : void *cb_arg)
365 : : {
366 : 1748 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(io_que);
367 : : struct nvme_request *req;
368 : : struct spdk_nvme_cmd *cmd;
369 [ + + + - : 1748 : bool ien = ctrlr->opts.enable_interrupts;
+ - + - ]
370 : :
371 [ + - + - ]: 1748 : req = nvme_allocate_request_null(ctrlr->adminq, cb_fn, cb_arg);
372 [ + + ]: 1748 : if (req == NULL) {
373 : 8 : return -ENOMEM;
374 : : }
375 : :
376 [ + - ]: 1740 : cmd = &req->cmd;
377 [ + - ]: 1740 : cmd->opc = SPDK_NVME_OPC_CREATE_IO_CQ;
378 : :
379 [ + - + - : 1740 : cmd->cdw10_bits.create_io_q.qid = io_que->id;
+ - + - +
- + - ]
380 [ + - + - : 1740 : cmd->cdw10_bits.create_io_q.qsize = pqpair->num_entries - 1;
+ - + - +
- + - +
- ]
381 : :
382 [ + - + - : 1740 : cmd->cdw11_bits.create_io_cq.pc = 1;
+ - + - ]
383 [ + + + - ]: 1740 : if (ien) {
384 [ # # # # : 2 : cmd->cdw11_bits.create_io_cq.ien = 1;
# # # # ]
385 : : /* The interrupt vector offset starts from 1. We directly map the
386 : : * queue id to interrupt vector.
387 : : */
388 [ # # # # : 2 : cmd->cdw11_bits.create_io_cq.iv = io_que->id;
# # # # #
# # # ]
389 : 0 : }
390 : :
391 [ + - + - : 1740 : cmd->dptr.prp.prp1 = pqpair->cpl_bus_addr;
+ - + - +
- + - ]
392 : :
393 : 1740 : return nvme_ctrlr_submit_admin_request(ctrlr, req);
394 : 55 : }
395 : :
396 : : int
397 : 1740 : nvme_pcie_ctrlr_cmd_create_io_sq(struct spdk_nvme_ctrlr *ctrlr,
398 : : struct spdk_nvme_qpair *io_que, spdk_nvme_cmd_cb cb_fn, void *cb_arg)
399 : : {
400 : 1740 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(io_que);
401 : : struct nvme_request *req;
402 : : struct spdk_nvme_cmd *cmd;
403 : :
404 [ + - + - ]: 1740 : req = nvme_allocate_request_null(ctrlr->adminq, cb_fn, cb_arg);
405 [ + + ]: 1740 : if (req == NULL) {
406 : 4 : return -ENOMEM;
407 : : }
408 : :
409 [ + - ]: 1736 : cmd = &req->cmd;
410 [ + - ]: 1736 : cmd->opc = SPDK_NVME_OPC_CREATE_IO_SQ;
411 : :
412 [ + - + - : 1736 : cmd->cdw10_bits.create_io_q.qid = io_que->id;
+ - + - +
- + - ]
413 [ + - + - : 1736 : cmd->cdw10_bits.create_io_q.qsize = pqpair->num_entries - 1;
+ - + - +
- + - +
- ]
414 [ + - + - : 1736 : cmd->cdw11_bits.create_io_sq.pc = 1;
+ - + - ]
415 [ + - + - : 1736 : cmd->cdw11_bits.create_io_sq.qprio = io_que->qprio;
+ - + - +
- ]
416 [ + - + - : 1736 : cmd->cdw11_bits.create_io_sq.cqid = io_que->id;
+ - + - +
- + - ]
417 [ + - + - : 1736 : cmd->dptr.prp.prp1 = pqpair->cmd_bus_addr;
+ - + - +
- + - ]
418 : :
419 : 1736 : return nvme_ctrlr_submit_admin_request(ctrlr, req);
420 : 53 : }
421 : :
422 : : int
423 : 1645 : nvme_pcie_ctrlr_cmd_delete_io_cq(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair,
424 : : spdk_nvme_cmd_cb cb_fn, void *cb_arg)
425 : : {
426 : : struct nvme_request *req;
427 : : struct spdk_nvme_cmd *cmd;
428 : :
429 [ + - + - ]: 1645 : req = nvme_allocate_request_null(ctrlr->adminq, cb_fn, cb_arg);
430 [ + + ]: 1645 : if (req == NULL) {
431 : 4 : return -ENOMEM;
432 : : }
433 : :
434 [ + - ]: 1641 : cmd = &req->cmd;
435 [ + - ]: 1641 : cmd->opc = SPDK_NVME_OPC_DELETE_IO_CQ;
436 [ + - + - : 1641 : cmd->cdw10_bits.delete_io_q.qid = qpair->id;
+ - + - +
- + - ]
437 : :
438 : 1641 : return nvme_ctrlr_submit_admin_request(ctrlr, req);
439 : 50 : }
440 : :
441 : : int
442 : 1644 : nvme_pcie_ctrlr_cmd_delete_io_sq(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair,
443 : : spdk_nvme_cmd_cb cb_fn, void *cb_arg)
444 : : {
445 : : struct nvme_request *req;
446 : : struct spdk_nvme_cmd *cmd;
447 : :
448 [ + - + - ]: 1644 : req = nvme_allocate_request_null(ctrlr->adminq, cb_fn, cb_arg);
449 [ + + ]: 1644 : if (req == NULL) {
450 : 4 : return -ENOMEM;
451 : : }
452 : :
453 [ + - ]: 1640 : cmd = &req->cmd;
454 [ + - ]: 1640 : cmd->opc = SPDK_NVME_OPC_DELETE_IO_SQ;
455 [ + - + - : 1640 : cmd->cdw10_bits.delete_io_q.qid = qpair->id;
+ - + - +
- + - ]
456 : :
457 : 1640 : return nvme_ctrlr_submit_admin_request(ctrlr, req);
458 : 49 : }
459 : :
460 : : static void
461 : 4 : nvme_completion_sq_error_delete_cq_cb(void *arg, const struct spdk_nvme_cpl *cpl)
462 : : {
463 : 4 : struct spdk_nvme_qpair *qpair = arg;
464 : 4 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
465 : :
466 [ + - - + : 4 : if (spdk_nvme_cpl_is_error(cpl)) {
# # # # #
# # # # #
# # ]
467 : 0 : SPDK_ERRLOG("delete_io_cq failed!\n");
468 : 0 : }
469 : :
470 [ # # # # ]: 4 : pqpair->pcie_state = NVME_PCIE_QPAIR_FAILED;
471 : 4 : }
472 : :
473 : : static void
474 : 1732 : nvme_completion_create_sq_cb(void *arg, const struct spdk_nvme_cpl *cpl)
475 : : {
476 : 1732 : struct spdk_nvme_qpair *qpair = arg;
477 : 1732 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
478 [ + - + - ]: 1732 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
479 : 1732 : struct nvme_pcie_ctrlr *pctrlr = nvme_pcie_ctrlr(ctrlr);
480 : : int rc;
481 : :
482 [ + + + - : 1732 : if (pqpair->flags.defer_destruction) {
- + ]
483 : : /* This qpair was deleted by the application while the
484 : : * connection was still in progress. We had to wait
485 : : * to free the qpair resources until this outstanding
486 : : * command was completed. Now that we have the completion
487 : : * free it now.
488 : : */
489 : 0 : nvme_pcie_qpair_destroy(qpair);
490 : 0 : return;
491 : : }
492 : :
493 [ + + + + : 1732 : if (spdk_nvme_cpl_is_error(cpl)) {
+ - + - +
- + - + -
- + ]
494 : 4 : SPDK_ERRLOG("nvme_create_io_sq failed, deleting cq!\n");
495 [ # # # # ]: 5 : rc = nvme_pcie_ctrlr_cmd_delete_io_cq(qpair->ctrlr, qpair, nvme_completion_sq_error_delete_cq_cb,
496 : 1 : qpair);
497 [ + + ]: 4 : if (rc != 0) {
498 : 0 : SPDK_ERRLOG("Failed to send request to delete_io_cq with rc=%d\n", rc);
499 [ # # # # ]: 0 : pqpair->pcie_state = NVME_PCIE_QPAIR_FAILED;
500 : 0 : }
501 : 4 : return;
502 : : }
503 [ + - + - ]: 1728 : pqpair->pcie_state = NVME_PCIE_QPAIR_READY;
504 [ + + + - : 1728 : if (ctrlr->shadow_doorbell) {
+ - ]
505 [ # # # # : 2210 : pqpair->shadow_doorbell.sq_tdbl = ctrlr->shadow_doorbell + (2 * qpair->id + 0) *
# # # # #
# # # # #
# # # # #
# ]
506 [ # # # # ]: 1277 : pctrlr->doorbell_stride_u32;
507 [ # # # # : 2210 : pqpair->shadow_doorbell.cq_hdbl = ctrlr->shadow_doorbell + (2 * qpair->id + 1) *
# # # # #
# # # # #
# # # # #
# ]
508 [ # # # # ]: 1277 : pctrlr->doorbell_stride_u32;
509 [ # # # # : 2210 : pqpair->shadow_doorbell.sq_eventidx = ctrlr->eventidx + (2 * qpair->id + 0) *
# # # # #
# # # # #
# # # # #
# ]
510 [ # # # # ]: 1277 : pctrlr->doorbell_stride_u32;
511 [ # # # # : 2210 : pqpair->shadow_doorbell.cq_eventidx = ctrlr->eventidx + (2 * qpair->id + 1) *
# # # # #
# # # # #
# # # # #
# ]
512 [ # # # # ]: 1277 : pctrlr->doorbell_stride_u32;
513 [ # # # # ]: 1277 : pqpair->flags.has_shadow_doorbell = 1;
514 : 40 : } else {
515 [ + - + - ]: 451 : pqpair->flags.has_shadow_doorbell = 0;
516 : : }
517 : 1728 : nvme_pcie_qpair_reset(qpair);
518 : :
519 : 51 : }
520 : :
521 : : static void
522 : 1736 : nvme_completion_create_cq_cb(void *arg, const struct spdk_nvme_cpl *cpl)
523 : : {
524 : 1736 : struct spdk_nvme_qpair *qpair = arg;
525 : 1736 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
526 : : int rc;
527 : :
528 [ + + + - : 1736 : if (pqpair->flags.defer_destruction) {
- + ]
529 : : /* This qpair was deleted by the application while the
530 : : * connection was still in progress. We had to wait
531 : : * to free the qpair resources until this outstanding
532 : : * command was completed. Now that we have the completion
533 : : * free it now.
534 : : */
535 : 0 : nvme_pcie_qpair_destroy(qpair);
536 : 0 : return;
537 : : }
538 : :
539 [ + + + + : 1736 : if (spdk_nvme_cpl_is_error(cpl)) {
+ - + - +
- + - + -
- + ]
540 [ # # # # ]: 4 : pqpair->pcie_state = NVME_PCIE_QPAIR_FAILED;
541 : 4 : SPDK_ERRLOG("nvme_create_io_cq failed!\n");
542 : 4 : return;
543 : : }
544 : :
545 [ + - + - ]: 1732 : rc = nvme_pcie_ctrlr_cmd_create_io_sq(qpair->ctrlr, qpair, nvme_completion_create_sq_cb, qpair);
546 : :
547 [ + + ]: 1732 : if (rc != 0) {
548 : 0 : SPDK_ERRLOG("Failed to send request to create_io_sq, deleting cq!\n");
549 [ # # # # ]: 0 : rc = nvme_pcie_ctrlr_cmd_delete_io_cq(qpair->ctrlr, qpair, nvme_completion_sq_error_delete_cq_cb,
550 : 0 : qpair);
551 [ # # ]: 0 : if (rc != 0) {
552 : 0 : SPDK_ERRLOG("Failed to send request to delete_io_cq with rc=%d\n", rc);
553 [ # # # # ]: 0 : pqpair->pcie_state = NVME_PCIE_QPAIR_FAILED;
554 : 0 : }
555 : 0 : return;
556 : : }
557 [ + - + - ]: 1732 : pqpair->pcie_state = NVME_PCIE_QPAIR_WAIT_FOR_SQ;
558 : 52 : }
559 : :
560 : : static int
561 : 1740 : _nvme_pcie_ctrlr_create_io_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair,
562 : : uint16_t qid)
563 : : {
564 : 1740 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
565 : : int rc;
566 : :
567 : : /* Statistics may already be allocated in the case of controller reset */
568 [ + + + - : 1740 : if (qpair->poll_group) {
+ + ]
569 [ + - + - ]: 1272 : struct nvme_pcie_poll_group *group = SPDK_CONTAINEROF(qpair->poll_group,
570 : : struct nvme_pcie_poll_group, group);
571 : :
572 [ + - + - : 1272 : pqpair->stat = &group->stats;
+ - ]
573 [ + - + - ]: 1272 : pqpair->shared_stats = true;
574 : 29 : } else {
575 [ + + + - : 468 : if (pqpair->stat == NULL) {
- + ]
576 [ + - + - ]: 439 : pqpair->stat = calloc(1, sizeof(*pqpair->stat));
577 [ + + + - : 439 : if (!pqpair->stat) {
+ - ]
578 : 0 : SPDK_ERRLOG("Failed to allocate qpair statistics\n");
579 : 0 : nvme_qpair_set_state(qpair, NVME_QPAIR_DISCONNECTED);
580 : 0 : return -ENOMEM;
581 : : }
582 : 24 : }
583 : : }
584 : :
585 : 1740 : rc = nvme_pcie_ctrlr_cmd_create_io_cq(ctrlr, qpair, nvme_completion_create_cq_cb, qpair);
586 : :
587 [ + + ]: 1740 : if (rc != 0) {
588 : 4 : SPDK_ERRLOG("Failed to send request to create_io_cq\n");
589 : 4 : nvme_qpair_set_state(qpair, NVME_QPAIR_DISCONNECTED);
590 : 4 : return rc;
591 : : }
592 [ + - + - ]: 1736 : pqpair->pcie_state = NVME_PCIE_QPAIR_WAIT_FOR_CQ;
593 : 1736 : return 0;
594 : 53 : }
595 : :
596 : : int
597 : 2579 : nvme_pcie_ctrlr_connect_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair)
598 : : {
599 : 2579 : int rc = 0;
600 : :
601 [ + + ]: 2579 : if (!nvme_qpair_is_admin_queue(qpair)) {
602 [ + - + - ]: 1740 : rc = _nvme_pcie_ctrlr_create_io_qpair(ctrlr, qpair, qpair->id);
603 : 53 : } else {
604 : 839 : nvme_qpair_set_state(qpair, NVME_QPAIR_CONNECTED);
605 : : }
606 : :
607 : 2579 : return rc;
608 : : }
609 : :
610 : : void
611 : 2597 : nvme_pcie_ctrlr_disconnect_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair)
612 : : {
613 [ + + + + : 2597 : if (!nvme_qpair_is_admin_queue(qpair) || !ctrlr->is_disconnecting) {
+ + + - +
- ]
614 : 2510 : nvme_transport_ctrlr_disconnect_qpair_done(qpair);
615 : 84 : } else {
616 : : /* If this function is called for the admin qpair via spdk_nvme_ctrlr_reset()
617 : : * or spdk_nvme_ctrlr_disconnect(), initiate a Controller Level Reset.
618 : : * Then we can abort trackers safely because the Controller Level Reset deletes
619 : : * all I/O SQ/CQs.
620 : : */
621 : 87 : nvme_ctrlr_disable(ctrlr);
622 : : }
623 : 2597 : }
624 : :
625 : : /* Used when dst points to MMIO (i.e. CMB) in a virtual machine - in these cases we must
626 : : * not use wide instructions because QEMU will not emulate such instructions to MMIO space.
627 : : * So this function ensures we only copy 8 bytes at a time.
628 : : */
629 : : static inline void
630 : 0 : nvme_pcie_copy_command_mmio(struct spdk_nvme_cmd *dst, const struct spdk_nvme_cmd *src)
631 : : {
632 : 0 : uint64_t *dst64 = (uint64_t *)dst;
633 : 0 : const uint64_t *src64 = (const uint64_t *)src;
634 : : uint32_t i;
635 : :
636 [ # # ]: 0 : for (i = 0; i < sizeof(*dst) / 8; i++) {
637 [ # # # # : 0 : dst64[i] = src64[i];
# # # # ]
638 : 0 : }
639 : 0 : }
640 : :
641 : : static inline void
642 : 28257903 : nvme_pcie_copy_command(struct spdk_nvme_cmd *dst, const struct spdk_nvme_cmd *src)
643 : : {
644 : : /* dst and src are known to be non-overlapping and 64-byte aligned. */
645 : : #if defined(__SSE2__)
646 : 28257903 : __m128i *d128 = (__m128i *)dst;
647 : 28257903 : const __m128i *s128 = (const __m128i *)src;
648 : :
649 [ + - + - ]: 28257903 : _mm_stream_si128(&d128[0], _mm_load_si128(&s128[0]));
650 [ + - + - ]: 55245595 : _mm_stream_si128(&d128[1], _mm_load_si128(&s128[1]));
651 [ + - + - ]: 55245595 : _mm_stream_si128(&d128[2], _mm_load_si128(&s128[2]));
652 [ + - + - ]: 55245595 : _mm_stream_si128(&d128[3], _mm_load_si128(&s128[3]));
653 : : #else
654 : : *dst = *src;
655 : : #endif
656 : 28257903 : }
657 : :
658 : : void
659 : 28258040 : nvme_pcie_qpair_submit_tracker(struct spdk_nvme_qpair *qpair, struct nvme_tracker *tr)
660 : : {
661 : : struct nvme_request *req;
662 : 28258040 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
663 [ + - + - ]: 28258040 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
664 : :
665 [ + - + - ]: 28258040 : req = tr->req;
666 [ + + # # ]: 28258040 : assert(req != NULL);
667 : :
668 [ + + + + : 28258040 : spdk_trace_record(TRACE_NVME_PCIE_SUBMIT, qpair->id, 0, (uintptr_t)req, req->cb_arg,
+ - + - +
- + - + -
- + # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
669 : : (uint32_t)req->cmd.cid, (uint32_t)req->cmd.opc,
670 : : req->cmd.cdw10, req->cmd.cdw11, req->cmd.cdw12,
671 : : pqpair->qpair.queue_depth);
672 : :
673 [ + + + - : 28258040 : if (req->cmd.fuse) {
+ - ]
674 : : /*
675 : : * Keep track of the fuse operation sequence so that we ring the doorbell only
676 : : * after the second fuse is submitted.
677 : : */
678 [ # # # # : 2 : qpair->last_fuse = req->cmd.fuse;
# # ]
679 : 0 : }
680 : :
681 : : /* Don't use wide instructions to copy NVMe command, this is limited by QEMU
682 : : * virtual NVMe controller, the maximum access width is 8 Bytes for one time.
683 : : */
684 [ + + + + : 28257974 : if (spdk_unlikely((ctrlr->quirks & NVME_QUIRK_MAXIMUM_PCI_ACCESS_WIDTH) && pqpair->sq_in_cmb)) {
+ + # # #
# # # -
+ ]
685 [ # # # # : 0 : nvme_pcie_copy_command_mmio(&pqpair->cmd[pqpair->sq_tail], &req->cmd);
# # # # #
# # # ]
686 : 0 : } else {
687 : : /* Copy the command from the tracker to the submission queue. */
688 [ + - + - : 28257974 : nvme_pcie_copy_command(&pqpair->cmd[pqpair->sq_tail], &req->cmd);
+ - + - +
- + - ]
689 : : }
690 : :
691 [ + + + - : 28257974 : if (spdk_unlikely(++pqpair->sq_tail == pqpair->num_entries)) {
+ - + + ]
692 [ + - + - ]: 84308 : pqpair->sq_tail = 0;
693 : 4848 : }
694 : :
695 [ + + + - : 28257974 : if (spdk_unlikely(pqpair->sq_tail == pqpair->sq_head)) {
+ - + - +
- ]
696 : 0 : SPDK_ERRLOG("sq_tail is passing sq_head!\n");
697 : 0 : }
698 : :
699 [ + + + - : 28257974 : if (!pqpair->flags.delay_cmd_submit) {
+ + ]
700 : 6603337 : nvme_pcie_qpair_ring_sq_doorbell(qpair);
701 : 214240 : }
702 : 28257974 : }
703 : :
704 : : void
705 : 28260443 : nvme_pcie_qpair_complete_tracker(struct spdk_nvme_qpair *qpair, struct nvme_tracker *tr,
706 : : struct spdk_nvme_cpl *cpl, bool print_on_error)
707 : : {
708 : 28260443 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
709 : : struct nvme_request *req;
710 : : bool retry, error;
711 : : bool print_error;
712 : :
713 [ + - + - ]: 28260443 : req = tr->req;
714 : :
715 [ + + + + : 28260443 : spdk_trace_record(TRACE_NVME_PCIE_COMPLETE, qpair->id, 0, (uintptr_t)req, req->cb_arg,
+ - + - +
- + - + -
- + # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
716 : : (uint32_t)req->cmd.cid, (uint32_t)cpl->status_raw, pqpair->qpair.queue_depth);
717 : :
718 [ + + # # ]: 28260443 : assert(req != NULL);
719 : :
720 [ + + + + : 28260443 : error = spdk_nvme_cpl_is_error(cpl);
+ - + + +
- + - +
- ]
721 [ + + + + : 28260443 : retry = error && nvme_completion_is_retry(cpl) &&
+ - ]
722 [ # # # # : 0 : req->retries < pqpair->retry_count;
# # # # ]
723 [ + + + + : 28260443 : print_error = error && print_on_error && !qpair->ctrlr->opts.disable_error_logging;
+ + + - #
# # # # #
# # # # #
# ]
724 : :
725 [ + + + - ]: 28260443 : if (print_error) {
726 [ # # ]: 1285687 : spdk_nvme_qpair_print_command(qpair, &req->cmd);
727 : 2 : }
728 : :
729 [ + + + + : 28260443 : if (print_error || SPDK_DEBUGLOG_FLAG_ENABLED("nvme")) {
- + ]
730 : 1287939 : spdk_nvme_qpair_print_completion(qpair, cpl);
731 : 2214 : }
732 : :
733 [ + + + - : 28260447 : assert(cpl->cid == req->cmd.cid);
+ - + - +
- + - #
# ]
734 : :
735 [ + + - + ]: 28260447 : if (retry) {
736 [ # # ]: 0 : req->retries++;
737 : 0 : nvme_pcie_qpair_submit_tracker(qpair, tr);
738 : 0 : } else {
739 [ + + + - : 28260447 : TAILQ_REMOVE(&pqpair->outstanding_tr, tr, tq_list);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
740 [ + - + - ]: 28260447 : pqpair->qpair.queue_depth--;
741 : :
742 : : /* Only check admin requests from different processes. */
743 [ + + + + : 28260447 : if (nvme_qpair_is_admin_queue(qpair) && req->pid != getpid()) {
+ - + - ]
744 : 438 : nvme_pcie_qpair_insert_pending_admin_request(qpair, req, cpl);
745 : 0 : } else {
746 [ + - + - : 28260009 : nvme_complete_request(tr->cb_fn, tr->cb_arg, qpair, req, cpl);
+ - + - ]
747 : : }
748 : :
749 [ + - + - ]: 28260447 : tr->req = NULL;
750 : :
751 [ + + + - : 28260447 : TAILQ_INSERT_HEAD(&pqpair->free_tr, tr, tq_list);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- # # # #
# # # # #
# + - + -
+ - + - +
- + - + -
+ - ]
752 : : }
753 : 28260447 : }
754 : :
755 : : void
756 : 3614 : nvme_pcie_qpair_manual_complete_tracker(struct spdk_nvme_qpair *qpair,
757 : : struct nvme_tracker *tr, uint32_t sct, uint32_t sc, uint32_t dnr,
758 : : bool print_on_error)
759 : : {
760 : 1582 : struct spdk_nvme_cpl cpl;
761 : :
762 [ + + ]: 3614 : memset(&cpl, 0, sizeof(cpl));
763 [ + - + - : 3614 : cpl.sqid = qpair->id;
+ - ]
764 [ + - + - : 3614 : cpl.cid = tr->cid;
+ - ]
765 [ + - + - ]: 3614 : cpl.status.sct = sct;
766 [ + - + - ]: 3614 : cpl.status.sc = sc;
767 [ + - + - ]: 3614 : cpl.status.dnr = dnr;
768 [ + - ]: 3614 : nvme_pcie_qpair_complete_tracker(qpair, tr, &cpl, print_on_error);
769 : 3614 : }
770 : :
771 : : void
772 : 2527 : nvme_pcie_qpair_abort_trackers(struct spdk_nvme_qpair *qpair, uint32_t dnr)
773 : : {
774 : 2527 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
775 : : struct nvme_tracker *tr, *temp, *last;
776 : :
777 [ + - + - : 2527 : last = TAILQ_LAST(&pqpair->outstanding_tr, nvme_outstanding_tr_head);
+ - + - +
- + - ]
778 : :
779 : : /* Abort previously submitted (outstanding) trs */
780 [ + + + - : 3004 : TAILQ_FOREACH_SAFE(tr, &pqpair->outstanding_tr, tq_list, temp) {
+ - + - #
# # # # #
+ - ]
781 [ + + + - : 576 : if (!qpair->ctrlr->opts.disable_error_logging) {
# # # # #
# # # #
# ]
782 : 576 : SPDK_ERRLOG("aborting outstanding command\n");
783 : 0 : }
784 : 576 : nvme_pcie_qpair_manual_complete_tracker(qpair, tr, SPDK_NVME_SCT_GENERIC,
785 : 0 : SPDK_NVME_SC_ABORTED_BY_REQUEST, dnr, true);
786 : :
787 [ + + ]: 576 : if (tr == last) {
788 : 99 : break;
789 : : }
790 : 0 : }
791 : 2527 : }
792 : :
793 : : void
794 : 1585 : nvme_pcie_admin_qpair_abort_aers(struct spdk_nvme_qpair *qpair)
795 : : {
796 : 1585 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
797 : : struct nvme_tracker *tr;
798 : :
799 [ + - + - : 1585 : tr = TAILQ_FIRST(&pqpair->outstanding_tr);
+ - ]
800 [ + + ]: 4623 : while (tr != NULL) {
801 [ + + + - : 3038 : assert(tr->req != NULL);
+ - # # ]
802 [ + - + - : 3038 : if (tr->req->cmd.opc == SPDK_NVME_OPC_ASYNC_EVENT_REQUEST) {
+ - + - +
- ]
803 : 3038 : nvme_pcie_qpair_manual_complete_tracker(qpair, tr,
804 : : SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_ABORTED_SQ_DELETION, 0,
805 : : false);
806 [ + - + - : 3038 : tr = TAILQ_FIRST(&pqpair->outstanding_tr);
+ - ]
807 : 156 : } else {
808 [ # # # # : 0 : tr = TAILQ_NEXT(tr, tq_list);
# # ]
809 : : }
810 : : }
811 : 1585 : }
812 : :
813 : : void
814 : 751 : nvme_pcie_admin_qpair_destroy(struct spdk_nvme_qpair *qpair)
815 : : {
816 : 751 : nvme_pcie_admin_qpair_abort_aers(qpair);
817 : 751 : }
818 : :
819 : : void
820 : 836 : nvme_pcie_qpair_abort_reqs(struct spdk_nvme_qpair *qpair, uint32_t dnr)
821 : : {
822 : 836 : nvme_pcie_qpair_abort_trackers(qpair, dnr);
823 : 836 : }
824 : :
825 : : static void
826 : 455511 : nvme_pcie_qpair_check_timeout(struct spdk_nvme_qpair *qpair)
827 : : {
828 : : uint64_t t02;
829 : : struct nvme_tracker *tr, *tmp;
830 : 455511 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
831 [ # # # # ]: 455511 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
832 : : struct spdk_nvme_ctrlr_process *active_proc;
833 : :
834 : : /* Don't check timeouts during controller initialization. */
835 [ - + # # : 455511 : if (ctrlr->state != NVME_CTRLR_STATE_READY) {
# # ]
836 : 0 : return;
837 : : }
838 : :
839 [ + + ]: 455511 : if (nvme_qpair_is_admin_queue(qpair)) {
840 : 332863 : active_proc = nvme_ctrlr_get_current_process(ctrlr);
841 : 0 : } else {
842 [ # # # # ]: 122648 : active_proc = qpair->active_proc;
843 : : }
844 : :
845 : : /* Only check timeouts if the current process has a timeout callback. */
846 [ + - - + : 455511 : if (active_proc == NULL || active_proc->timeout_cb_fn == NULL) {
# # # # ]
847 : 0 : return;
848 : : }
849 : :
850 : 455511 : t02 = spdk_get_ticks();
851 [ + + # # : 457435 : TAILQ_FOREACH_SAFE(tr, &pqpair->outstanding_tr, tq_list, tmp) {
# # # # #
# # # # #
# # ]
852 [ - + # # : 124987 : assert(tr->req != NULL);
# # # # ]
853 : :
854 [ + + # # : 124987 : if (nvme_request_check_timeout(tr->req, tr->cid, active_proc, t02)) {
# # # # #
# ]
855 : : /*
856 : : * The requests are in order, so as soon as one has not timed out,
857 : : * stop iterating.
858 : : */
859 : 123063 : break;
860 : : }
861 : 0 : }
862 : 0 : }
863 : :
864 : : int32_t
865 : 475275572 : nvme_pcie_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions)
866 : : {
867 : 475275572 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
868 : : struct nvme_tracker *tr;
869 : : struct spdk_nvme_cpl *cpl, *next_cpl;
870 : 475275572 : uint32_t num_completions = 0;
871 [ + - + - ]: 475275572 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
872 : : uint16_t next_cq_head;
873 : : uint8_t next_phase;
874 : 475275572 : bool next_is_valid = false;
875 : : int rc;
876 : :
877 [ + + + - : 475275572 : if (spdk_unlikely(pqpair->pcie_state == NVME_PCIE_QPAIR_FAILED)) {
- + ]
878 : 0 : return -ENXIO;
879 : : }
880 : :
881 [ + + ]: 475275572 : if (spdk_unlikely(nvme_qpair_get_state(qpair) == NVME_QPAIR_CONNECTING)) {
882 [ + + + - : 411881 : if (pqpair->pcie_state == NVME_PCIE_QPAIR_READY) {
+ + ]
883 : : /* It is possible that another thread set the pcie_state to
884 : : * QPAIR_READY, if it polled the adminq and processed the SQ
885 : : * completion for this qpair. So check for that condition
886 : : * here and then update the qpair's state to CONNECTED, since
887 : : * we can only set the qpair state from the qpair's thread.
888 : : * (Note: this fixed issue #2157.)
889 : : */
890 : 1712 : nvme_qpair_set_state(qpair, NVME_QPAIR_CONNECTED);
891 [ + + + - : 410216 : } else if (pqpair->pcie_state == NVME_PCIE_QPAIR_FAILED) {
- + ]
892 : 0 : nvme_qpair_set_state(qpair, NVME_QPAIR_DISCONNECTED);
893 : 0 : return -ENXIO;
894 : : } else {
895 [ + - + - ]: 410169 : rc = spdk_nvme_qpair_process_completions(ctrlr->adminq, 0);
896 [ + + ]: 410169 : if (rc < 0) {
897 : 0 : return rc;
898 [ + + + - : 410169 : } else if (pqpair->pcie_state == NVME_PCIE_QPAIR_FAILED) {
- + ]
899 : 0 : nvme_qpair_set_state(qpair, NVME_QPAIR_DISCONNECTED);
900 : 0 : return -ENXIO;
901 : : }
902 : : }
903 : 411881 : return 0;
904 : : }
905 : :
906 [ + + ]: 474863691 : if (spdk_unlikely(nvme_qpair_is_admin_queue(qpair))) {
907 : 40815460 : nvme_ctrlr_lock(ctrlr);
908 : 505853 : }
909 : :
910 [ + + + + : 474863691 : if (max_completions == 0 || max_completions > pqpair->max_completions_cap) {
# # # # ]
911 : : /*
912 : : * max_completions == 0 means unlimited, but complete at most
913 : : * max_completions_cap batch of I/O at a time so that the completion
914 : : * queue doorbells don't wrap around.
915 : : */
916 [ + - + - ]: 440827839 : max_completions = pqpair->max_completions_cap;
917 : 37057998 : }
918 : :
919 [ + - + - : 474909095 : pqpair->stat->polls++;
+ - ]
920 : :
921 : 67896766 : while (1) {
922 [ + - + - : 501777262 : cpl = &pqpair->cpl[pqpair->cq_head];
+ - + - +
- ]
923 : :
924 [ + + + + : 501777262 : if (!next_is_valid && cpl->status.p != pqpair->flags.phase) {
+ - + - +
- + - + -
+ + ]
925 : 473521116 : break;
926 : : }
927 : :
928 [ + + + - : 28256146 : if (spdk_likely(pqpair->cq_head + 1 != pqpair->num_entries)) {
+ - + - +
- + + ]
929 [ + - + - : 28171838 : next_cq_head = pqpair->cq_head + 1;
+ - ]
930 [ + - + - ]: 28171838 : next_phase = pqpair->flags.phase;
931 : 1267080 : } else {
932 : 84308 : next_cq_head = 0;
933 [ + - + - ]: 84308 : next_phase = !pqpair->flags.phase;
934 : : }
935 [ + - + - : 28256146 : next_cpl = &pqpair->cpl[next_cq_head];
+ - ]
936 [ + - + - : 28256146 : next_is_valid = (next_cpl->status.p == next_phase);
+ - ]
937 [ + + + + ]: 28256146 : if (next_is_valid) {
938 [ + - + - : 20373437 : __builtin_prefetch(&pqpair->tr[next_cpl->cid]);
+ - + - +
- ]
939 : 1068429 : }
940 : :
941 : : #if defined(__PPC64__) || defined(__riscv) || defined(__loongarch__)
942 : : /*
943 : : * This memory barrier prevents reordering of:
944 : : * - load after store from/to tr
945 : : * - load after load cpl phase and cpl cid
946 : : */
947 : : spdk_mb();
948 : : #elif defined(__aarch64__)
949 : : __asm volatile("dmb oshld" ::: "memory");
950 : : #endif
951 : :
952 [ + + + - : 28256146 : if (spdk_unlikely(++pqpair->cq_head == pqpair->num_entries)) {
+ - + + ]
953 [ + - + - ]: 84308 : pqpair->cq_head = 0;
954 [ + - + - : 84308 : pqpair->flags.phase = !pqpair->flags.phase;
+ - + - ]
955 : 4848 : }
956 : :
957 [ + - + - : 28256146 : tr = &pqpair->tr[cpl->cid];
+ - + - +
- ]
958 [ + - + - : 28256146 : pqpair->sq_head = cpl->sqhd;
+ - + - ]
959 : :
960 [ + - + - : 28256146 : if (tr->req) {
+ - ]
961 : : /* Prefetch the req's STAILQ_ENTRY since we'll need to access it
962 : : * as part of putting the req back on the qpair's free list.
963 : : */
964 [ + - + - : 28256146 : __builtin_prefetch(&tr->req->stailq);
+ - ]
965 : 28256146 : nvme_pcie_qpair_complete_tracker(qpair, tr, cpl, true);
966 : 1271928 : } else {
967 : 0 : SPDK_ERRLOG("cpl does not map to outstanding cmd\n");
968 : 0 : spdk_nvme_qpair_print_completion(qpair, cpl);
969 [ # # ]: 0 : assert(0);
970 : : }
971 : :
972 [ + + ]: 28256146 : if (++num_completions == max_completions) {
973 : 1387979 : break;
974 : : }
975 : : }
976 : :
977 [ + + ]: 474909095 : if (num_completions > 0) {
978 [ + - + - : 8037277 : pqpair->stat->completions += num_completions;
+ - + - ]
979 : 8037277 : nvme_pcie_qpair_ring_cq_doorbell(qpair);
980 : 424871 : } else {
981 [ + - + - : 466871818 : pqpair->stat->idle_polls++;
+ - ]
982 : : }
983 : :
984 [ + + + - : 474909095 : if (pqpair->flags.delay_cmd_submit) {
+ + ]
985 [ + + + - : 389804717 : if (pqpair->last_sq_tail != pqpair->sq_tail) {
+ - + - +
+ ]
986 : 6219198 : nvme_pcie_qpair_ring_sq_doorbell(qpair);
987 [ + - + - : 6219198 : pqpair->last_sq_tail = pqpair->sq_tail;
+ - + - ]
988 : 252598 : }
989 : 47814694 : }
990 : :
991 [ + + + + : 474909095 : if (spdk_unlikely(ctrlr->timeout_enabled)) {
+ - + - ]
992 : : /*
993 : : * User registered for timeout callback
994 : : */
995 : 455511 : nvme_pcie_qpair_check_timeout(qpair);
996 : 0 : }
997 : :
998 : : /* Before returning, complete any pending admin request or
999 : : * process the admin qpair disconnection.
1000 : : */
1001 [ + + ]: 474909095 : if (spdk_unlikely(nvme_qpair_is_admin_queue(qpair))) {
1002 : 40815460 : nvme_pcie_qpair_complete_pending_admin_request(qpair);
1003 : :
1004 [ + + ]: 40815460 : if (nvme_qpair_get_state(qpair) == NVME_QPAIR_DISCONNECTING) {
1005 [ # # # # ]: 620 : rc = nvme_ctrlr_disable_poll(qpair->ctrlr);
1006 [ + + ]: 620 : if (rc != -EAGAIN) {
1007 : 87 : nvme_transport_ctrlr_disconnect_qpair_done(qpair);
1008 : 3 : }
1009 : 18 : }
1010 : :
1011 : 40815460 : nvme_ctrlr_unlock(ctrlr);
1012 : 505853 : }
1013 : :
1014 [ + + + - : 474909095 : if (spdk_unlikely(pqpair->flags.has_pending_vtophys_failures)) {
- + ]
1015 : : struct nvme_tracker *tr, *tmp;
1016 : :
1017 [ # # # # : 0 : TAILQ_FOREACH_SAFE(tr, &pqpair->outstanding_tr, tq_list, tmp) {
# # # # #
# # # # #
# # ]
1018 [ # # # # ]: 0 : if (tr->bad_vtophys) {
1019 [ # # ]: 0 : tr->bad_vtophys = 0;
1020 : 0 : nvme_pcie_fail_request_bad_vtophys(qpair, tr);
1021 : 0 : }
1022 : 0 : }
1023 [ # # # # ]: 0 : pqpair->flags.has_pending_vtophys_failures = 0;
1024 : 0 : }
1025 : :
1026 : 474909095 : return num_completions;
1027 : 66883863 : }
1028 : :
1029 : : int
1030 : 2454 : nvme_pcie_qpair_destroy(struct spdk_nvme_qpair *qpair)
1031 : : {
1032 : 2454 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
1033 : :
1034 [ + + ]: 2454 : if (nvme_qpair_is_admin_queue(qpair)) {
1035 : 751 : nvme_pcie_admin_qpair_destroy(qpair);
1036 : 37 : }
1037 : : /*
1038 : : * We check sq_vaddr and cq_vaddr to see if the user specified the memory
1039 : : * buffers when creating the I/O queue.
1040 : : * If the user specified them, we cannot free that memory.
1041 : : * Nor do we free it if it's in the CMB.
1042 : : */
1043 [ + + + - : 2454 : if (!pqpair->sq_vaddr && pqpair->cmd && !pqpair->sq_in_cmb) {
+ + + - +
- + - + -
+ - + - -
+ ]
1044 [ + - + - ]: 2446 : spdk_free(pqpair->cmd);
1045 : 86 : }
1046 [ + + + + : 2454 : if (!pqpair->cq_vaddr && pqpair->cpl) {
+ - + - +
- + - ]
1047 [ + - + - ]: 2446 : spdk_free(pqpair->cpl);
1048 : 86 : }
1049 [ + + + - : 2454 : if (pqpair->tr) {
- + ]
1050 [ + - + - ]: 2454 : spdk_free(pqpair->tr);
1051 : 88 : }
1052 : :
1053 : 2454 : nvme_qpair_deinit(qpair);
1054 : :
1055 [ + + + + : 2877 : if (!pqpair->shared_stats && (!qpair->active_proc ||
+ + + + +
- + - + +
- + ]
1056 [ + - + - : 439 : qpair->active_proc == nvme_ctrlr_get_current_process(qpair->ctrlr))) {
+ - + - ]
1057 [ + + + - : 1202 : if (qpair->id) {
+ + ]
1058 [ + - + - ]: 451 : free(pqpair->stat);
1059 : 27 : } else {
1060 : : /* statistics of admin qpair are allocates from huge pages because
1061 : : * admin qpair is shared for multi-process */
1062 [ + - + - ]: 751 : spdk_free(pqpair->stat);
1063 : : }
1064 : :
1065 : 64 : }
1066 : :
1067 : 2454 : spdk_free(pqpair);
1068 : :
1069 : 2454 : return 0;
1070 : : }
1071 : :
1072 : : struct spdk_nvme_qpair *
1073 : 1691 : nvme_pcie_ctrlr_create_io_qpair(struct spdk_nvme_ctrlr *ctrlr, uint16_t qid,
1074 : : const struct spdk_nvme_io_qpair_opts *opts)
1075 : : {
1076 : : struct nvme_pcie_qpair *pqpair;
1077 : : struct spdk_nvme_qpair *qpair;
1078 : : int rc;
1079 : :
1080 [ + + # # ]: 1691 : assert(ctrlr != NULL);
1081 : :
1082 : 1691 : pqpair = spdk_zmalloc(sizeof(*pqpair), 64, NULL,
1083 : : SPDK_ENV_NUMA_ID_ANY, SPDK_MALLOC_SHARE);
1084 [ + + ]: 1691 : if (pqpair == NULL) {
1085 : 0 : return NULL;
1086 : : }
1087 : :
1088 [ + - + - : 1691 : pqpair->num_entries = opts->io_queue_size;
+ - + - ]
1089 [ + + + - : 1691 : pqpair->flags.delay_cmd_submit = opts->delay_cmd_submit;
+ - + - +
- + - ]
1090 : :
1091 [ + - ]: 1691 : qpair = &pqpair->qpair;
1092 : :
1093 [ + + + - : 1691 : rc = nvme_qpair_init(qpair, qid, ctrlr, opts->qprio, opts->io_queue_requests, opts->async_mode);
+ - + - +
- + - +
- ]
1094 [ - + ]: 1691 : if (rc != 0) {
1095 : 0 : nvme_pcie_qpair_destroy(qpair);
1096 : 0 : return NULL;
1097 : : }
1098 : :
1099 : 1691 : rc = nvme_pcie_qpair_construct(qpair, opts);
1100 : :
1101 [ - + ]: 1691 : if (rc != 0) {
1102 : 0 : nvme_pcie_qpair_destroy(qpair);
1103 : 0 : return NULL;
1104 : : }
1105 : :
1106 : 1691 : return qpair;
1107 : 48 : }
1108 : :
1109 : : int
1110 : 1691 : nvme_pcie_ctrlr_delete_io_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair)
1111 : : {
1112 : 1691 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
1113 : : struct nvme_completion_poll_status *status;
1114 : : int rc;
1115 : :
1116 [ + + # # ]: 1691 : assert(ctrlr != NULL);
1117 : :
1118 [ + + + + : 1691 : if (ctrlr->is_removed) {
+ - - + ]
1119 : 24 : goto free;
1120 : : }
1121 : :
1122 [ + + + + : 1667 : if (ctrlr->prepare_for_reset) {
+ - - + ]
1123 [ + + ]: 31 : if (nvme_qpair_get_state(qpair) == NVME_QPAIR_CONNECTING) {
1124 [ # # # # ]: 0 : pqpair->flags.defer_destruction = true;
1125 : 0 : }
1126 : 31 : goto clear_shadow_doorbells;
1127 : : }
1128 : :
1129 : : /* If attempting to delete a qpair that's still being connected, we have to wait until it's
1130 : : * finished, so that we don't free it while it's waiting for the create cq/sq callbacks.
1131 : : */
1132 [ + + + - : 1645 : while (pqpair->pcie_state == NVME_PCIE_QPAIR_WAIT_FOR_CQ ||
- + + - ]
1133 [ + + + - ]: 1636 : pqpair->pcie_state == NVME_PCIE_QPAIR_WAIT_FOR_SQ) {
1134 [ # # # # ]: 0 : rc = spdk_nvme_qpair_process_completions(ctrlr->adminq, 0);
1135 [ # # ]: 0 : if (rc < 0) {
1136 : 0 : break;
1137 : : }
1138 : : }
1139 : :
1140 : 1636 : status = calloc(1, sizeof(*status));
1141 [ + + ]: 1636 : if (!status) {
1142 : 0 : SPDK_ERRLOG("Failed to allocate status tracker\n");
1143 : 0 : goto free;
1144 : : }
1145 : :
1146 : : /* Delete the I/O submission queue */
1147 : 1636 : rc = nvme_pcie_ctrlr_cmd_delete_io_sq(ctrlr, qpair, nvme_completion_poll_cb, status);
1148 [ - + ]: 1636 : if (rc != 0) {
1149 : 0 : SPDK_ERRLOG("Failed to send request to delete_io_sq with rc=%d\n", rc);
1150 : 0 : free(status);
1151 : 0 : goto free;
1152 : : }
1153 [ + + + - : 1636 : if (nvme_wait_for_completion(ctrlr->adminq, status)) {
- + ]
1154 [ - + + - : 3 : if (!status->timed_out) {
# # # # ]
1155 : 3 : free(status);
1156 : 0 : }
1157 : 3 : goto free;
1158 : : }
1159 : :
1160 : : /* Now that the submission queue is deleted, the device is supposed to have
1161 : : * completed any outstanding I/O. Try to complete them. If they don't complete,
1162 : : * they'll be marked as aborted and completed below. */
1163 [ + + + - : 1633 : if (qpair->active_proc == nvme_ctrlr_get_current_process(ctrlr)) {
- + ]
1164 : 1633 : nvme_pcie_qpair_process_completions(qpair, 0);
1165 : 47 : }
1166 : :
1167 [ + + ]: 1633 : memset(status, 0, sizeof(*status));
1168 : : /* Delete the completion queue */
1169 : 1633 : rc = nvme_pcie_ctrlr_cmd_delete_io_cq(ctrlr, qpair, nvme_completion_poll_cb, status);
1170 [ - + ]: 1633 : if (rc != 0) {
1171 : 0 : SPDK_ERRLOG("Failed to send request to delete_io_cq with rc=%d\n", rc);
1172 : 0 : free(status);
1173 : 0 : goto free;
1174 : : }
1175 [ + + + - : 1633 : if (nvme_wait_for_completion(ctrlr->adminq, status)) {
- + ]
1176 [ # # # # : 0 : if (!status->timed_out) {
# # # # ]
1177 : 0 : free(status);
1178 : 0 : }
1179 : 0 : goto free;
1180 : : }
1181 : 1633 : free(status);
1182 : :
1183 : 1616 : clear_shadow_doorbells:
1184 [ + + + + : 1702 : if (pqpair->flags.has_shadow_doorbell && ctrlr->shadow_doorbell) {
- + # # #
# # # ]
1185 [ # # # # : 1206 : *pqpair->shadow_doorbell.sq_tdbl = 0;
# # ]
1186 [ # # # # : 1206 : *pqpair->shadow_doorbell.cq_hdbl = 0;
# # ]
1187 [ # # # # : 1206 : *pqpair->shadow_doorbell.sq_eventidx = 0;
# # ]
1188 [ # # # # : 1206 : *pqpair->shadow_doorbell.cq_eventidx = 0;
# # ]
1189 : 38 : }
1190 : 448 : free:
1191 [ + + - + ]: 1691 : if (qpair->no_deletion_notification_needed == 0) {
1192 : : /* Abort the rest of the I/O */
1193 : 1691 : nvme_pcie_qpair_abort_trackers(qpair, 1);
1194 : 48 : }
1195 : :
1196 [ + + + - : 1691 : if (!pqpair->flags.defer_destruction) {
- + ]
1197 : 1691 : nvme_pcie_qpair_destroy(qpair);
1198 : 48 : }
1199 : 1691 : return 0;
1200 : : }
1201 : :
1202 : : static void
1203 : 12 : nvme_pcie_fail_request_bad_vtophys(struct spdk_nvme_qpair *qpair, struct nvme_tracker *tr)
1204 : : {
1205 [ + - # # ]: 12 : if (!qpair->in_completion_context) {
1206 : 12 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
1207 : :
1208 [ # # ]: 12 : tr->bad_vtophys = 1;
1209 [ # # # # ]: 12 : pqpair->flags.has_pending_vtophys_failures = 1;
1210 : 12 : return;
1211 : : }
1212 : :
1213 : : /*
1214 : : * Bad vtophys translation, so abort this request and return
1215 : : * immediately.
1216 : : */
1217 : 0 : SPDK_ERRLOG("vtophys or other payload buffer related error\n");
1218 : 0 : nvme_pcie_qpair_manual_complete_tracker(qpair, tr, SPDK_NVME_SCT_GENERIC,
1219 : : SPDK_NVME_SC_INVALID_FIELD,
1220 : : 1 /* do not retry */, true);
1221 : 3 : }
1222 : :
1223 : : /*
1224 : : * Append PRP list entries to describe a virtually contiguous buffer starting at virt_addr of len bytes.
1225 : : *
1226 : : * *prp_index will be updated to account for the number of PRP entries used.
1227 : : */
1228 : : static inline int
1229 : 9838533 : nvme_pcie_prp_list_append(struct spdk_nvme_ctrlr *ctrlr, struct nvme_tracker *tr,
1230 : : uint32_t *prp_index, void *virt_addr, size_t len,
1231 : : uint32_t page_size)
1232 : : {
1233 [ + - + - : 9838533 : struct spdk_nvme_cmd *cmd = &tr->req->cmd;
+ - ]
1234 : 9838533 : uintptr_t page_mask = page_size - 1;
1235 : : uint64_t phys_addr;
1236 : : uint32_t i;
1237 : :
1238 [ + + + + : 9838533 : SPDK_DEBUGLOG(nvme, "prp_index:%u virt_addr:%p len:%u\n",
+ - # # ]
1239 : : *prp_index, virt_addr, (uint32_t)len);
1240 : :
1241 [ + + ]: 9838533 : if (spdk_unlikely(((uintptr_t)virt_addr & 3) != 0)) {
1242 : 8 : SPDK_ERRLOG("virt_addr %p not dword aligned\n", virt_addr);
1243 : 8 : return -EFAULT;
1244 : : }
1245 : :
1246 [ + - ]: 9838525 : i = *prp_index;
1247 [ + + ]: 73136378 : while (len) {
1248 : : uint32_t seg_len;
1249 : :
1250 : : /*
1251 : : * prp_index 0 is stored in prp1, and the rest are stored in the prp[] array,
1252 : : * so prp_index == count is valid.
1253 : : */
1254 [ + + ]: 63297869 : if (spdk_unlikely(i > SPDK_COUNTOF(tr->u.prp))) {
1255 : 8 : SPDK_ERRLOG("out of PRP entries\n");
1256 : 8 : return -EFAULT;
1257 : : }
1258 : :
1259 : 63297861 : phys_addr = nvme_pcie_vtophys(ctrlr, virt_addr, NULL);
1260 [ + + ]: 63297861 : if (spdk_unlikely(phys_addr == SPDK_VTOPHYS_ERROR)) {
1261 : 4 : SPDK_ERRLOG("vtophys(%p) failed\n", virt_addr);
1262 : 4 : return -EFAULT;
1263 : : }
1264 : :
1265 [ + + ]: 63297857 : if (i == 0) {
1266 [ + + + + : 9047392 : SPDK_DEBUGLOG(nvme, "prp1 = %p\n", (void *)phys_addr);
+ - ]
1267 [ + - + - : 9047392 : cmd->dptr.prp.prp1 = phys_addr;
+ - + - ]
1268 : 9047392 : seg_len = page_size - ((uintptr_t)virt_addr & page_mask);
1269 : 327 : } else {
1270 [ + + ]: 54250465 : if ((phys_addr & page_mask) != 0) {
1271 : 4 : SPDK_ERRLOG("PRP %u not page aligned (%p)\n", i, virt_addr);
1272 : 4 : return -EFAULT;
1273 : : }
1274 : :
1275 [ + + + + : 54250461 : SPDK_DEBUGLOG(nvme, "prp[%u] = %p\n", i - 1, (void *)phys_addr);
+ - ]
1276 [ + - + - : 54250461 : tr->u.prp[i - 1] = phys_addr;
+ - + - +
- ]
1277 : 54250461 : seg_len = page_size;
1278 : : }
1279 : :
1280 [ + + ]: 63297853 : seg_len = spdk_min(seg_len, len);
1281 [ + - ]: 63297853 : virt_addr = (uint8_t *)virt_addr + seg_len;
1282 : 63297853 : len -= seg_len;
1283 : 63297853 : i++;
1284 : : }
1285 : :
1286 [ + - ]: 9838509 : cmd->psdt = SPDK_NVME_PSDT_PRP;
1287 [ + + ]: 9838509 : if (i <= 1) {
1288 [ + - + - : 2462530 : cmd->dptr.prp.prp2 = 0;
+ - + - ]
1289 [ + + ]: 7376291 : } else if (i == 2) {
1290 [ # # # # : 5051071 : cmd->dptr.prp.prp2 = tr->u.prp[0];
# # # # #
# # # # #
# # # # ]
1291 [ + + + + : 5051071 : SPDK_DEBUGLOG(nvme, "prp2 = %p\n", (void *)cmd->dptr.prp.prp2);
# # # # #
# # # #
# ]
1292 : 7 : } else {
1293 [ + - + - : 2324908 : cmd->dptr.prp.prp2 = tr->prp_sgl_bus_addr;
+ - + - +
- + - ]
1294 [ + + + + : 2324908 : SPDK_DEBUGLOG(nvme, "prp2 = %p (PRP list)\n", (void *)cmd->dptr.prp.prp2);
+ - # # #
# # # #
# ]
1295 : : }
1296 : :
1297 [ + - ]: 9838509 : *prp_index = i;
1298 : 9838509 : return 0;
1299 : 333 : }
1300 : :
1301 : : static int
1302 : 0 : nvme_pcie_qpair_build_request_invalid(struct spdk_nvme_qpair *qpair,
1303 : : struct nvme_request *req, struct nvme_tracker *tr, bool dword_aligned)
1304 : : {
1305 [ # # ]: 0 : assert(0);
1306 : : nvme_pcie_fail_request_bad_vtophys(qpair, tr);
1307 : : return -EINVAL;
1308 : : }
1309 : :
1310 : : /**
1311 : : * Build PRP list describing physically contiguous payload buffer.
1312 : : */
1313 : : static int
1314 : 8413745 : nvme_pcie_qpair_build_contig_request(struct spdk_nvme_qpair *qpair, struct nvme_request *req,
1315 : : struct nvme_tracker *tr, bool dword_aligned)
1316 : : {
1317 : 8413745 : uint32_t prp_index = 0;
1318 : : int rc;
1319 : :
1320 [ + - + - ]: 16825837 : rc = nvme_pcie_prp_list_append(qpair->ctrlr, tr, &prp_index,
1321 [ + - + - : 8413745 : (uint8_t *)req->payload.contig_or_cb_arg + req->payload_offset,
+ - + - +
- + - ]
1322 [ + - + - : 16825525 : req->payload_size, qpair->ctrlr->page_size);
+ - + - +
- + - ]
1323 [ + + ]: 8413745 : if (rc) {
1324 : 4 : nvme_pcie_fail_request_bad_vtophys(qpair, tr);
1325 : 1 : } else {
1326 [ + + + + : 8413741 : SPDK_DEBUGLOG(nvme, "Number of PRP entries: %" PRIu32 "\n", prp_index);
+ - ]
1327 : : }
1328 : :
1329 : 8413745 : return rc;
1330 : : }
1331 : :
1332 : : /**
1333 : : * Build an SGL describing a physically contiguous payload buffer.
1334 : : *
1335 : : * This is more efficient than using PRP because large buffers can be
1336 : : * described this way.
1337 : : */
1338 : : static int
1339 : 16113079 : nvme_pcie_qpair_build_contig_hw_sgl_request(struct spdk_nvme_qpair *qpair, struct nvme_request *req,
1340 : : struct nvme_tracker *tr, bool dword_aligned)
1341 : : {
1342 : : uint8_t *virt_addr;
1343 : 7185475 : uint64_t phys_addr, mapping_length;
1344 : : uint32_t length;
1345 : : struct spdk_nvme_sgl_descriptor *sgl;
1346 : 16113079 : uint32_t nseg = 0;
1347 : :
1348 [ + + + - : 16113079 : assert(req->payload_size != 0);
+ - # # ]
1349 [ + + + - : 16113079 : assert(nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_CONTIG);
# # ]
1350 : :
1351 [ + - + - ]: 16113079 : sgl = tr->u.sgl;
1352 [ + - + - ]: 16113079 : req->cmd.psdt = SPDK_NVME_PSDT_SGL_MPTR_CONTIG;
1353 [ + - + - : 16113079 : req->cmd.dptr.sgl1.unkeyed.subtype = 0;
+ - + - +
- + - ]
1354 : :
1355 [ + - + - ]: 16113079 : length = req->payload_size;
1356 : : /* ubsan complains about applying zero offset to null pointer if contig_or_cb_arg is NULL,
1357 : : * so just double cast it to make it go away */
1358 [ + - + - : 16113079 : virt_addr = (uint8_t *)((uintptr_t)req->payload.contig_or_cb_arg + req->payload_offset);
+ - + - +
- ]
1359 : :
1360 [ + + ]: 32239457 : while (length > 0) {
1361 [ + + ]: 16126378 : if (nseg >= NVME_MAX_SGL_DESCRIPTORS) {
1362 : 0 : nvme_pcie_fail_request_bad_vtophys(qpair, tr);
1363 : 0 : return -EFAULT;
1364 : : }
1365 : :
1366 [ + + + + : 16126378 : if (dword_aligned && ((uintptr_t)virt_addr & 3)) {
- + ]
1367 : 0 : SPDK_ERRLOG("virt_addr %p not dword aligned\n", virt_addr);
1368 : 0 : nvme_pcie_fail_request_bad_vtophys(qpair, tr);
1369 : 0 : return -EFAULT;
1370 : : }
1371 : :
1372 : 16126378 : mapping_length = length;
1373 [ + - + - ]: 16126378 : phys_addr = nvme_pcie_vtophys(qpair->ctrlr, virt_addr, &mapping_length);
1374 [ + + ]: 16126378 : if (phys_addr == SPDK_VTOPHYS_ERROR) {
1375 : 0 : nvme_pcie_fail_request_bad_vtophys(qpair, tr);
1376 : 0 : return -EFAULT;
1377 : : }
1378 : :
1379 [ + + ]: 16126378 : mapping_length = spdk_min(length, mapping_length);
1380 : :
1381 : 16126378 : length -= mapping_length;
1382 [ + - ]: 16126378 : virt_addr += mapping_length;
1383 : :
1384 [ + - + - : 16126378 : sgl->unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
+ - ]
1385 [ + - + - : 16126378 : sgl->unkeyed.length = mapping_length;
+ - + - ]
1386 [ + - + - ]: 16126378 : sgl->address = phys_addr;
1387 [ + - + - : 16126378 : sgl->unkeyed.subtype = 0;
+ - ]
1388 : :
1389 [ + - ]: 16126378 : sgl++;
1390 : 16126378 : nseg++;
1391 : : }
1392 : :
1393 [ + + ]: 16113079 : if (nseg == 1) {
1394 : : /*
1395 : : * The whole transfer can be described by a single SGL descriptor.
1396 : : * Use the special case described by the spec where SGL1's type is Data Block.
1397 : : * This means the SGL in the tracker is not used at all, so copy the first (and only)
1398 : : * SGL element into SGL1.
1399 : : */
1400 [ + - + - : 16099952 : req->cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
+ - + - +
- + - ]
1401 [ + - + - : 16099952 : req->cmd.dptr.sgl1.address = tr->u.sgl[0].address;
+ - + - +
- + - + -
+ - + - +
- ]
1402 [ + - + - : 16099952 : req->cmd.dptr.sgl1.unkeyed.length = tr->u.sgl[0].unkeyed.length;
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - ]
1403 : 1201543 : } else {
1404 : : /* SPDK NVMe driver supports only 1 SGL segment for now, it is enough because
1405 : : * NVME_MAX_SGL_DESCRIPTORS * 16 is less than one page.
1406 : : */
1407 [ # # # # : 13127 : req->cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT;
# # # # #
# # # ]
1408 [ # # # # : 13127 : req->cmd.dptr.sgl1.address = tr->prp_sgl_bus_addr;
# # # # #
# # # #
# ]
1409 [ # # # # : 13127 : req->cmd.dptr.sgl1.unkeyed.length = nseg * sizeof(struct spdk_nvme_sgl_descriptor);
# # # # #
# # # #
# ]
1410 : : }
1411 : :
1412 [ + + + + : 16113079 : SPDK_DEBUGLOG(nvme, "Number of SGL descriptors: %" PRIu32 "\n", nseg);
+ - ]
1413 : 16113079 : return 0;
1414 : 1201544 : }
1415 : :
1416 : : /**
1417 : : * Build SGL list describing scattered payload buffer.
1418 : : */
1419 : : static int
1420 : 66603 : nvme_pcie_qpair_build_hw_sgl_request(struct spdk_nvme_qpair *qpair, struct nvme_request *req,
1421 : : struct nvme_tracker *tr, bool dword_aligned)
1422 : : {
1423 : : int rc;
1424 : 65171 : void *virt_addr;
1425 : 65171 : uint64_t phys_addr, mapping_length;
1426 : 65171 : uint32_t remaining_transfer_len, remaining_user_sge_len, length;
1427 : : struct spdk_nvme_sgl_descriptor *sgl;
1428 : 66603 : uint32_t nseg = 0;
1429 : 66603 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
1430 : :
1431 : : /*
1432 : : * Build scattered payloads.
1433 : : */
1434 [ + + # # : 66603 : assert(req->payload_size != 0);
# # # # ]
1435 [ + + # # : 66603 : assert(nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_SGL);
# # ]
1436 [ + + # # : 66603 : assert(req->payload.reset_sgl_fn != NULL);
# # # # #
# ]
1437 [ - + # # : 66603 : assert(req->payload.next_sge_fn != NULL);
# # # # #
# ]
1438 [ # # # # : 66603 : req->payload.reset_sgl_fn(req->payload.contig_or_cb_arg, req->payload_offset);
# # # # #
# # # # #
# # # # #
# ]
1439 : :
1440 [ # # # # ]: 66603 : sgl = tr->u.sgl;
1441 [ # # # # ]: 66603 : req->cmd.psdt = SPDK_NVME_PSDT_SGL_MPTR_CONTIG;
1442 [ # # # # : 66603 : req->cmd.dptr.sgl1.unkeyed.subtype = 0;
# # # # #
# # # ]
1443 : :
1444 [ # # # # ]: 66603 : remaining_transfer_len = req->payload_size;
1445 : :
1446 [ + + ]: 135514 : while (remaining_transfer_len > 0) {
1447 [ # # # # : 68911 : rc = req->payload.next_sge_fn(req->payload.contig_or_cb_arg,
# # # # #
# # # # #
# # ]
1448 : : &virt_addr, &remaining_user_sge_len);
1449 [ + + ]: 68911 : if (rc) {
1450 : 0 : nvme_pcie_fail_request_bad_vtophys(qpair, tr);
1451 : 0 : return -EFAULT;
1452 : : }
1453 : :
1454 : : /* Bit Bucket SGL descriptor */
1455 [ + + ]: 68911 : if ((uint64_t)virt_addr == UINT64_MAX) {
1456 : : /* TODO: enable WRITE and COMPARE when necessary */
1457 [ # # # # : 0 : if (req->cmd.opc != SPDK_NVME_OPC_READ) {
# # ]
1458 : 0 : SPDK_ERRLOG("Only READ command can be supported\n");
1459 : 0 : goto exit;
1460 : : }
1461 [ # # ]: 0 : if (nseg >= NVME_MAX_SGL_DESCRIPTORS) {
1462 : 0 : SPDK_ERRLOG("Too many SGL entries\n");
1463 : 0 : goto exit;
1464 : : }
1465 : :
1466 [ # # # # : 0 : sgl->unkeyed.type = SPDK_NVME_SGL_TYPE_BIT_BUCKET;
# # ]
1467 : : /* If the SGL describes a destination data buffer, the length of data
1468 : : * buffer shall be discarded by controller, and the length is included
1469 : : * in Number of Logical Blocks (NLB) parameter. Otherwise, the length
1470 : : * is not included in the NLB parameter.
1471 : : */
1472 [ # # ]: 0 : remaining_user_sge_len = spdk_min(remaining_user_sge_len, remaining_transfer_len);
1473 : 0 : remaining_transfer_len -= remaining_user_sge_len;
1474 : :
1475 [ # # # # : 0 : sgl->unkeyed.length = remaining_user_sge_len;
# # # # ]
1476 [ # # # # ]: 0 : sgl->address = 0;
1477 [ # # # # : 0 : sgl->unkeyed.subtype = 0;
# # ]
1478 : :
1479 [ # # ]: 0 : sgl++;
1480 : 0 : nseg++;
1481 : :
1482 : 0 : continue;
1483 : : }
1484 : :
1485 [ + + ]: 68911 : remaining_user_sge_len = spdk_min(remaining_user_sge_len, remaining_transfer_len);
1486 : 68911 : remaining_transfer_len -= remaining_user_sge_len;
1487 [ + + ]: 146483 : while (remaining_user_sge_len > 0) {
1488 [ + + ]: 77572 : if (nseg >= NVME_MAX_SGL_DESCRIPTORS) {
1489 : 0 : SPDK_ERRLOG("Too many SGL entries\n");
1490 : 0 : goto exit;
1491 : : }
1492 : :
1493 [ + + + + : 77572 : if (dword_aligned && ((uintptr_t)virt_addr & 3)) {
# # ]
1494 : 0 : SPDK_ERRLOG("virt_addr %p not dword aligned\n", virt_addr);
1495 : 0 : goto exit;
1496 : : }
1497 : :
1498 : 77572 : mapping_length = remaining_user_sge_len;
1499 [ # # # # ]: 77572 : phys_addr = nvme_pcie_vtophys(qpair->ctrlr, virt_addr, &mapping_length);
1500 [ + + ]: 77572 : if (phys_addr == SPDK_VTOPHYS_ERROR) {
1501 : 0 : goto exit;
1502 : : }
1503 : :
1504 [ + + ]: 77572 : length = spdk_min(remaining_user_sge_len, mapping_length);
1505 : 77572 : remaining_user_sge_len -= length;
1506 [ # # ]: 77572 : virt_addr = (uint8_t *)virt_addr + length;
1507 : :
1508 [ + - + + : 77572 : if (!pqpair->flags.disable_pcie_sgl_merge && nseg > 0 &&
+ + # # #
# ]
1509 [ + + # # : 10969 : phys_addr == (*(sgl - 1)).address + (*(sgl - 1)).unkeyed.length) {
# # # # #
# # # # #
# # ]
1510 : : /* extend previous entry */
1511 [ # # # # : 1705 : (*(sgl - 1)).unkeyed.length += length;
# # # # #
# ]
1512 : 1705 : continue;
1513 : : }
1514 : :
1515 [ # # # # : 75867 : sgl->unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
# # ]
1516 [ # # # # : 75867 : sgl->unkeyed.length = length;
# # # # ]
1517 [ # # # # ]: 75867 : sgl->address = phys_addr;
1518 [ # # # # : 75867 : sgl->unkeyed.subtype = 0;
# # ]
1519 : :
1520 [ # # ]: 75867 : sgl++;
1521 : 75867 : nseg++;
1522 : : }
1523 : : }
1524 : :
1525 [ + + ]: 66603 : if (nseg == 1) {
1526 : : /*
1527 : : * The whole transfer can be described by a single SGL descriptor.
1528 : : * Use the special case described by the spec where SGL1's type is Data Block.
1529 : : * This means the SGL in the tracker is not used at all, so copy the first (and only)
1530 : : * SGL element into SGL1.
1531 : : */
1532 [ # # # # : 57839 : req->cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
# # # # #
# # # ]
1533 [ # # # # : 57839 : req->cmd.dptr.sgl1.address = tr->u.sgl[0].address;
# # # # #
# # # # #
# # # # #
# ]
1534 [ # # # # : 57839 : req->cmd.dptr.sgl1.unkeyed.length = tr->u.sgl[0].unkeyed.length;
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
1535 : 28 : } else {
1536 : : /* SPDK NVMe driver supports only 1 SGL segment for now, it is enough because
1537 : : * NVME_MAX_SGL_DESCRIPTORS * 16 is less than one page.
1538 : : */
1539 [ # # # # : 8764 : req->cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT;
# # # # #
# # # ]
1540 [ # # # # : 8764 : req->cmd.dptr.sgl1.address = tr->prp_sgl_bus_addr;
# # # # #
# # # #
# ]
1541 [ # # # # : 8764 : req->cmd.dptr.sgl1.unkeyed.length = nseg * sizeof(struct spdk_nvme_sgl_descriptor);
# # # # #
# # # #
# ]
1542 : : }
1543 : :
1544 [ + + - + : 66603 : SPDK_DEBUGLOG(nvme, "Number of SGL descriptors: %" PRIu32 "\n", nseg);
# # ]
1545 : 66603 : return 0;
1546 : :
1547 : 0 : exit:
1548 : 0 : nvme_pcie_fail_request_bad_vtophys(qpair, tr);
1549 : 0 : return -EFAULT;
1550 : 35 : }
1551 : :
1552 : : /**
1553 : : * Build PRP list describing scattered payload buffer.
1554 : : */
1555 : : static int
1556 : 633591 : nvme_pcie_qpair_build_prps_sgl_request(struct spdk_nvme_qpair *qpair, struct nvme_request *req,
1557 : : struct nvme_tracker *tr, bool dword_aligned)
1558 : : {
1559 : : int rc;
1560 : 399444 : void *virt_addr;
1561 : 399444 : uint32_t remaining_transfer_len, length;
1562 : 633591 : uint32_t prp_index = 0;
1563 [ # # # # : 633591 : uint32_t page_size = qpair->ctrlr->page_size;
# # # # ]
1564 : :
1565 : : /*
1566 : : * Build scattered payloads.
1567 : : */
1568 [ + + # # : 633591 : assert(nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_SGL);
# # ]
1569 [ - + # # : 633591 : assert(req->payload.reset_sgl_fn != NULL);
# # # # #
# ]
1570 [ # # # # : 633591 : req->payload.reset_sgl_fn(req->payload.contig_or_cb_arg, req->payload_offset);
# # # # #
# # # # #
# # # # #
# ]
1571 : :
1572 [ # # # # ]: 633591 : remaining_transfer_len = req->payload_size;
1573 [ + + ]: 2058299 : while (remaining_transfer_len > 0) {
1574 [ + + # # : 1424708 : assert(req->payload.next_sge_fn != NULL);
# # # # #
# ]
1575 [ # # # # : 1424708 : rc = req->payload.next_sge_fn(req->payload.contig_or_cb_arg, &virt_addr, &length);
# # # # #
# # # # #
# # ]
1576 [ + + ]: 1424708 : if (rc) {
1577 : 0 : nvme_pcie_fail_request_bad_vtophys(qpair, tr);
1578 : 0 : return -EFAULT;
1579 : : }
1580 : :
1581 [ - + ]: 1424708 : length = spdk_min(remaining_transfer_len, length);
1582 : :
1583 : : /*
1584 : : * Any incompatible sges should have been handled up in the splitting routine,
1585 : : * but assert here as an additional check.
1586 : : *
1587 : : * All SGEs except last must end on a page boundary.
1588 : : */
1589 [ + + - + : 1424708 : assert((length == remaining_transfer_len) ||
# # ]
1590 : : _is_page_aligned((uintptr_t)virt_addr + length, page_size));
1591 : :
1592 [ # # # # ]: 1424708 : rc = nvme_pcie_prp_list_append(qpair->ctrlr, tr, &prp_index, virt_addr, length, page_size);
1593 [ + + ]: 1424708 : if (rc) {
1594 : 0 : nvme_pcie_fail_request_bad_vtophys(qpair, tr);
1595 : 0 : return rc;
1596 : : }
1597 : :
1598 : 1424708 : remaining_transfer_len -= length;
1599 : : }
1600 : :
1601 [ + + - + : 633591 : SPDK_DEBUGLOG(nvme, "Number of PRP entries: %" PRIu32 "\n", prp_index);
# # ]
1602 : 633591 : return 0;
1603 : 1 : }
1604 : :
1605 : : typedef int(*build_req_fn)(struct spdk_nvme_qpair *, struct nvme_request *, struct nvme_tracker *,
1606 : : bool);
1607 : :
1608 : : static build_req_fn const g_nvme_pcie_build_req_table[][2] = {
1609 : : [NVME_PAYLOAD_TYPE_INVALID] = {
1610 : : nvme_pcie_qpair_build_request_invalid, /* PRP */
1611 : : nvme_pcie_qpair_build_request_invalid /* SGL */
1612 : : },
1613 : : [NVME_PAYLOAD_TYPE_CONTIG] = {
1614 : : nvme_pcie_qpair_build_contig_request, /* PRP */
1615 : : nvme_pcie_qpair_build_contig_hw_sgl_request /* SGL */
1616 : : },
1617 : : [NVME_PAYLOAD_TYPE_SGL] = {
1618 : : nvme_pcie_qpair_build_prps_sgl_request, /* PRP */
1619 : : nvme_pcie_qpair_build_hw_sgl_request /* SGL */
1620 : : }
1621 : : };
1622 : :
1623 : : static int
1624 : 25226996 : nvme_pcie_qpair_build_metadata(struct spdk_nvme_qpair *qpair, struct nvme_tracker *tr,
1625 : : bool sgl_supported, bool mptr_sgl_supported, bool dword_aligned)
1626 : : {
1627 : : void *md_payload;
1628 [ + - + - ]: 25226996 : struct nvme_request *req = tr->req;
1629 : 9548101 : uint64_t mapping_length;
1630 : :
1631 [ + + + - : 25226996 : if (req->payload.md) {
+ - + - ]
1632 [ # # # # : 3449535 : md_payload = (uint8_t *)req->payload.md + req->md_offset;
# # # # #
# # # ]
1633 [ + + - + : 3449535 : if (dword_aligned && ((uintptr_t)md_payload & 3)) {
# # ]
1634 : 0 : SPDK_ERRLOG("virt_addr %p not dword aligned\n", md_payload);
1635 : 0 : goto exit;
1636 : : }
1637 : :
1638 [ # # # # ]: 3449535 : mapping_length = req->md_size;
1639 [ + + + + : 3449535 : if (sgl_supported && mptr_sgl_supported && dword_aligned) {
+ + # # #
# # # ]
1640 [ - + # # : 8 : assert(req->cmd.psdt == SPDK_NVME_PSDT_SGL_MPTR_CONTIG);
# # # # ]
1641 [ # # # # ]: 8 : req->cmd.psdt = SPDK_NVME_PSDT_SGL_MPTR_SGL;
1642 : :
1643 [ # # # # : 8 : tr->meta_sgl.address = nvme_pcie_vtophys(qpair->ctrlr, md_payload, &mapping_length);
# # # # #
# ]
1644 [ + - + + : 8 : if (tr->meta_sgl.address == SPDK_VTOPHYS_ERROR || mapping_length != req->md_size) {
# # # # #
# # # #
# ]
1645 : 4 : goto exit;
1646 : : }
1647 [ # # # # : 4 : tr->meta_sgl.unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
# # # # ]
1648 [ # # # # : 4 : tr->meta_sgl.unkeyed.length = req->md_size;
# # # # #
# # # #
# ]
1649 [ # # # # : 4 : tr->meta_sgl.unkeyed.subtype = 0;
# # # # ]
1650 [ # # # # : 4 : req->cmd.mptr = tr->prp_sgl_bus_addr - sizeof(struct spdk_nvme_sgl_descriptor);
# # # # #
# ]
1651 : 1 : } else {
1652 [ # # # # : 3449527 : req->cmd.mptr = nvme_pcie_vtophys(qpair->ctrlr, md_payload, &mapping_length);
# # # # #
# ]
1653 [ + - + + : 3449527 : if (req->cmd.mptr == SPDK_VTOPHYS_ERROR || mapping_length != req->md_size) {
# # # # #
# # # #
# ]
1654 : 4 : goto exit;
1655 : : }
1656 : : }
1657 : 3 : }
1658 : :
1659 : 25226988 : return 0;
1660 : :
1661 : 6 : exit:
1662 : 8 : nvme_pcie_fail_request_bad_vtophys(qpair, tr);
1663 : 8 : return -EINVAL;
1664 : 1201885 : }
1665 : :
1666 : : int
1667 : 28258303 : nvme_pcie_qpair_submit_request(struct spdk_nvme_qpair *qpair, struct nvme_request *req)
1668 : : {
1669 : : struct nvme_tracker *tr;
1670 : 28258303 : int rc = 0;
1671 [ + - + - ]: 28258303 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
1672 : 28258303 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
1673 : : enum nvme_payload_type payload_type;
1674 : : bool sgl_supported;
1675 : : bool mptr_sgl_supported;
1676 : 28258303 : bool dword_aligned = true;
1677 : :
1678 [ + + ]: 28258303 : if (spdk_unlikely(nvme_qpair_is_admin_queue(qpair))) {
1679 : 1260376 : nvme_ctrlr_lock(ctrlr);
1680 : 804 : }
1681 : :
1682 [ + - + - : 28258303 : tr = TAILQ_FIRST(&pqpair->free_tr);
+ - ]
1683 : :
1684 [ + + ]: 28258303 : if (tr == NULL) {
1685 [ # # # # : 88 : pqpair->stat->queued_requests++;
# # ]
1686 : : /* Inform the upper layer to try again later. */
1687 : 88 : rc = -EAGAIN;
1688 : 88 : goto exit;
1689 : : }
1690 : :
1691 [ + - + - : 28258215 : pqpair->stat->submitted_requests++;
+ - ]
1692 [ + + + - : 28258215 : TAILQ_REMOVE(&pqpair->free_tr, tr, tq_list); /* remove tr from free_tr */
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - # # #
# # # # #
# # # # +
- + - + -
+ - + - +
- + - ]
1693 [ + - + - : 28258215 : TAILQ_INSERT_TAIL(&pqpair->outstanding_tr, tr, tq_list);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
1694 [ + - + - ]: 28258215 : pqpair->qpair.queue_depth++;
1695 [ + - + - ]: 28258215 : tr->req = req;
1696 [ + - + - : 28258215 : tr->cb_fn = req->cb_fn;
+ - + - ]
1697 [ + - + - : 28258215 : tr->cb_arg = req->cb_arg;
+ - + - ]
1698 [ + - + - : 28258215 : req->cmd.cid = tr->cid;
+ - + - +
- ]
1699 : : /* Use PRP by default. This bit will be overridden below if needed. */
1700 [ + - + - ]: 28258215 : req->cmd.psdt = SPDK_NVME_PSDT_PRP;
1701 : :
1702 [ + + + - : 28258215 : if (req->payload_size != 0) {
+ + ]
1703 [ + - ]: 25226906 : payload_type = nvme_payload_type(&req->payload);
1704 : : /* According to the specification, PRPs shall be used for all
1705 : : * Admin commands for NVMe over PCIe implementations.
1706 : : */
1707 [ + + + - : 41412293 : sgl_supported = (ctrlr->flags & SPDK_NVME_CTRLR_SGL_SUPPORTED) != 0 &&
+ + ]
1708 [ + + ]: 16185387 : !nvme_qpair_is_admin_queue(qpair);
1709 [ + + + - : 26367285 : mptr_sgl_supported = (ctrlr->flags & SPDK_NVME_CTRLR_MPTR_SGL_SUPPORTED) != 0 &&
+ - ]
1710 [ + + ]: 1140379 : !nvme_qpair_is_admin_queue(qpair);
1711 : :
1712 [ + + + + ]: 25226798 : if (sgl_supported) {
1713 : : /* Don't use SGL for DSM command */
1714 [ + + + + : 16179097 : if (spdk_unlikely((ctrlr->quirks & NVME_QUIRK_NO_SGL_FOR_DSM) &&
+ - # # #
# + - ]
1715 : : (req->cmd.opc == SPDK_NVME_OPC_DATASET_MANAGEMENT))) {
1716 : 22 : sgl_supported = false;
1717 : 0 : }
1718 : 1200987 : }
1719 : :
1720 [ + + + + : 25226798 : if (sgl_supported && !(ctrlr->flags & SPDK_NVME_CTRLR_SGL_REQUIRES_DWORD_ALIGNMENT)) {
+ - + - +
- ]
1721 : 13430298 : dword_aligned = false;
1722 : 1061873 : }
1723 : :
1724 : : /* If we fail to build the request or the metadata, do not return the -EFAULT back up
1725 : : * the stack. This ensures that we always fail these types of requests via a
1726 : : * completion callback, and never in the context of the submission.
1727 : : */
1728 [ + - + - : 25226876 : rc = g_nvme_pcie_build_req_table[payload_type][sgl_supported](qpair, req, tr, dword_aligned);
+ - + - +
- + - - +
+ - + - ]
1729 [ + + ]: 25226876 : if (rc < 0) {
1730 [ # # # # ]: 0 : assert(rc == -EFAULT);
1731 : 0 : rc = 0;
1732 : 0 : goto exit;
1733 : : }
1734 : :
1735 [ + - + - : 25226876 : rc = nvme_pcie_qpair_build_metadata(qpair, tr, sgl_supported, mptr_sgl_supported, dword_aligned);
+ - ]
1736 [ + + ]: 25226876 : if (rc < 0) {
1737 [ # # # # ]: 0 : assert(rc == -EFAULT);
1738 : 0 : rc = 0;
1739 : 0 : goto exit;
1740 : : }
1741 : 1201780 : }
1742 : :
1743 : 28258185 : nvme_pcie_qpair_submit_tracker(qpair, tr);
1744 : :
1745 : 26987780 : exit:
1746 [ + + ]: 28258273 : if (spdk_unlikely(nvme_qpair_is_admin_queue(qpair))) {
1747 : 1260376 : nvme_ctrlr_unlock(ctrlr);
1748 : 804 : }
1749 : :
1750 : 28258273 : return rc;
1751 : : }
1752 : :
1753 : : struct spdk_nvme_transport_poll_group *
1754 : 1137 : nvme_pcie_poll_group_create(void)
1755 : : {
1756 : 1137 : struct nvme_pcie_poll_group *group = calloc(1, sizeof(*group));
1757 : :
1758 [ + + ]: 1137 : if (group == NULL) {
1759 : 0 : SPDK_ERRLOG("Unable to allocate poll group.\n");
1760 : 0 : return NULL;
1761 : : }
1762 : :
1763 [ + - ]: 1137 : return &group->group;
1764 : 24 : }
1765 : :
1766 : : int
1767 : 1252 : nvme_pcie_poll_group_connect_qpair(struct spdk_nvme_qpair *qpair)
1768 : : {
1769 : 1252 : return 0;
1770 : : }
1771 : :
1772 : : int
1773 : 1252 : nvme_pcie_poll_group_disconnect_qpair(struct spdk_nvme_qpair *qpair)
1774 : : {
1775 : 1252 : return 0;
1776 : : }
1777 : :
1778 : : int
1779 : 1252 : nvme_pcie_poll_group_add(struct spdk_nvme_transport_poll_group *tgroup,
1780 : : struct spdk_nvme_qpair *qpair)
1781 : : {
1782 : 1252 : return 0;
1783 : : }
1784 : :
1785 : : int
1786 : 1252 : nvme_pcie_poll_group_remove(struct spdk_nvme_transport_poll_group *tgroup,
1787 : : struct spdk_nvme_qpair *qpair)
1788 : : {
1789 : 1252 : struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
1790 : :
1791 [ + - + - ]: 1252 : pqpair->stat = &g_dummy_stat;
1792 : 1252 : return 0;
1793 : : }
1794 : :
1795 : : int64_t
1796 : 333633092 : nvme_pcie_poll_group_process_completions(struct spdk_nvme_transport_poll_group *tgroup,
1797 : : uint32_t completions_per_qpair, spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb)
1798 : : {
1799 : : struct spdk_nvme_qpair *qpair, *tmp_qpair;
1800 : 333633092 : int32_t local_completions = 0;
1801 : 333633092 : int64_t total_completions = 0;
1802 : :
1803 [ + + + + : 333634236 : STAILQ_FOREACH_SAFE(qpair, &tgroup->disconnected_qpairs, poll_group_stailq, tmp_qpair) {
+ - + + +
- + - + -
+ + ]
1804 [ - + + - : 1144 : disconnected_qpair_cb(qpair, tgroup->group->ctx);
+ - + - +
- + - ]
1805 : 22 : }
1806 : :
1807 [ + + + + : 689479551 : STAILQ_FOREACH_SAFE(qpair, &tgroup->connected_qpairs, poll_group_stailq, tmp_qpair) {
+ - + + +
- + - + -
+ + ]
1808 : 355846459 : local_completions = spdk_nvme_qpair_process_completions(qpair, completions_per_qpair);
1809 [ - + ]: 355846459 : if (spdk_unlikely(local_completions < 0)) {
1810 [ # # # # : 0 : disconnected_qpair_cb(qpair, tgroup->group->ctx);
# # # # #
# # # ]
1811 : 0 : total_completions = -ENXIO;
1812 [ + + ]: 355846459 : } else if (spdk_likely(total_completions >= 0)) {
1813 [ + - ]: 355846459 : total_completions += local_completions;
1814 : 18063411 : }
1815 : 18063411 : }
1816 : :
1817 : 333633092 : return total_completions;
1818 : : }
1819 : :
1820 : : void
1821 : 37443 : nvme_pcie_poll_group_check_disconnected_qpairs(struct spdk_nvme_transport_poll_group *tgroup,
1822 : : spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb)
1823 : : {
1824 : : struct spdk_nvme_qpair *qpair, *tmp_qpair;
1825 : :
1826 [ + + # # : 37445 : STAILQ_FOREACH_SAFE(qpair, &tgroup->disconnected_qpairs, poll_group_stailq, tmp_qpair) {
# # # # #
# # # # #
# # ]
1827 [ # # # # : 2 : disconnected_qpair_cb(qpair, tgroup->group->ctx);
# # # # #
# # # ]
1828 : 0 : }
1829 : 37443 : }
1830 : :
1831 : : int
1832 : 1137 : nvme_pcie_poll_group_destroy(struct spdk_nvme_transport_poll_group *tgroup)
1833 : : {
1834 [ + - + + : 1137 : if (!STAILQ_EMPTY(&tgroup->connected_qpairs) || !STAILQ_EMPTY(&tgroup->disconnected_qpairs)) {
+ - + - +
- + - + -
- + ]
1835 : 0 : return -EBUSY;
1836 : : }
1837 : :
1838 : 1137 : free(tgroup);
1839 : :
1840 : 1137 : return 0;
1841 : 24 : }
1842 : :
1843 : : int
1844 : 12 : nvme_pcie_poll_group_get_stats(struct spdk_nvme_transport_poll_group *tgroup,
1845 : : struct spdk_nvme_transport_poll_group_stat **_stats)
1846 : : {
1847 : : struct nvme_pcie_poll_group *group;
1848 : : struct spdk_nvme_transport_poll_group_stat *stats;
1849 : :
1850 [ + + + + ]: 12 : if (tgroup == NULL || _stats == NULL) {
1851 : 8 : SPDK_ERRLOG("Invalid stats or group pointer\n");
1852 : 8 : return -EINVAL;
1853 : : }
1854 : :
1855 : 4 : stats = calloc(1, sizeof(*stats));
1856 [ - + ]: 4 : if (!stats) {
1857 : 0 : SPDK_ERRLOG("Can't allocate memory for stats\n");
1858 : 0 : return -ENOMEM;
1859 : : }
1860 [ # # # # ]: 4 : stats->trtype = SPDK_NVME_TRANSPORT_PCIE;
1861 : 4 : group = SPDK_CONTAINEROF(tgroup, struct nvme_pcie_poll_group, group);
1862 [ - + - + : 4 : memcpy(&stats->pcie, &group->stats, sizeof(group->stats));
# # # # #
# ]
1863 : :
1864 [ # # ]: 4 : *_stats = stats;
1865 : :
1866 : 4 : return 0;
1867 : 3 : }
1868 : :
1869 : : void
1870 : 4 : nvme_pcie_poll_group_free_stats(struct spdk_nvme_transport_poll_group *tgroup,
1871 : : struct spdk_nvme_transport_poll_group_stat *stats)
1872 : : {
1873 : 4 : free(stats);
1874 : 4 : }
1875 : :
1876 : : static void
1877 : 1958 : nvme_pcie_trace(void)
1878 : : {
1879 : 1958 : struct spdk_trace_tpoint_opts opts[] = {
1880 : : {
1881 : : "NVME_PCIE_SUBMIT", TRACE_NVME_PCIE_SUBMIT,
1882 : : OWNER_TYPE_NVME_PCIE_QP, OBJECT_NVME_PCIE_REQ, 1,
1883 : : { { "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 },
1884 : : { "cid", SPDK_TRACE_ARG_TYPE_INT, 4 },
1885 : : { "opc", SPDK_TRACE_ARG_TYPE_INT, 4 },
1886 : : { "dw10", SPDK_TRACE_ARG_TYPE_PTR, 4 },
1887 : : { "dw11", SPDK_TRACE_ARG_TYPE_PTR, 4 },
1888 : : { "dw12", SPDK_TRACE_ARG_TYPE_PTR, 4 },
1889 : : { "qd", SPDK_TRACE_ARG_TYPE_INT, 4 }
1890 : : }
1891 : : },
1892 : : {
1893 : : "NVME_PCIE_COMPLETE", TRACE_NVME_PCIE_COMPLETE,
1894 : : OWNER_TYPE_NVME_PCIE_QP, OBJECT_NVME_PCIE_REQ, 0,
1895 : : { { "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 },
1896 : : { "cid", SPDK_TRACE_ARG_TYPE_INT, 4 },
1897 : : { "cpl", SPDK_TRACE_ARG_TYPE_PTR, 4 },
1898 : : { "qd", SPDK_TRACE_ARG_TYPE_INT, 4 }
1899 : : }
1900 : : },
1901 : : };
1902 : :
1903 : 1958 : spdk_trace_register_object(OBJECT_NVME_PCIE_REQ, 'p');
1904 : 1958 : spdk_trace_register_owner_type(OWNER_TYPE_NVME_PCIE_QP, 'q');
1905 : 1958 : spdk_trace_register_description_ext(opts, SPDK_COUNTOF(opts));
1906 : 1958 : }
1907 : 2541 : SPDK_TRACE_REGISTER_FN(nvme_pcie_trace, "nvme_pcie", TRACE_GROUP_NVME_PCIE)
|