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