Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2018 Intel Corporation. All rights reserved.
3 : : * Copyright (c) 2020 Mellanox Technologies LTD. All rights reserved.
4 : : * Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : : */
6 : :
7 : : /*
8 : : * NVMe/TCP transport
9 : : */
10 : :
11 : : #include "nvme_internal.h"
12 : :
13 : : #include "spdk/endian.h"
14 : : #include "spdk/likely.h"
15 : : #include "spdk/string.h"
16 : : #include "spdk/stdinc.h"
17 : : #include "spdk/crc32.h"
18 : : #include "spdk/assert.h"
19 : : #include "spdk/trace.h"
20 : : #include "spdk/util.h"
21 : : #include "spdk/nvmf.h"
22 : : #include "spdk/dma.h"
23 : :
24 : : #include "spdk_internal/nvme_tcp.h"
25 : : #include "spdk_internal/trace_defs.h"
26 : :
27 : : #define NVME_TCP_RW_BUFFER_SIZE 131072
28 : :
29 : : /* For async connect workloads, allow more time since we are more likely
30 : : * to be processing lots ICREQs at once.
31 : : */
32 : : #define ICREQ_TIMEOUT_SYNC 2 /* in seconds */
33 : : #define ICREQ_TIMEOUT_ASYNC 10 /* in seconds */
34 : :
35 : : #define NVME_TCP_HPDA_DEFAULT 0
36 : : #define NVME_TCP_MAX_R2T_DEFAULT 1
37 : : #define NVME_TCP_PDU_H2C_MIN_DATA_SIZE 4096
38 : :
39 : : /*
40 : : * Maximum value of transport_ack_timeout used by TCP controller
41 : : */
42 : : #define NVME_TCP_CTRLR_MAX_TRANSPORT_ACK_TIMEOUT 31
43 : :
44 : : enum nvme_tcp_qpair_state {
45 : : NVME_TCP_QPAIR_STATE_INVALID = 0,
46 : : NVME_TCP_QPAIR_STATE_INITIALIZING = 1,
47 : : NVME_TCP_QPAIR_STATE_FABRIC_CONNECT_SEND = 2,
48 : : NVME_TCP_QPAIR_STATE_FABRIC_CONNECT_POLL = 3,
49 : : NVME_TCP_QPAIR_STATE_AUTHENTICATING = 4,
50 : : NVME_TCP_QPAIR_STATE_RUNNING = 5,
51 : : NVME_TCP_QPAIR_STATE_EXITING = 6,
52 : : NVME_TCP_QPAIR_STATE_EXITED = 7,
53 : : };
54 : :
55 : : /* NVMe TCP transport extensions for spdk_nvme_ctrlr */
56 : : struct nvme_tcp_ctrlr {
57 : : struct spdk_nvme_ctrlr ctrlr;
58 : : char psk_identity[NVMF_PSK_IDENTITY_LEN];
59 : : uint8_t psk[SPDK_TLS_PSK_MAX_LEN];
60 : : int psk_size;
61 : : char *tls_cipher_suite;
62 : : };
63 : :
64 : : struct nvme_tcp_poll_group {
65 : : struct spdk_nvme_transport_poll_group group;
66 : : struct spdk_sock_group *sock_group;
67 : : uint32_t completions_per_qpair;
68 : : int64_t num_completions;
69 : :
70 : : TAILQ_HEAD(, nvme_tcp_qpair) needs_poll;
71 : : struct spdk_nvme_tcp_stat stats;
72 : : };
73 : :
74 : : /* NVMe TCP qpair extensions for spdk_nvme_qpair */
75 : : struct nvme_tcp_qpair {
76 : : struct spdk_nvme_qpair qpair;
77 : : struct spdk_sock *sock;
78 : :
79 : : TAILQ_HEAD(, nvme_tcp_req) free_reqs;
80 : : TAILQ_HEAD(, nvme_tcp_req) outstanding_reqs;
81 : :
82 : : TAILQ_HEAD(, nvme_tcp_pdu) send_queue;
83 : : struct nvme_tcp_pdu *recv_pdu;
84 : : struct nvme_tcp_pdu *send_pdu; /* only for error pdu and init pdu */
85 : : struct nvme_tcp_pdu *send_pdus; /* Used by tcp_reqs */
86 : : enum nvme_tcp_pdu_recv_state recv_state;
87 : : struct nvme_tcp_req *tcp_reqs;
88 : : struct spdk_nvme_tcp_stat *stats;
89 : :
90 : : uint16_t num_entries;
91 : : uint16_t async_complete;
92 : :
93 : : struct {
94 : : uint16_t host_hdgst_enable: 1;
95 : : uint16_t host_ddgst_enable: 1;
96 : : uint16_t icreq_send_ack: 1;
97 : : uint16_t in_connect_poll: 1;
98 : : uint16_t reserved: 12;
99 : : } flags;
100 : :
101 : : /** Specifies the maximum number of PDU-Data bytes per H2C Data Transfer PDU */
102 : : uint32_t maxh2cdata;
103 : :
104 : : uint32_t maxr2t;
105 : :
106 : : /* 0 based value, which is used to guide the padding */
107 : : uint8_t cpda;
108 : :
109 : : enum nvme_tcp_qpair_state state;
110 : :
111 : : TAILQ_ENTRY(nvme_tcp_qpair) link;
112 : : bool needs_poll;
113 : :
114 : : uint64_t icreq_timeout_tsc;
115 : :
116 : : bool shared_stats;
117 : : };
118 : :
119 : : enum nvme_tcp_req_state {
120 : : NVME_TCP_REQ_FREE,
121 : : NVME_TCP_REQ_ACTIVE,
122 : : NVME_TCP_REQ_ACTIVE_R2T,
123 : : };
124 : :
125 : : struct nvme_tcp_req {
126 : : struct nvme_request *req;
127 : : enum nvme_tcp_req_state state;
128 : : uint16_t cid;
129 : : uint16_t ttag;
130 : : uint32_t datao;
131 : : uint32_t expected_datao;
132 : : uint32_t r2tl_remain;
133 : : uint32_t active_r2ts;
134 : : /* Used to hold a value received from subsequent R2T while we are still
135 : : * waiting for H2C complete */
136 : : uint16_t ttag_r2t_next;
137 : : bool in_capsule_data;
138 : : /* It is used to track whether the req can be safely freed */
139 : : union {
140 : : uint8_t raw;
141 : : struct {
142 : : /* The last send operation completed - kernel released send buffer */
143 : : uint8_t send_ack : 1;
144 : : /* Data transfer completed - target send resp or last data bit */
145 : : uint8_t data_recv : 1;
146 : : /* tcp_req is waiting for completion of the previous send operation (buffer reclaim notification
147 : : * from kernel) to send H2C */
148 : : uint8_t h2c_send_waiting_ack : 1;
149 : : /* tcp_req received subsequent r2t while it is still waiting for send_ack.
150 : : * Rare case, actual when dealing with target that can send several R2T requests.
151 : : * SPDK TCP target sends 1 R2T for the whole data buffer */
152 : : uint8_t r2t_waiting_h2c_complete : 1;
153 : : /* Accel operation is in progress */
154 : : uint8_t in_progress_accel : 1;
155 : : uint8_t domain_in_use: 1;
156 : : uint8_t reserved : 2;
157 : : } bits;
158 : : } ordering;
159 : : struct nvme_tcp_pdu *pdu;
160 : : struct iovec iov[NVME_TCP_MAX_SGL_DESCRIPTORS];
161 : : uint32_t iovcnt;
162 : : /* Used to hold a value received from subsequent R2T while we are still
163 : : * waiting for H2C ack */
164 : : uint32_t r2tl_remain_next;
165 : : struct nvme_tcp_qpair *tqpair;
166 : : TAILQ_ENTRY(nvme_tcp_req) link;
167 : : struct spdk_nvme_cpl rsp;
168 : : uint8_t rsvd1[32];
169 : : };
170 : : SPDK_STATIC_ASSERT(sizeof(struct nvme_tcp_req) % SPDK_CACHE_LINE_SIZE == 0, "unaligned size");
171 : :
172 : : static struct spdk_nvme_tcp_stat g_dummy_stats = {};
173 : :
174 : : static void nvme_tcp_send_h2c_data(struct nvme_tcp_req *tcp_req);
175 : : static int64_t nvme_tcp_poll_group_process_completions(struct spdk_nvme_transport_poll_group
176 : : *tgroup, uint32_t completions_per_qpair, spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb);
177 : : static void nvme_tcp_icresp_handle(struct nvme_tcp_qpair *tqpair, struct nvme_tcp_pdu *pdu);
178 : : static void nvme_tcp_req_complete(struct nvme_tcp_req *tcp_req, struct nvme_tcp_qpair *tqpair,
179 : : struct spdk_nvme_cpl *rsp, bool print_on_error);
180 : :
181 : : static inline struct nvme_tcp_qpair *
182 : 116619115 : nvme_tcp_qpair(struct spdk_nvme_qpair *qpair)
183 : : {
184 [ + + + - : 116619115 : assert(qpair->trtype == SPDK_NVME_TRANSPORT_TCP);
+ - # # ]
185 : 116619115 : return SPDK_CONTAINEROF(qpair, struct nvme_tcp_qpair, qpair);
186 : : }
187 : :
188 : : static inline struct nvme_tcp_poll_group *
189 : 325796095 : nvme_tcp_poll_group(struct spdk_nvme_transport_poll_group *group)
190 : : {
191 : 325796095 : return SPDK_CONTAINEROF(group, struct nvme_tcp_poll_group, group);
192 : : }
193 : :
194 : : static inline struct nvme_tcp_ctrlr *
195 : 2199 : nvme_tcp_ctrlr(struct spdk_nvme_ctrlr *ctrlr)
196 : : {
197 [ + + + - : 2199 : assert(ctrlr->trid.trtype == SPDK_NVME_TRANSPORT_TCP);
+ - + - #
# ]
198 : 2199 : return SPDK_CONTAINEROF(ctrlr, struct nvme_tcp_ctrlr, ctrlr);
199 : : }
200 : :
201 : : static struct nvme_tcp_req *
202 : 15583971 : nvme_tcp_req_get(struct nvme_tcp_qpair *tqpair)
203 : : {
204 : : struct nvme_tcp_req *tcp_req;
205 : :
206 [ + - + - : 15583971 : tcp_req = TAILQ_FIRST(&tqpair->free_reqs);
+ - ]
207 [ + + ]: 15583971 : if (!tcp_req) {
208 : 348548 : return NULL;
209 : : }
210 : :
211 [ + + + - : 15235423 : assert(tcp_req->state == NVME_TCP_REQ_FREE);
+ - # # ]
212 [ + - + - ]: 15235423 : tcp_req->state = NVME_TCP_REQ_ACTIVE;
213 [ + + + - : 15235423 : TAILQ_REMOVE(&tqpair->free_reqs, tcp_req, link);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - # # #
# # # # #
# # # # +
- + - + -
+ - + - +
- + - ]
214 [ + - + - ]: 15235423 : tcp_req->datao = 0;
215 [ + - + - ]: 15235423 : tcp_req->expected_datao = 0;
216 [ + - + - ]: 15235423 : tcp_req->req = NULL;
217 [ + - + - ]: 15235423 : tcp_req->in_capsule_data = false;
218 [ + - + - ]: 15235423 : tcp_req->r2tl_remain = 0;
219 [ + - + - ]: 15235423 : tcp_req->r2tl_remain_next = 0;
220 [ + - + - ]: 15235423 : tcp_req->active_r2ts = 0;
221 [ + - + - ]: 15235423 : tcp_req->iovcnt = 0;
222 [ + - + - : 15235423 : tcp_req->ordering.raw = 0;
+ - ]
223 [ + + + - : 15235423 : memset(tcp_req->pdu, 0, sizeof(struct nvme_tcp_pdu));
+ - ]
224 [ + + + - ]: 15235423 : memset(&tcp_req->rsp, 0, sizeof(struct spdk_nvme_cpl));
225 : :
226 : 15235423 : return tcp_req;
227 : 21157 : }
228 : :
229 : : static void
230 : 15235447 : nvme_tcp_req_put(struct nvme_tcp_qpair *tqpair, struct nvme_tcp_req *tcp_req)
231 : : {
232 [ + + + - : 15235447 : assert(tcp_req->state != NVME_TCP_REQ_FREE);
+ - # # ]
233 [ + - + - ]: 15235447 : tcp_req->state = NVME_TCP_REQ_FREE;
234 [ + + + - : 15235447 : TAILQ_INSERT_HEAD(&tqpair->free_reqs, tcp_req, link);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- # # # #
# # # # #
# + - + -
+ - + - +
- + - + -
+ - ]
235 : 15235447 : }
236 : :
237 : : static inline void
238 : 674128 : nvme_tcp_accel_finish_sequence(struct nvme_tcp_poll_group *tgroup, struct nvme_tcp_req *treq,
239 : : void *seq, spdk_nvme_accel_completion_cb cb_fn, void *cb_arg)
240 : : {
241 [ # # # # : 674128 : struct spdk_nvme_poll_group *pg = tgroup->group.group;
# # ]
242 : :
243 [ # # # # : 674128 : treq->ordering.bits.in_progress_accel = 1;
# # ]
244 [ # # # # : 674128 : pg->accel_fn_table.finish_sequence(seq, cb_fn, cb_arg);
# # # # #
# ]
245 : 674128 : }
246 : :
247 : : static inline void
248 : 328967 : nvme_tcp_accel_reverse_sequence(struct nvme_tcp_poll_group *tgroup, void *seq)
249 : : {
250 [ # # # # : 328967 : struct spdk_nvme_poll_group *pg = tgroup->group.group;
# # ]
251 : :
252 [ # # # # : 328967 : pg->accel_fn_table.reverse_sequence(seq);
# # # # #
# ]
253 : 328967 : }
254 : :
255 : : static inline int
256 : 674128 : nvme_tcp_accel_append_crc32c(struct nvme_tcp_poll_group *tgroup, void **seq, uint32_t *dst,
257 : : struct iovec *iovs, uint32_t iovcnt, uint32_t seed,
258 : : spdk_nvme_accel_step_cb cb_fn, void *cb_arg)
259 : : {
260 [ # # # # : 674128 : struct spdk_nvme_poll_group *pg = tgroup->group.group;
# # ]
261 : :
262 [ # # # # : 674128 : return pg->accel_fn_table.append_crc32c(pg->ctx, seq, dst, iovs, iovcnt, NULL, NULL,
# # # # #
# # # #
# ]
263 : 0 : seed, cb_fn, cb_arg);
264 : : }
265 : :
266 : : static void
267 : 5418 : nvme_tcp_free_reqs(struct nvme_tcp_qpair *tqpair)
268 : : {
269 [ + - + - ]: 5418 : free(tqpair->tcp_reqs);
270 [ + - + - ]: 5418 : tqpair->tcp_reqs = NULL;
271 : :
272 [ + - + - ]: 5418 : spdk_free(tqpair->send_pdus);
273 [ + - + - ]: 5418 : tqpair->send_pdus = NULL;
274 : 5418 : }
275 : :
276 : : static int
277 : 5430 : nvme_tcp_alloc_reqs(struct nvme_tcp_qpair *tqpair)
278 : : {
279 : : uint16_t i;
280 : : struct nvme_tcp_req *tcp_req;
281 : :
282 [ + - + - : 5430 : tqpair->tcp_reqs = aligned_alloc(SPDK_CACHE_LINE_SIZE,
+ - ]
283 [ + - + - ]: 5430 : tqpair->num_entries * sizeof(*tcp_req));
284 [ + + + - : 5430 : if (tqpair->tcp_reqs == NULL) {
+ - ]
285 : 0 : SPDK_ERRLOG("Failed to allocate tcp_reqs on tqpair=%p\n", tqpair);
286 : 0 : goto fail;
287 : : }
288 : :
289 : : /* Add additional 2 member for the send_pdu, recv_pdu owned by the tqpair */
290 [ + - + - : 5430 : tqpair->send_pdus = spdk_zmalloc((tqpair->num_entries + 2) * sizeof(struct nvme_tcp_pdu),
+ - + - +
- ]
291 : : 0x1000, NULL,
292 : : SPDK_ENV_NUMA_ID_ANY, SPDK_MALLOC_DMA);
293 : :
294 [ + + + - : 5430 : if (tqpair->send_pdus == NULL) {
+ - ]
295 : 0 : SPDK_ERRLOG("Failed to allocate send_pdus on tqpair=%p\n", tqpair);
296 : 0 : goto fail;
297 : : }
298 : :
299 [ + + + - : 5430 : memset(tqpair->tcp_reqs, 0, tqpair->num_entries * sizeof(*tcp_req));
+ - + - +
- ]
300 [ + - + - : 5430 : TAILQ_INIT(&tqpair->send_queue);
+ - + - +
- + - + -
+ - ]
301 [ + - + - : 5430 : TAILQ_INIT(&tqpair->free_reqs);
+ - + - +
- + - + -
+ - ]
302 [ + - + - : 5430 : TAILQ_INIT(&tqpair->outstanding_reqs);
+ - + - +
- + - + -
+ - ]
303 [ + - + - : 5430 : tqpair->qpair.queue_depth = 0;
+ - ]
304 [ + + + - : 775940 : for (i = 0; i < tqpair->num_entries; i++) {
+ + ]
305 [ + - + - : 770510 : tcp_req = &tqpair->tcp_reqs[i];
+ - ]
306 [ + - + - ]: 770510 : tcp_req->cid = i;
307 [ + - + - ]: 770510 : tcp_req->tqpair = tqpair;
308 [ + - + - : 770510 : tcp_req->pdu = &tqpair->send_pdus[i];
+ - + - +
- ]
309 [ + - + - : 770510 : TAILQ_INSERT_TAIL(&tqpair->free_reqs, tcp_req, link);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
310 : 196370 : }
311 : :
312 [ + - + - : 5430 : tqpair->send_pdu = &tqpair->send_pdus[i];
+ - + - +
- ]
313 [ + - + - : 5430 : tqpair->recv_pdu = &tqpair->send_pdus[i + 1];
+ - + - +
- + - ]
314 : :
315 : 5430 : return 0;
316 : 0 : fail:
317 : 0 : nvme_tcp_free_reqs(tqpair);
318 : 0 : return -ENOMEM;
319 : 1665 : }
320 : :
321 : : static inline void
322 : 77444216 : nvme_tcp_qpair_set_recv_state(struct nvme_tcp_qpair *tqpair,
323 : : enum nvme_tcp_pdu_recv_state state)
324 : : {
325 [ + + + - : 77444216 : if (tqpair->recv_state == state) {
- + ]
326 : 527 : SPDK_ERRLOG("The recv state of tqpair=%p is same with the state(%d) to be set\n",
327 : : tqpair, state);
328 : 527 : return;
329 : : }
330 : :
331 [ + + ]: 77443689 : if (state == NVME_TCP_PDU_RECV_STATE_ERROR) {
332 [ + + # # : 52 : assert(TAILQ_EMPTY(&tqpair->outstanding_reqs));
# # # # #
# ]
333 : 1 : }
334 : :
335 [ - + - + ]: 77443689 : tqpair->recv_state = state;
336 : 74349 : }
337 : :
338 : : static void nvme_tcp_qpair_abort_reqs(struct spdk_nvme_qpair *qpair, uint32_t dnr);
339 : :
340 : : static void
341 : 21670 : nvme_tcp_ctrlr_disconnect_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair)
342 : : {
343 : 21670 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(qpair);
344 : : struct nvme_tcp_pdu *pdu;
345 : : int rc;
346 : : struct nvme_tcp_poll_group *group;
347 : :
348 [ + + + + : 21670 : if (tqpair->needs_poll) {
+ - + - ]
349 [ # # # # ]: 13 : group = nvme_tcp_poll_group(qpair->poll_group);
350 [ + + # # : 13 : TAILQ_REMOVE(&group->needs_poll, tqpair, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
351 [ # # # # ]: 13 : tqpair->needs_poll = false;
352 : 1 : }
353 : :
354 [ + - ]: 21670 : rc = spdk_sock_close(&tqpair->sock);
355 : :
356 [ + + + - : 21670 : if (tqpair->sock != NULL) {
- + ]
357 [ # # ]: 4 : SPDK_ERRLOG("tqpair=%p, errno=%d, rc=%d\n", tqpair, errno, rc);
358 : : /* Set it to NULL manually */
359 [ # # # # ]: 4 : tqpair->sock = NULL;
360 : 1 : }
361 : :
362 : : /* clear the send_queue */
363 [ + + + - : 21674 : while (!TAILQ_EMPTY(&tqpair->send_queue)) {
+ - - + ]
364 [ # # # # : 4 : pdu = TAILQ_FIRST(&tqpair->send_queue);
# # ]
365 : : /* Remove the pdu from the send_queue to prevent the wrong sending out
366 : : * in the next round connection
367 : : */
368 [ + + # # : 4 : TAILQ_REMOVE(&tqpair->send_queue, pdu, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
369 : : }
370 : :
371 [ + - ]: 21670 : nvme_tcp_qpair_abort_reqs(qpair, qpair->abort_dnr);
372 : :
373 : : /* If the qpair is marked as asynchronous, let it go through the process_completions() to
374 : : * let any outstanding requests (e.g. those with outstanding accel operations) complete.
375 : : * Otherwise, there's no way of waiting for them, so tqpair->outstanding_reqs has to be
376 : : * empty.
377 : : */
378 [ + + + + ]: 21670 : if (qpair->async) {
379 : 3662 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_QUIESCING);
380 : 832 : } else {
381 [ + + + - : 18008 : assert(TAILQ_EMPTY(&tqpair->outstanding_reqs));
+ - + - #
# ]
382 : 18008 : nvme_transport_ctrlr_disconnect_qpair_done(qpair);
383 : : }
384 : 21670 : }
385 : :
386 : : static int
387 : 5410 : nvme_tcp_ctrlr_delete_io_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair)
388 : : {
389 : 5410 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(qpair);
390 : :
391 [ + + # # ]: 5410 : assert(qpair != NULL);
392 [ + - ]: 5410 : nvme_tcp_qpair_abort_reqs(qpair, qpair->abort_dnr);
393 [ + + + - : 5410 : assert(TAILQ_EMPTY(&tqpair->outstanding_reqs));
+ - + - #
# ]
394 : :
395 : 5410 : nvme_qpair_deinit(qpair);
396 : 5410 : nvme_tcp_free_reqs(tqpair);
397 [ + + + + : 5410 : if (!tqpair->shared_stats) {
+ - - + ]
398 [ + - + - ]: 4347 : free(tqpair->stats);
399 : 1660 : }
400 : 5410 : free(tqpair);
401 : :
402 : 5410 : return 0;
403 : : }
404 : :
405 : : static int
406 : 2154 : nvme_tcp_ctrlr_enable(struct spdk_nvme_ctrlr *ctrlr)
407 : : {
408 : 2154 : return 0;
409 : : }
410 : :
411 : : static int
412 : 2191 : nvme_tcp_ctrlr_destruct(struct spdk_nvme_ctrlr *ctrlr)
413 : : {
414 : 2191 : struct nvme_tcp_ctrlr *tctrlr = nvme_tcp_ctrlr(ctrlr);
415 : :
416 [ + + + - : 2191 : if (ctrlr->adminq) {
+ - ]
417 [ + - + - ]: 2165 : nvme_tcp_ctrlr_delete_io_qpair(ctrlr, ctrlr->adminq);
418 : 828 : }
419 : :
420 : 2191 : nvme_ctrlr_destruct_finish(ctrlr);
421 : :
422 : 2191 : free(tctrlr);
423 : :
424 : 2191 : return 0;
425 : : }
426 : :
427 : : /* If there are queued requests, we assume they are queued because they are waiting
428 : : * for resources to be released. Those resources are almost certainly released in
429 : : * response to a PDU completing. However, to attempt to make forward progress
430 : : * the qpair needs to be polled and we can't rely on another network event to make
431 : : * that happen. Add it to a list of qpairs to poll regardless of network activity.
432 : : *
433 : : * Besides, when tqpair state is NVME_TCP_QPAIR_STATE_FABRIC_CONNECT_POLL or
434 : : * NVME_TCP_QPAIR_STATE_INITIALIZING, need to add it to needs_poll list too to make
435 : : * forward progress in case that the resources are released after icreq's or CONNECT's
436 : : * resp is processed. */
437 : : static void
438 : 16334536 : nvme_tcp_cond_schedule_qpair_polling(struct nvme_tcp_qpair *tqpair)
439 : : {
440 : : struct nvme_tcp_poll_group *pgroup;
441 : :
442 [ + + + + : 16334536 : if (tqpair->needs_poll || !tqpair->qpair.poll_group) {
+ + + - +
- + - + -
+ - ]
443 : 11582996 : return;
444 : : }
445 : :
446 [ + + # # : 4751540 : if (STAILQ_EMPTY(&tqpair->qpair.queued_req) &&
# # # # #
# # # ]
447 [ + + + - : 3535230 : spdk_likely(tqpair->state != NVME_TCP_QPAIR_STATE_FABRIC_CONNECT_POLL &&
# # # # #
# ]
448 : : tqpair->state != NVME_TCP_QPAIR_STATE_INITIALIZING)) {
449 : 3534962 : return;
450 : : }
451 : :
452 [ # # # # : 1216578 : pgroup = nvme_tcp_poll_group(tqpair->qpair.poll_group);
# # ]
453 [ # # # # : 1216578 : TAILQ_INSERT_TAIL(&pgroup->needs_poll, tqpair, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
454 [ # # # # ]: 1216578 : tqpair->needs_poll = true;
455 : 22807 : }
456 : :
457 : : static void
458 : 16005569 : pdu_write_done(void *cb_arg, int err)
459 : : {
460 : 16005569 : struct nvme_tcp_pdu *pdu = cb_arg;
461 [ + - + - ]: 16005569 : struct nvme_tcp_qpair *tqpair = pdu->qpair;
462 : :
463 : 16005569 : nvme_tcp_cond_schedule_qpair_polling(tqpair);
464 [ + + + - : 16005569 : TAILQ_REMOVE(&tqpair->send_queue, pdu, tailq);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
465 : :
466 [ + + ]: 16005569 : if (err != 0) {
467 [ # # # # : 1471 : nvme_transport_ctrlr_disconnect_qpair(tqpair->qpair.ctrlr, &tqpair->qpair);
# # # # ]
468 : 1471 : return;
469 : : }
470 : :
471 [ + + + - : 16004098 : assert(pdu->cb_fn != NULL);
+ - # # ]
472 [ + - + - : 16004098 : pdu->cb_fn(pdu->cb_arg);
- + + - +
- + - ]
473 : 22807 : }
474 : :
475 : : static void
476 : 0 : pdu_write_fail(struct nvme_tcp_pdu *pdu, int status)
477 : : {
478 [ # # # # ]: 0 : struct nvme_tcp_qpair *tqpair = pdu->qpair;
479 : :
480 : : /* This function is similar to pdu_write_done(), but it should be called before a PDU is
481 : : * sent over the socket */
482 [ # # # # : 0 : TAILQ_INSERT_TAIL(&tqpair->send_queue, pdu, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
483 : 0 : pdu_write_done(pdu, status);
484 : 0 : }
485 : :
486 : : static void
487 : 0 : pdu_seq_fail(struct nvme_tcp_pdu *pdu, int status)
488 : : {
489 [ # # # # ]: 0 : struct nvme_tcp_req *treq = pdu->req;
490 : :
491 : 0 : SPDK_ERRLOG("Failed to execute accel sequence: %d\n", status);
492 [ # # # # ]: 0 : nvme_tcp_cond_schedule_qpair_polling(pdu->qpair);
493 [ # # # # : 0 : treq->rsp.status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
# # # # ]
494 [ # # # # : 0 : nvme_tcp_req_complete(treq, treq->tqpair, &treq->rsp, true);
# # ]
495 : 0 : }
496 : :
497 : : static void
498 : 16005661 : _tcp_write_pdu(struct nvme_tcp_pdu *pdu)
499 : : {
500 : 16005661 : uint32_t mapped_length = 0;
501 [ + - + - ]: 16005661 : struct nvme_tcp_qpair *tqpair = pdu->qpair;
502 : :
503 [ + - + - : 16028491 : pdu->sock_req.iovcnt = nvme_tcp_build_iovs(pdu->iov, SPDK_COUNTOF(pdu->iov), pdu,
+ - + - ]
504 [ + - + - : 16005661 : (bool)tqpair->flags.host_hdgst_enable, (bool)tqpair->flags.host_ddgst_enable,
+ - + - ]
505 : : &mapped_length);
506 [ + - + - : 16005661 : TAILQ_INSERT_TAIL(&tqpair->send_queue, pdu, tailq);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
507 [ + + + - : 16005661 : if (spdk_unlikely(mapped_length < pdu->data_len)) {
+ - ]
508 [ # # # # ]: 0 : SPDK_ERRLOG("could not map the whole %u bytes (mapped only %u bytes)\n", pdu->data_len,
509 : : mapped_length);
510 : 0 : pdu_write_done(pdu, -EINVAL);
511 : 0 : return;
512 : : }
513 [ + - + - : 16005661 : pdu->sock_req.cb_fn = pdu_write_done;
+ - ]
514 [ + - + - : 16005661 : pdu->sock_req.cb_arg = pdu;
+ - ]
515 [ + - + - : 16005661 : tqpair->stats->submitted_requests++;
+ - ]
516 [ + - + - : 16005661 : spdk_sock_writev_async(tqpair->sock, &pdu->sock_req);
+ - ]
517 : 22830 : }
518 : :
519 : : static void
520 : 345161 : tcp_write_pdu_seq_cb(void *ctx, int status)
521 : : {
522 : 345161 : struct nvme_tcp_pdu *pdu = ctx;
523 [ # # # # ]: 345161 : struct nvme_tcp_req *treq = pdu->req;
524 [ # # # # ]: 345161 : struct nvme_request *req = treq->req;
525 : :
526 [ - + # # : 345161 : assert(treq->ordering.bits.in_progress_accel);
# # # # #
# ]
527 [ # # # # : 345161 : treq->ordering.bits.in_progress_accel = 0;
# # ]
528 : :
529 [ # # # # ]: 345161 : req->accel_sequence = NULL;
530 [ - + ]: 345161 : if (spdk_unlikely(status != 0)) {
531 : 0 : pdu_seq_fail(pdu, status);
532 : 0 : return;
533 : : }
534 : :
535 : 345161 : _tcp_write_pdu(pdu);
536 : 0 : }
537 : :
538 : : static void
539 : 16005661 : tcp_write_pdu(struct nvme_tcp_pdu *pdu)
540 : : {
541 [ + - + - ]: 16005661 : struct nvme_tcp_req *treq = pdu->req;
542 [ + - + - ]: 16005661 : struct nvme_tcp_qpair *tqpair = pdu->qpair;
543 : : struct nvme_tcp_poll_group *tgroup;
544 : : struct nvme_request *req;
545 : :
546 [ + + ]: 16005661 : if (spdk_likely(treq != NULL)) {
547 [ + - + - ]: 16000155 : req = treq->req;
548 [ + + + + : 16424252 : if (req->accel_sequence != NULL &&
- + # # ]
549 [ # # # # : 424097 : spdk_nvme_opc_get_data_transfer(req->cmd.opc) == SPDK_NVME_DATA_HOST_TO_CONTROLLER &&
# # ]
550 [ + + # # ]: 356527 : pdu->data_len > 0) {
551 [ - + # # : 345161 : assert(tqpair->qpair.poll_group != NULL);
# # # # #
# ]
552 [ # # # # : 345161 : tgroup = nvme_tcp_poll_group(tqpair->qpair.poll_group);
# # ]
553 [ # # # # ]: 345161 : nvme_tcp_accel_finish_sequence(tgroup, treq, req->accel_sequence,
554 : 0 : tcp_write_pdu_seq_cb, pdu);
555 : 345161 : return;
556 : : }
557 : 21157 : }
558 : :
559 : 15660500 : _tcp_write_pdu(pdu);
560 : 22830 : }
561 : :
562 : : static void
563 : 345161 : pdu_accel_seq_compute_crc32_done(void *cb_arg)
564 : : {
565 : 345161 : struct nvme_tcp_pdu *pdu = cb_arg;
566 : :
567 [ # # # # ]: 345161 : pdu->data_digest_crc32 ^= SPDK_CRC32C_XOR;
568 [ # # # # : 345161 : MAKE_DIGEST_WORD(pdu->data_digest, pdu->data_digest_crc32);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
569 : 345161 : }
570 : :
571 : : static bool
572 : 360712 : pdu_accel_compute_crc32(struct nvme_tcp_pdu *pdu)
573 : : {
574 [ # # # # ]: 360712 : struct nvme_tcp_qpair *tqpair = pdu->qpair;
575 [ # # # # : 360712 : struct nvme_tcp_poll_group *tgroup = nvme_tcp_poll_group(tqpair->qpair.poll_group);
# # ]
576 [ # # # # : 360712 : struct nvme_request *req = ((struct nvme_tcp_req *)pdu->req)->req;
# # # # ]
577 : : int rc;
578 : :
579 : : /* Only support this limited case for the first step */
580 [ + + - + : 360712 : if (spdk_unlikely(nvme_qpair_get_state(&tqpair->qpair) < NVME_QPAIR_CONNECTED ||
+ + - + #
# # # # #
# # # # ]
581 : : pdu->dif_ctx != NULL ||
582 : : pdu->data_len % SPDK_NVME_TCP_DIGEST_ALIGNMENT != 0)) {
583 : 112 : return false;
584 : : }
585 : :
586 [ + - # # : 360600 : if (tqpair->qpair.poll_group == NULL ||
# # # # #
# ]
587 [ + + # # : 360600 : tgroup->group.group->accel_fn_table.append_crc32c == NULL) {
# # # # #
# # # ]
588 : 15439 : return false;
589 : : }
590 : :
591 [ # # ]: 690322 : rc = nvme_tcp_accel_append_crc32c(tgroup, &req->accel_sequence,
592 [ # # ]: 0 : &pdu->data_digest_crc32,
593 [ # # # # : 345161 : pdu->data_iov, pdu->data_iovcnt, 0,
# # ]
594 : 0 : pdu_accel_seq_compute_crc32_done, pdu);
595 [ - + ]: 345161 : if (spdk_unlikely(rc != 0)) {
596 : : /* If accel is out of resources, fall back to non-accelerated crc32 */
597 [ # # ]: 0 : if (rc == -ENOMEM) {
598 : 0 : return false;
599 : : }
600 : :
601 : 0 : SPDK_ERRLOG("Failed to append crc32c operation: %d\n", rc);
602 : 0 : pdu_write_fail(pdu, rc);
603 : 0 : return true;
604 : : }
605 : :
606 : 345161 : tcp_write_pdu(pdu);
607 : :
608 : 345161 : return true;
609 : 3 : }
610 : :
611 : : static void
612 : 0 : pdu_compute_crc32_seq_cb(void *cb_arg, int status)
613 : : {
614 : 0 : struct nvme_tcp_pdu *pdu = cb_arg;
615 [ # # # # ]: 0 : struct nvme_tcp_req *treq = pdu->req;
616 [ # # # # ]: 0 : struct nvme_request *req = treq->req;
617 : : uint32_t crc32c;
618 : :
619 [ # # # # : 0 : assert(treq->ordering.bits.in_progress_accel);
# # # # #
# ]
620 [ # # # # : 0 : treq->ordering.bits.in_progress_accel = 0;
# # ]
621 : :
622 [ # # # # ]: 0 : req->accel_sequence = NULL;
623 [ # # ]: 0 : if (spdk_unlikely(status != 0)) {
624 : 0 : pdu_seq_fail(pdu, status);
625 : 0 : return;
626 : : }
627 : :
628 : 0 : crc32c = nvme_tcp_pdu_calc_data_digest(pdu);
629 : 0 : crc32c = crc32c ^ SPDK_CRC32C_XOR;
630 [ # # # # : 0 : MAKE_DIGEST_WORD(pdu->data_digest, crc32c);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
631 : :
632 : 0 : _tcp_write_pdu(pdu);
633 : 0 : }
634 : :
635 : : static void
636 : 16005661 : pdu_compute_crc32(struct nvme_tcp_pdu *pdu)
637 : : {
638 [ + - + - ]: 16005661 : struct nvme_tcp_qpair *tqpair = pdu->qpair;
639 : : struct nvme_tcp_poll_group *tgroup;
640 : : struct nvme_request *req;
641 : : uint32_t crc32c;
642 : :
643 : : /* Data Digest */
644 [ + + + + : 16008350 : if (pdu->data_len > 0 && g_nvme_tcp_ddgst[pdu->hdr.common.pdu_type] &&
+ + + + +
- + - + -
+ - + - +
- + - + -
+ - ]
645 [ + - + - ]: 2694 : tqpair->flags.host_ddgst_enable) {
646 [ + + ]: 360712 : if (pdu_accel_compute_crc32(pdu)) {
647 : 345161 : return;
648 : : }
649 : :
650 [ # # # # : 15551 : req = ((struct nvme_tcp_req *)pdu->req)->req;
# # # # ]
651 [ + + # # : 15551 : if (req->accel_sequence != NULL) {
# # ]
652 [ # # # # : 0 : tgroup = nvme_tcp_poll_group(tqpair->qpair.poll_group);
# # ]
653 [ # # # # : 0 : nvme_tcp_accel_finish_sequence(tgroup, pdu->req, req->accel_sequence,
# # # # ]
654 : 0 : pdu_compute_crc32_seq_cb, pdu);
655 : 0 : return;
656 : : }
657 : :
658 : 15551 : crc32c = nvme_tcp_pdu_calc_data_digest(pdu);
659 : 15551 : crc32c = crc32c ^ SPDK_CRC32C_XOR;
660 [ # # # # : 15551 : MAKE_DIGEST_WORD(pdu->data_digest, crc32c);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
661 : 3 : }
662 : :
663 : 15660500 : tcp_write_pdu(pdu);
664 : 22830 : }
665 : :
666 : : static int
667 : 16005661 : nvme_tcp_qpair_write_pdu(struct nvme_tcp_qpair *tqpair,
668 : : struct nvme_tcp_pdu *pdu,
669 : : nvme_tcp_qpair_xfer_complete_cb cb_fn,
670 : : void *cb_arg)
671 : : {
672 : : int hlen;
673 : : uint32_t crc32c;
674 : :
675 [ + - + - : 16005661 : hlen = pdu->hdr.common.hlen;
+ - + - ]
676 [ + - + - ]: 16005661 : pdu->cb_fn = cb_fn;
677 [ + - + - ]: 16005661 : pdu->cb_arg = cb_arg;
678 [ + - + - ]: 16005661 : pdu->qpair = tqpair;
679 : :
680 : : /* Header Digest */
681 [ + + + + : 16005661 : if (g_nvme_tcp_hdgst[pdu->hdr.common.pdu_type] && tqpair->flags.host_hdgst_enable) {
+ + + - +
- + - + -
+ - + + +
- + - -
+ ]
682 : 49543 : crc32c = nvme_tcp_pdu_calc_header_digest(pdu);
683 [ # # # # : 49543 : MAKE_DIGEST_WORD((uint8_t *)&pdu->hdr.raw[hlen], crc32c);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
684 : 3 : }
685 : :
686 : 16005661 : pdu_compute_crc32(pdu);
687 : :
688 : 16005661 : return 0;
689 : : }
690 : :
691 : : static int
692 : 17128111 : nvme_tcp_try_memory_translation(struct nvme_tcp_req *tcp_req, void **addr, uint32_t length)
693 : : {
694 [ + - + - ]: 17128111 : struct nvme_request *req = tcp_req->req;
695 : 17128111 : struct spdk_memory_domain_translation_result translation = {
696 : : .iov_count = 0,
697 : : .size = sizeof(translation)
698 : : };
699 : : int rc;
700 : :
701 [ + + + - : 17128111 : if (!tcp_req->ordering.bits.domain_in_use) {
+ - - + ]
702 : 17060541 : return 0;
703 : : }
704 : :
705 [ # # # # : 135140 : rc = spdk_memory_domain_translate_data(req->payload.opts->memory_domain,
# # # # #
# ]
706 [ # # # # : 67570 : req->payload.opts->memory_domain_ctx, spdk_memory_domain_get_system_domain(), NULL, *addr, length,
# # # # #
# # # ]
707 : : &translation);
708 [ + - - + : 67570 : if (spdk_unlikely(rc || translation.iov_count != 1)) {
# # ]
709 [ # # ]: 0 : SPDK_ERRLOG("DMA memory translation failed, rc %d, iov_count %u\n", rc, translation.iov_count);
710 : 0 : return -EFAULT;
711 : : }
712 : :
713 [ - + # # : 67570 : assert(length == translation.iov.iov_len);
# # # # ]
714 [ # # # # : 67570 : *addr = translation.iov.iov_base;
# # ]
715 : 67570 : return 0;
716 : 19812 : }
717 : :
718 : : /*
719 : : * Build SGL describing contiguous payload buffer.
720 : : */
721 : : static int
722 : 14928210 : nvme_tcp_build_contig_request(struct nvme_tcp_qpair *tqpair, struct nvme_tcp_req *tcp_req)
723 : : {
724 [ + - + - ]: 14928210 : struct nvme_request *req = tcp_req->req;
725 : :
726 : : /* ubsan complains about applying zero offset to null pointer if contig_or_cb_arg is NULL,
727 : : * so just double cast it to make it go away */
728 [ + - + - : 14928210 : void *addr = (void *)((uintptr_t)req->payload.contig_or_cb_arg + req->payload_offset);
+ - + - +
- ]
729 [ + - + - ]: 14928210 : size_t length = req->payload_size;
730 : : int rc;
731 : :
732 [ + + + + : 14928210 : SPDK_DEBUGLOG(nvme, "enter\n");
+ - ]
733 : :
734 [ + + + - : 14928210 : assert(nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_CONTIG);
# # ]
735 : 14928210 : rc = nvme_tcp_try_memory_translation(tcp_req, &addr, length);
736 [ - + ]: 14928210 : if (spdk_unlikely(rc)) {
737 : 0 : return rc;
738 : : }
739 : :
740 [ + - + - : 14928210 : tcp_req->iov[0].iov_base = addr;
+ - + - +
- ]
741 [ + - + - : 14928210 : tcp_req->iov[0].iov_len = length;
+ - + - +
- ]
742 [ + - + - ]: 14928210 : tcp_req->iovcnt = 1;
743 : 14928210 : return 0;
744 : 19787 : }
745 : :
746 : : /*
747 : : * Build SGL describing scattered payload buffer.
748 : : */
749 : : static int
750 : 358905 : nvme_tcp_build_sgl_request(struct nvme_tcp_qpair *tqpair, struct nvme_tcp_req *tcp_req)
751 : : {
752 : : int rc;
753 : 358905 : uint32_t length, remaining_size, iovcnt = 0, max_num_sgl;
754 [ # # # # ]: 358905 : struct nvme_request *req = tcp_req->req;
755 : :
756 [ + + - + : 358905 : SPDK_DEBUGLOG(nvme, "enter\n");
# # ]
757 : :
758 [ + + # # : 358905 : assert(req->payload_size != 0);
# # # # ]
759 [ + + # # : 358905 : assert(nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_SGL);
# # ]
760 [ + + # # : 358905 : assert(req->payload.reset_sgl_fn != NULL);
# # # # #
# ]
761 [ - + # # : 358905 : assert(req->payload.next_sge_fn != NULL);
# # # # #
# ]
762 [ # # # # : 358905 : req->payload.reset_sgl_fn(req->payload.contig_or_cb_arg, req->payload_offset);
# # # # #
# # # # #
# # # # #
# ]
763 : :
764 [ + + # # : 358905 : max_num_sgl = spdk_min(req->qpair->ctrlr->max_sges, NVME_TCP_MAX_SGL_DESCRIPTORS);
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
765 [ # # # # ]: 358905 : remaining_size = req->payload_size;
766 : :
767 : 6 : do {
768 : 2199876 : void *addr;
769 : :
770 [ # # # # : 2199901 : rc = req->payload.next_sge_fn(req->payload.contig_or_cb_arg, &addr, &length);
# # # # #
# # # # #
# # ]
771 [ + + ]: 2199901 : if (rc) {
772 : 0 : return -1;
773 : : }
774 : :
775 : 2199901 : rc = nvme_tcp_try_memory_translation(tcp_req, &addr, length);
776 [ + + ]: 2199901 : if (spdk_unlikely(rc)) {
777 : 0 : return rc;
778 : : }
779 : :
780 [ + + ]: 2199901 : length = spdk_min(length, remaining_size);
781 [ # # # # : 2199901 : tcp_req->iov[iovcnt].iov_base = addr;
# # # # #
# ]
782 [ # # # # : 2199901 : tcp_req->iov[iovcnt].iov_len = length;
# # # # #
# ]
783 : 2199901 : remaining_size -= length;
784 : 2199901 : iovcnt++;
785 [ + + + + ]: 2199901 : } while (remaining_size > 0 && iovcnt < max_num_sgl);
786 : :
787 : :
788 : : /* Should be impossible if we did our sgl checks properly up the stack, but do a sanity check here. */
789 [ + + ]: 358905 : if (remaining_size > 0) {
790 : 8 : SPDK_ERRLOG("Failed to construct tcp_req=%p, and the iovcnt=%u, remaining_size=%u\n",
791 : : tcp_req, iovcnt, remaining_size);
792 : 8 : return -1;
793 : : }
794 : :
795 [ # # # # ]: 358897 : tcp_req->iovcnt = iovcnt;
796 : :
797 : 358897 : return 0;
798 : 6 : }
799 : :
800 : : static int
801 : 15235427 : nvme_tcp_req_init(struct nvme_tcp_qpair *tqpair, struct nvme_request *req,
802 : : struct nvme_tcp_req *tcp_req)
803 : : {
804 [ + - + - : 15235427 : struct spdk_nvme_ctrlr *ctrlr = tqpair->qpair.ctrlr;
+ - ]
805 : 15235427 : int rc = 0;
806 : : enum spdk_nvme_data_transfer xfer;
807 : : uint32_t max_in_capsule_data_size;
808 : :
809 [ + - + - ]: 15235427 : tcp_req->req = req;
810 [ + + + + : 15235427 : tcp_req->ordering.bits.domain_in_use = (req->payload.opts && req->payload.opts->memory_domain);
+ - + - #
# # # # #
# # # # +
- + - +
- ]
811 : :
812 [ + - + - : 15235427 : req->cmd.cid = tcp_req->cid;
+ - + - +
- ]
813 [ + - + - ]: 15235427 : req->cmd.psdt = SPDK_NVME_PSDT_SGL_MPTR_CONTIG;
814 [ + - + - : 15235427 : req->cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_TRANSPORT_DATA_BLOCK;
+ - + - +
- + - ]
815 [ + - + - : 15235427 : req->cmd.dptr.sgl1.unkeyed.subtype = SPDK_NVME_SGL_SUBTYPE_TRANSPORT;
+ - + - +
- + - ]
816 [ + - + - : 15235427 : req->cmd.dptr.sgl1.unkeyed.length = req->payload_size;
+ - + - +
- + - + -
+ - + - ]
817 : :
818 [ + + + - : 15235427 : if (spdk_unlikely(req->cmd.opc == SPDK_NVME_OPC_FABRIC)) {
+ + ]
819 [ + - ]: 84063 : struct spdk_nvmf_capsule_cmd *nvmf_cmd = (struct spdk_nvmf_capsule_cmd *)&req->cmd;
820 : :
821 [ + - + - ]: 84063 : xfer = spdk_nvme_opc_get_data_transfer(nvmf_cmd->fctype);
822 : 9108 : } else {
823 [ + - + - ]: 15151364 : xfer = spdk_nvme_opc_get_data_transfer(req->cmd.opc);
824 : : }
825 : :
826 : : /* For c2h delay filling in the iov until the data arrives.
827 : : * For h2c some delay is also possible if data doesn't fit into cmd capsule (not implemented). */
828 [ + + + - ]: 15235427 : if (nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_CONTIG) {
829 [ + + ]: 14876534 : if (xfer != SPDK_NVME_DATA_CONTROLLER_TO_HOST) {
830 : 7413171 : rc = nvme_tcp_build_contig_request(tqpair, tcp_req);
831 : 16450 : }
832 [ + - # # ]: 380046 : } else if (nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_SGL) {
833 [ + + ]: 358893 : if (xfer != SPDK_NVME_DATA_CONTROLLER_TO_HOST) {
834 : 184976 : rc = nvme_tcp_build_sgl_request(tqpair, tcp_req);
835 : 3 : }
836 : 3 : } else {
837 : 0 : rc = -1;
838 : : }
839 : :
840 [ + + ]: 15235427 : if (rc) {
841 : 4 : return rc;
842 : : }
843 : :
844 [ + + ]: 15235423 : if (xfer == SPDK_NVME_DATA_HOST_TO_CONTROLLER) {
845 [ + - + - ]: 7074653 : max_in_capsule_data_size = ctrlr->ioccsz_bytes;
846 [ + + + + : 7074653 : if (spdk_unlikely((req->cmd.opc == SPDK_NVME_OPC_FABRIC) ||
+ + + - +
+ ]
847 : : nvme_qpair_is_admin_queue(&tqpair->qpair))) {
848 : 23731 : max_in_capsule_data_size = SPDK_NVME_TCP_IN_CAPSULE_DATA_MAX_SIZE;
849 : 3814 : }
850 : :
851 [ + + + - : 7074653 : if (req->payload_size <= max_in_capsule_data_size) {
- + ]
852 [ + - + - : 6308594 : req->cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
+ - + - +
- + - ]
853 [ + - + - : 6308594 : req->cmd.dptr.sgl1.unkeyed.subtype = SPDK_NVME_SGL_SUBTYPE_OFFSET;
+ - + - +
- + - ]
854 [ + - + - : 6308594 : req->cmd.dptr.sgl1.address = 0;
+ - + - +
- ]
855 [ + - + - ]: 6308594 : tcp_req->in_capsule_data = true;
856 : 4348 : }
857 : 4348 : }
858 : :
859 : 15235423 : return 0;
860 : 21156 : }
861 : :
862 : : static inline bool
863 : 31219063 : nvme_tcp_req_complete_safe(struct nvme_tcp_req *tcp_req)
864 : : {
865 [ + + + + : 31236902 : if (!(tcp_req->ordering.bits.send_ack && tcp_req->ordering.bits.data_recv &&
+ + + - +
- + - + -
+ + - + ]
866 [ + + + - : 15220378 : !tcp_req->ordering.bits.in_progress_accel)) {
+ - ]
867 : 15998685 : return false;
868 : : }
869 : :
870 [ + + + - : 15220378 : assert(tcp_req->state == NVME_TCP_REQ_ACTIVE);
+ - # # ]
871 [ + + + - : 15220378 : assert(tcp_req->tqpair != NULL);
+ - # # ]
872 [ + + + - : 15220378 : assert(tcp_req->req != NULL);
+ - # # ]
873 : :
874 [ + - + - : 15220378 : nvme_tcp_req_complete(tcp_req, tcp_req->tqpair, &tcp_req->rsp, true);
+ - ]
875 : 15220378 : return true;
876 : 38998 : }
877 : :
878 : : static void
879 : 15234223 : nvme_tcp_qpair_cmd_send_complete(void *cb_arg)
880 : : {
881 : 15234223 : struct nvme_tcp_req *tcp_req = cb_arg;
882 : :
883 [ + + + + : 15234223 : SPDK_DEBUGLOG(nvme, "tcp req %p, cid %u, qid %u\n", tcp_req, tcp_req->cid,
+ - # # #
# # # # #
# # # # #
# ]
884 : : tcp_req->tqpair->qpair.id);
885 [ + - + - : 15234223 : tcp_req->ordering.bits.send_ack = 1;
+ - ]
886 : : /* Handle the r2t case */
887 [ + + + - : 15234223 : if (spdk_unlikely(tcp_req->ordering.bits.h2c_send_waiting_ack)) {
+ - - + ]
888 [ # # # # : 0 : SPDK_DEBUGLOG(nvme, "tcp req %p, send H2C data\n", tcp_req);
# # ]
889 : 0 : nvme_tcp_send_h2c_data(tcp_req);
890 : 0 : } else {
891 [ + + + + : 15234223 : if (tcp_req->in_capsule_data && tcp_req->ordering.bits.domain_in_use) {
+ + + + +
- + - + -
- + ]
892 [ # # # # : 112408 : spdk_memory_domain_invalidate_data(tcp_req->req->payload.opts->memory_domain,
# # # # #
# # # #
# ]
893 [ # # # # : 56204 : tcp_req->req->payload.opts->memory_domain_ctx, tcp_req->iov, tcp_req->iovcnt);
# # # # #
# # # # #
# # # # #
# ]
894 : 0 : }
895 : :
896 : 15234223 : nvme_tcp_req_complete_safe(tcp_req);
897 : : }
898 : 15234223 : }
899 : :
900 : : static int
901 : 15235423 : nvme_tcp_qpair_capsule_cmd_send(struct nvme_tcp_qpair *tqpair,
902 : : struct nvme_tcp_req *tcp_req)
903 : : {
904 : : struct nvme_tcp_pdu *pdu;
905 : : struct spdk_nvme_tcp_cmd *capsule_cmd;
906 : 15235423 : uint32_t plen = 0, alignment;
907 : : uint8_t pdo;
908 : :
909 [ + + + + : 15235423 : SPDK_DEBUGLOG(nvme, "enter\n");
+ - ]
910 [ + - + - ]: 15235423 : pdu = tcp_req->pdu;
911 [ + - + - ]: 15235423 : pdu->req = tcp_req;
912 : :
913 [ + - + - ]: 15235423 : capsule_cmd = &pdu->hdr.capsule_cmd;
914 [ + - + - : 15235423 : capsule_cmd->common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_CAPSULE_CMD;
+ - ]
915 [ + - + - : 15235423 : plen = capsule_cmd->common.hlen = sizeof(*capsule_cmd);
+ - ]
916 [ + - + - : 15235423 : capsule_cmd->ccsqe = tcp_req->req->cmd;
+ - + - ]
917 : :
918 [ + + + + : 15235423 : SPDK_DEBUGLOG(nvme, "capsule_cmd cid=%u on tqpair(%p)\n", tcp_req->req->cmd.cid, tqpair);
+ - # # #
# # # # #
# # ]
919 : :
920 [ + + + - : 15235423 : if (tqpair->flags.host_hdgst_enable) {
+ - ]
921 [ + + - + : 49539 : SPDK_DEBUGLOG(nvme, "Header digest is enabled for capsule command on tcp_req=%p\n",
# # ]
922 : : tcp_req);
923 [ # # # # : 49539 : capsule_cmd->common.flags |= SPDK_NVME_TCP_CH_FLAGS_HDGSTF;
# # # # ]
924 : 49539 : plen += SPDK_NVME_TCP_DIGEST_LEN;
925 : 2 : }
926 : :
927 [ + + + + : 15235423 : if ((tcp_req->req->payload_size == 0) || !tcp_req->in_capsule_data) {
+ + + - +
+ + - + -
+ - + + ]
928 : 9021896 : goto end;
929 : : }
930 : :
931 : 6213527 : pdo = plen;
932 [ + - + - ]: 6213527 : pdu->padding_len = 0;
933 [ + + + - : 6213527 : if (tqpair->cpda) {
- + ]
934 [ - + # # : 4 : alignment = (tqpair->cpda + 1) << 2;
# # # # #
# ]
935 [ + + ]: 4 : if (alignment > plen) {
936 [ # # # # ]: 4 : pdu->padding_len = alignment - plen;
937 : 4 : pdo = alignment;
938 : 4 : plen = alignment;
939 : 1 : }
940 : 1 : }
941 : :
942 [ + - + - : 6213527 : capsule_cmd->common.pdo = pdo;
+ - ]
943 [ + - + - : 6213527 : plen += tcp_req->req->payload_size;
+ - + - ]
944 [ + + + - : 6213527 : if (tqpair->flags.host_ddgst_enable) {
+ - ]
945 [ # # # # : 287531 : capsule_cmd->common.flags |= SPDK_NVME_TCP_CH_FLAGS_DDGSTF;
# # # # ]
946 : 287531 : plen += SPDK_NVME_TCP_DIGEST_LEN;
947 : 2 : }
948 : :
949 [ + - + - ]: 6213527 : tcp_req->datao = 0;
950 [ + - + - : 6216220 : nvme_tcp_pdu_set_data_buf(pdu, tcp_req->iov, tcp_req->iovcnt,
+ - ]
951 [ + - + - : 6213527 : 0, tcp_req->req->payload_size);
+ - + - ]
952 : 15214268 : end:
953 [ + - + - : 15235423 : capsule_cmd->common.plen = plen;
+ - ]
954 : 15235423 : return nvme_tcp_qpair_write_pdu(tqpair, pdu, nvme_tcp_qpair_cmd_send_complete, tcp_req);
955 : :
956 : : }
957 : :
958 : : static int
959 : 15583959 : nvme_tcp_qpair_submit_request(struct spdk_nvme_qpair *qpair,
960 : : struct nvme_request *req)
961 : : {
962 : : struct nvme_tcp_qpair *tqpair;
963 : : struct nvme_tcp_req *tcp_req;
964 : :
965 : 15583959 : tqpair = nvme_tcp_qpair(qpair);
966 [ + + # # ]: 15583959 : assert(tqpair != NULL);
967 [ + + # # ]: 15583959 : assert(req != NULL);
968 : :
969 : 15583959 : tcp_req = nvme_tcp_req_get(tqpair);
970 [ + + ]: 15583959 : if (!tcp_req) {
971 [ # # # # : 348544 : tqpair->stats->queued_requests++;
# # ]
972 : : /* Inform the upper layer to try again later. */
973 : 348544 : return -EAGAIN;
974 : : }
975 : :
976 [ + + ]: 15235415 : if (spdk_unlikely(nvme_tcp_req_init(tqpair, req, tcp_req))) {
977 : 4 : SPDK_ERRLOG("nvme_tcp_req_init() failed\n");
978 : 4 : nvme_tcp_req_put(tqpair, tcp_req);
979 : 4 : return -1;
980 : : }
981 : :
982 [ + - + - ]: 15235411 : tqpair->qpair.queue_depth++;
983 [ + + + + : 15235411 : spdk_trace_record(TRACE_NVME_TCP_SUBMIT, qpair->id, 0, (uintptr_t)tcp_req->pdu, req->cb_arg,
+ - + - +
- + - + -
- + # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
984 : : (uint32_t)req->cmd.cid, (uint32_t)req->cmd.opc,
985 : : req->cmd.cdw10, req->cmd.cdw11, req->cmd.cdw12, tqpair->qpair.queue_depth);
986 [ + - + - : 15235411 : TAILQ_INSERT_TAIL(&tqpair->outstanding_reqs, tcp_req, link);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
987 : 15235411 : return nvme_tcp_qpair_capsule_cmd_send(tqpair, tcp_req);
988 : 21154 : }
989 : :
990 : : static int
991 : 2154 : nvme_tcp_qpair_reset(struct spdk_nvme_qpair *qpair)
992 : : {
993 : 2154 : return 0;
994 : : }
995 : :
996 : : static void
997 : 15235443 : nvme_tcp_req_complete(struct nvme_tcp_req *tcp_req,
998 : : struct nvme_tcp_qpair *tqpair,
999 : : struct spdk_nvme_cpl *rsp,
1000 : : bool print_on_error)
1001 : : {
1002 : 15214283 : struct spdk_nvme_cpl cpl;
1003 : : struct spdk_nvme_qpair *qpair;
1004 : : struct nvme_request *req;
1005 : : bool print_error;
1006 : :
1007 [ + + + - : 15235443 : assert(tcp_req->req != NULL);
+ - # # ]
1008 [ + - + - ]: 15235443 : req = tcp_req->req;
1009 [ + - + - ]: 15235443 : qpair = req->qpair;
1010 : :
1011 [ + + + + : 15235443 : SPDK_DEBUGLOG(nvme, "complete tcp_req(%p) on tqpair=%p\n", tcp_req, tqpair);
+ - ]
1012 : :
1013 [ + + + - : 15235443 : if (!tcp_req->tqpair->qpair.in_completion_context) {
+ - + - +
+ ]
1014 [ + - + - : 339467 : tcp_req->tqpair->async_complete++;
+ - ]
1015 : 3320 : }
1016 : :
1017 : : /* Cache arguments to be passed to nvme_complete_request since tcp_req can be zeroed when released */
1018 [ + - + - ]: 15235443 : memcpy(&cpl, rsp, sizeof(cpl));
1019 : :
1020 [ + + + + : 15235443 : if (spdk_unlikely(spdk_nvme_cpl_is_error(rsp))) {
+ - + + +
- + - + -
+ + ]
1021 [ + + + + : 463661 : print_error = print_on_error && !qpair->ctrlr->opts.disable_error_logging;
+ + + - +
- + - + -
+ - ]
1022 : :
1023 [ + + + + ]: 463661 : if (print_error) {
1024 [ + - ]: 407850 : spdk_nvme_qpair_print_command(qpair, &req->cmd);
1025 : 1995 : }
1026 : :
1027 [ + + + + : 463661 : if (print_error || SPDK_DEBUGLOG_FLAG_ENABLED("nvme")) {
- + ]
1028 : 407874 : spdk_nvme_qpair_print_completion(qpair, rsp);
1029 : 1995 : }
1030 : 5307 : }
1031 : :
1032 [ + - + - ]: 15235443 : tqpair->qpair.queue_depth--;
1033 [ + + + + : 15235443 : spdk_trace_record(TRACE_NVME_TCP_COMPLETE, qpair->id, 0, (uintptr_t)tcp_req->pdu, req->cb_arg,
+ - + - +
- + - + -
- + # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1034 : : (uint32_t)req->cmd.cid, (uint32_t)cpl.status_raw, tqpair->qpair.queue_depth);
1035 [ + + + - : 15235443 : TAILQ_REMOVE(&tcp_req->tqpair->outstanding_reqs, tcp_req, link);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
1036 : 15235443 : nvme_tcp_req_put(tqpair, tcp_req);
1037 [ + - + - : 15235443 : nvme_complete_request(req->cb_fn, req->cb_arg, req->qpair, req, &cpl);
+ - + - +
- + - ]
1038 : 15235443 : }
1039 : :
1040 : : static void
1041 : 27080 : nvme_tcp_qpair_abort_reqs(struct spdk_nvme_qpair *qpair, uint32_t dnr)
1042 : : {
1043 : : struct nvme_tcp_req *tcp_req, *tmp;
1044 : 27080 : struct spdk_nvme_cpl cpl = {};
1045 : 27080 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(qpair);
1046 : :
1047 [ + - + - : 27080 : cpl.sqid = qpair->id;
+ - ]
1048 [ + - + - ]: 27080 : cpl.status.sc = SPDK_NVME_SC_ABORTED_SQ_DELETION;
1049 [ + - + - ]: 27080 : cpl.status.sct = SPDK_NVME_SCT_GENERIC;
1050 [ + - + - ]: 27080 : cpl.status.dnr = dnr;
1051 : :
1052 [ + + + + : 33824 : TAILQ_FOREACH_SAFE(tcp_req, &tqpair->outstanding_reqs, link, tmp) {
+ - + - #
# # # # #
+ - ]
1053 : : /* We cannot abort requests with accel operations in progress */
1054 [ + + # # : 6744 : if (tcp_req->ordering.bits.in_progress_accel) {
# # # # ]
1055 : 8 : continue;
1056 : : }
1057 : :
1058 : 6736 : nvme_tcp_req_complete(tcp_req, tqpair, &cpl, true);
1059 : 2 : }
1060 : 27080 : }
1061 : :
1062 : : static void
1063 : 1 : nvme_tcp_qpair_send_h2c_term_req_complete(void *cb_arg)
1064 : : {
1065 : 1 : struct nvme_tcp_qpair *tqpair = cb_arg;
1066 : :
1067 [ # # # # ]: 1 : tqpair->state = NVME_TCP_QPAIR_STATE_EXITING;
1068 : 1 : }
1069 : :
1070 : : static void
1071 : 67 : nvme_tcp_qpair_send_h2c_term_req(struct nvme_tcp_qpair *tqpair, struct nvme_tcp_pdu *pdu,
1072 : : enum spdk_nvme_tcp_term_req_fes fes, uint32_t error_offset)
1073 : : {
1074 : : struct nvme_tcp_pdu *rsp_pdu;
1075 : : struct spdk_nvme_tcp_term_req_hdr *h2c_term_req;
1076 : 67 : uint32_t h2c_term_req_hdr_len = sizeof(*h2c_term_req);
1077 : : uint8_t copy_len;
1078 : :
1079 [ # # # # ]: 67 : rsp_pdu = tqpair->send_pdu;
1080 [ - + ]: 67 : memset(rsp_pdu, 0, sizeof(*rsp_pdu));
1081 [ # # # # ]: 67 : h2c_term_req = &rsp_pdu->hdr.term_req;
1082 [ # # # # : 67 : h2c_term_req->common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_H2C_TERM_REQ;
# # ]
1083 [ # # # # : 67 : h2c_term_req->common.hlen = h2c_term_req_hdr_len;
# # ]
1084 : :
1085 [ + + - + ]: 67 : if ((fes == SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD) ||
1086 : 2 : (fes == SPDK_NVME_TCP_TERM_REQ_FES_INVALID_DATA_UNSUPPORTED_PARAMETER)) {
1087 [ # # # # : 59 : DSET32(&h2c_term_req->fei, error_offset);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1088 : 13 : }
1089 : :
1090 [ # # # # : 67 : copy_len = pdu->hdr.common.hlen;
# # # # ]
1091 [ + + ]: 67 : if (copy_len > SPDK_NVME_TCP_TERM_REQ_ERROR_DATA_MAX_SIZE) {
1092 : 4 : copy_len = SPDK_NVME_TCP_TERM_REQ_ERROR_DATA_MAX_SIZE;
1093 : 1 : }
1094 : :
1095 : : /* Copy the error info into the buffer */
1096 [ - + - + : 67 : memcpy((uint8_t *)rsp_pdu->hdr.raw + h2c_term_req_hdr_len, pdu->hdr.raw, copy_len);
# # # # #
# # # #
# ]
1097 [ # # # # : 67 : nvme_tcp_pdu_set_data(rsp_pdu, (uint8_t *)rsp_pdu->hdr.raw + h2c_term_req_hdr_len, copy_len);
# # ]
1098 : :
1099 : : /* Contain the header len of the wrong received pdu */
1100 [ # # # # : 67 : h2c_term_req->common.plen = h2c_term_req->common.hlen + copy_len;
# # # # #
# # # ]
1101 : 67 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_QUIESCING);
1102 : 67 : nvme_tcp_qpair_write_pdu(tqpair, rsp_pdu, nvme_tcp_qpair_send_h2c_term_req_complete, tqpair);
1103 : 67 : }
1104 : :
1105 : : static bool
1106 : 23243257 : nvme_tcp_qpair_recv_state_valid(struct nvme_tcp_qpair *tqpair)
1107 : : {
1108 [ + + + - : 23243257 : switch (tqpair->state) {
+ - ]
1109 : 23222072 : case NVME_TCP_QPAIR_STATE_FABRIC_CONNECT_SEND:
1110 : : case NVME_TCP_QPAIR_STATE_FABRIC_CONNECT_POLL:
1111 : : case NVME_TCP_QPAIR_STATE_AUTHENTICATING:
1112 : : case NVME_TCP_QPAIR_STATE_RUNNING:
1113 : 23243253 : return true;
1114 : 3 : default:
1115 : 4 : return false;
1116 : : }
1117 : 21182 : }
1118 : :
1119 : : static void
1120 : 23248693 : nvme_tcp_pdu_ch_handle(struct nvme_tcp_qpair *tqpair)
1121 : : {
1122 : : struct nvme_tcp_pdu *pdu;
1123 : 23248693 : uint32_t error_offset = 0;
1124 : : enum spdk_nvme_tcp_term_req_fes fes;
1125 : 23248693 : uint32_t expected_hlen, hd_len = 0;
1126 : 23248693 : bool plen_error = false;
1127 : :
1128 [ + - + - ]: 23248693 : pdu = tqpair->recv_pdu;
1129 : :
1130 [ + + + + : 23248693 : SPDK_DEBUGLOG(nvme, "pdu type = %d\n", pdu->hdr.common.pdu_type);
+ - # # #
# # # #
# ]
1131 [ + + + - : 23248693 : if (pdu->hdr.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_IC_RESP) {
+ - + - +
+ ]
1132 [ + + + - : 5436 : if (tqpair->state != NVME_TCP_QPAIR_STATE_INVALID) {
- + ]
1133 : 4 : SPDK_ERRLOG("Already received IC_RESP PDU, and we should reject this pdu=%p\n", pdu);
1134 : 4 : fes = SPDK_NVME_TCP_TERM_REQ_FES_PDU_SEQUENCE_ERROR;
1135 : 4 : goto err;
1136 : : }
1137 : 5432 : expected_hlen = sizeof(struct spdk_nvme_tcp_ic_resp);
1138 [ + + + - : 5432 : if (pdu->hdr.common.plen != expected_hlen) {
+ - + - +
- ]
1139 : 4 : plen_error = true;
1140 : 1 : }
1141 : 1660 : } else {
1142 [ + + ]: 23243257 : if (spdk_unlikely(!nvme_tcp_qpair_recv_state_valid(tqpair))) {
1143 : 4 : SPDK_ERRLOG("The TCP/IP tqpair connection is not negotiated\n");
1144 : 4 : fes = SPDK_NVME_TCP_TERM_REQ_FES_PDU_SEQUENCE_ERROR;
1145 : 4 : goto err;
1146 : : }
1147 : :
1148 [ + + + + : 23243253 : switch (pdu->hdr.common.pdu_type) {
+ - + - -
+ + - - ]
1149 : 14771710 : case SPDK_NVME_TCP_PDU_TYPE_CAPSULE_RESP:
1150 : 14789550 : expected_hlen = sizeof(struct spdk_nvme_tcp_rsp);
1151 [ + + + - : 14789550 : if (pdu->hdr.common.flags & SPDK_NVME_TCP_CH_FLAGS_HDGSTF) {
+ - + - +
- + - ]
1152 : 49511 : hd_len = SPDK_NVME_TCP_DIGEST_LEN;
1153 : 1 : }
1154 : :
1155 [ + + + - : 14789550 : if (pdu->hdr.common.plen != (expected_hlen + hd_len)) {
+ - + - +
- ]
1156 : 4 : plen_error = true;
1157 : 1 : }
1158 : 14789550 : break;
1159 : 7685622 : case SPDK_NVME_TCP_PDU_TYPE_C2H_DATA:
1160 : 7688960 : expected_hlen = sizeof(struct spdk_nvme_tcp_c2h_data_hdr);
1161 [ + + + - : 7688960 : if (pdu->hdr.common.plen < pdu->hdr.common.pdo) {
+ - + - +
- + - + -
+ - + - ]
1162 : 4 : plen_error = true;
1163 : 1 : }
1164 : 7688960 : break;
1165 : 3 : case SPDK_NVME_TCP_PDU_TYPE_C2H_TERM_REQ:
1166 : 4 : expected_hlen = sizeof(struct spdk_nvme_tcp_term_req_hdr);
1167 [ - + # # : 4 : if ((pdu->hdr.common.plen <= expected_hlen) ||
# # # # #
# # # ]
1168 [ # # # # : 0 : (pdu->hdr.common.plen > SPDK_NVME_TCP_TERM_REQ_PDU_MAX_SIZE)) {
# # # # ]
1169 : 4 : plen_error = true;
1170 : 1 : }
1171 : 4 : break;
1172 : 764727 : case SPDK_NVME_TCP_PDU_TYPE_R2T:
1173 : 764728 : expected_hlen = sizeof(struct spdk_nvme_tcp_r2t_hdr);
1174 [ + + # # : 764728 : if (pdu->hdr.common.flags & SPDK_NVME_TCP_CH_FLAGS_HDGSTF) {
# # # # #
# # # ]
1175 : 4 : hd_len = SPDK_NVME_TCP_DIGEST_LEN;
1176 : 1 : }
1177 : :
1178 [ + + # # : 764728 : if (pdu->hdr.common.plen != (expected_hlen + hd_len)) {
# # # # #
# ]
1179 : 4 : plen_error = true;
1180 : 1 : }
1181 : 764728 : break;
1182 : :
1183 : 10 : default:
1184 [ # # # # : 11 : SPDK_ERRLOG("Unexpected PDU type 0x%02x\n", tqpair->recv_pdu->hdr.common.pdu_type);
# # # # #
# # # ]
1185 : 11 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1186 : 11 : error_offset = offsetof(struct spdk_nvme_tcp_common_pdu_hdr, pdu_type);
1187 : 11 : goto err;
1188 : : }
1189 : : }
1190 : :
1191 [ + + + - : 23248674 : if (pdu->hdr.common.hlen != expected_hlen) {
+ - + - -
+ ]
1192 [ # # # # : 4 : SPDK_ERRLOG("Expected PDU header length %u, got %u\n",
# # # # ]
1193 : : expected_hlen, pdu->hdr.common.hlen);
1194 : 4 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1195 : 4 : error_offset = offsetof(struct spdk_nvme_tcp_common_pdu_hdr, hlen);
1196 : 4 : goto err;
1197 : :
1198 [ + + - + ]: 23248670 : } else if (plen_error) {
1199 : 20 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1200 : 20 : error_offset = offsetof(struct spdk_nvme_tcp_common_pdu_hdr, plen);
1201 : 20 : goto err;
1202 : : } else {
1203 : 23248650 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PSH);
1204 [ + - + - : 23248650 : nvme_tcp_pdu_calc_psh_len(tqpair->recv_pdu, tqpair->flags.host_hdgst_enable);
+ - + - ]
1205 : 23248650 : return;
1206 : : }
1207 : 34 : err:
1208 : 43 : nvme_tcp_qpair_send_h2c_term_req(tqpair, pdu, fes, error_offset);
1209 : 22843 : }
1210 : :
1211 : : static struct nvme_tcp_req *
1212 : 23243234 : get_nvme_active_req_by_cid(struct nvme_tcp_qpair *tqpair, uint32_t cid)
1213 : : {
1214 [ + + # # ]: 23243234 : assert(tqpair != NULL);
1215 [ + + + + : 23243234 : if ((cid >= tqpair->num_entries) || (tqpair->tcp_reqs[cid].state == NVME_TCP_REQ_FREE)) {
+ - + - +
- + - + -
+ - - + ]
1216 : 4 : return NULL;
1217 : : }
1218 : :
1219 [ + - + - : 23243230 : return &tqpair->tcp_reqs[cid];
+ - ]
1220 : 21178 : }
1221 : :
1222 : : static void
1223 : 328967 : nvme_tcp_recv_payload_seq_cb(void *cb_arg, int status)
1224 : : {
1225 : 328967 : struct nvme_tcp_req *treq = cb_arg;
1226 [ # # # # ]: 328967 : struct nvme_request *req = treq->req;
1227 [ # # # # ]: 328967 : struct nvme_tcp_qpair *tqpair = treq->tqpair;
1228 : :
1229 [ - + # # : 328967 : assert(treq->ordering.bits.in_progress_accel);
# # # # #
# ]
1230 [ # # # # : 328967 : treq->ordering.bits.in_progress_accel = 0;
# # ]
1231 : :
1232 : 328967 : nvme_tcp_cond_schedule_qpair_polling(tqpair);
1233 : :
1234 [ # # # # ]: 328967 : req->accel_sequence = NULL;
1235 [ - + ]: 328967 : if (spdk_unlikely(status != 0)) {
1236 [ # # # # ]: 0 : pdu_seq_fail(treq->pdu, status);
1237 : 0 : return;
1238 : : }
1239 : :
1240 : 328967 : nvme_tcp_req_complete_safe(treq);
1241 : 0 : }
1242 : :
1243 : : static void
1244 : 7688966 : nvme_tcp_c2h_data_payload_handle(struct nvme_tcp_qpair *tqpair,
1245 : : struct nvme_tcp_pdu *pdu, uint32_t *reaped)
1246 : : {
1247 : : struct nvme_tcp_req *tcp_req;
1248 : : struct nvme_tcp_poll_group *tgroup;
1249 : : struct spdk_nvme_tcp_c2h_data_hdr *c2h_data;
1250 : : uint8_t flags;
1251 : :
1252 [ + - + - ]: 7688966 : tcp_req = pdu->req;
1253 [ + + # # ]: 7688966 : assert(tcp_req != NULL);
1254 : :
1255 [ + + + + : 7688966 : SPDK_DEBUGLOG(nvme, "enter\n");
+ - ]
1256 [ + - + - ]: 7688966 : c2h_data = &pdu->hdr.c2h_data;
1257 [ + - + - : 7688966 : tcp_req->datao += pdu->data_len;
+ - + - ]
1258 [ + - + - : 7688966 : flags = c2h_data->common.flags;
+ - ]
1259 : :
1260 [ + + - + ]: 7688966 : if (flags & SPDK_NVME_TCP_C2H_DATA_FLAGS_LAST_PDU) {
1261 [ + + + - : 7469002 : if (tcp_req->datao == tcp_req->req->payload_size) {
+ - + - +
- + - +
- ]
1262 [ + - + - : 7468430 : tcp_req->rsp.status.p = 0;
+ - + - ]
1263 : 3339 : } else {
1264 [ # # # # : 572 : tcp_req->rsp.status.p = 1;
# # # # ]
1265 : : }
1266 : :
1267 [ + - + - : 7469002 : tcp_req->rsp.cid = tcp_req->cid;
+ - + - +
- ]
1268 [ + - + - : 7469002 : tcp_req->rsp.sqid = tqpair->qpair.id;
+ - + - +
- + - ]
1269 [ + + + - ]: 7469002 : if (flags & SPDK_NVME_TCP_C2H_DATA_FLAGS_SUCCESS) {
1270 [ # # # # : 430816 : tcp_req->ordering.bits.data_recv = 1;
# # ]
1271 [ + + # # : 430816 : if (tcp_req->req->accel_sequence != NULL) {
# # # # #
# ]
1272 [ # # # # : 67570 : tgroup = nvme_tcp_poll_group(tqpair->qpair.poll_group);
# # ]
1273 [ # # # # : 67570 : nvme_tcp_accel_reverse_sequence(tgroup, tcp_req->req->accel_sequence);
# # # # ]
1274 : 67570 : nvme_tcp_accel_finish_sequence(tgroup, tcp_req,
1275 [ # # # # : 67570 : tcp_req->req->accel_sequence,
# # # # ]
1276 : : nvme_tcp_recv_payload_seq_cb,
1277 : 0 : tcp_req);
1278 : 67570 : return;
1279 : : }
1280 : :
1281 [ + + ]: 363246 : if (nvme_tcp_req_complete_safe(tcp_req)) {
1282 : 363246 : (*reaped)++;
1283 : 3 : }
1284 : 3 : }
1285 : 3341 : }
1286 : 3341 : }
1287 : :
1288 : : static const char *spdk_nvme_tcp_term_req_fes_str[] = {
1289 : : "Invalid PDU Header Field",
1290 : : "PDU Sequence Error",
1291 : : "Header Digest Error",
1292 : : "Data Transfer Out of Range",
1293 : : "Data Transfer Limit Exceeded",
1294 : : "Unsupported parameter",
1295 : : };
1296 : :
1297 : : static void
1298 : 8 : nvme_tcp_c2h_term_req_dump(struct spdk_nvme_tcp_term_req_hdr *c2h_term_req)
1299 : : {
1300 [ # # # # : 8 : SPDK_ERRLOG("Error info of pdu(%p): %s\n", c2h_term_req,
# # # # #
# ]
1301 : : spdk_nvme_tcp_term_req_fes_str[c2h_term_req->fes]);
1302 [ - + # # : 8 : if ((c2h_term_req->fes == SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD) ||
# # # # ]
1303 [ # # # # ]: 0 : (c2h_term_req->fes == SPDK_NVME_TCP_TERM_REQ_FES_INVALID_DATA_UNSUPPORTED_PARAMETER)) {
1304 [ + + - + : 8 : SPDK_DEBUGLOG(nvme, "The offset from the start of the PDU header is %u\n",
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
1305 : : DGET32(c2h_term_req->fei));
1306 : 2 : }
1307 : : /* we may also need to dump some other info here */
1308 : 8 : }
1309 : :
1310 : : static void
1311 : 8 : nvme_tcp_c2h_term_req_payload_handle(struct nvme_tcp_qpair *tqpair,
1312 : : struct nvme_tcp_pdu *pdu)
1313 : : {
1314 [ # # # # ]: 8 : nvme_tcp_c2h_term_req_dump(&pdu->hdr.term_req);
1315 : 8 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_QUIESCING);
1316 : 8 : }
1317 : :
1318 : : static void
1319 : 7359991 : _nvme_tcp_pdu_payload_handle(struct nvme_tcp_qpair *tqpair, uint32_t *reaped)
1320 : : {
1321 : : struct nvme_tcp_pdu *pdu;
1322 : :
1323 [ + + # # ]: 7359991 : assert(tqpair != NULL);
1324 [ + - + - ]: 7359991 : pdu = tqpair->recv_pdu;
1325 : :
1326 [ + + + - : 7359991 : switch (pdu->hdr.common.pdu_type) {
+ - + - -
+ - ]
1327 : 7356649 : case SPDK_NVME_TCP_PDU_TYPE_C2H_DATA:
1328 : 7359987 : nvme_tcp_c2h_data_payload_handle(tqpair, pdu, reaped);
1329 : 7359987 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY);
1330 : 7359987 : break;
1331 : :
1332 : 3 : case SPDK_NVME_TCP_PDU_TYPE_C2H_TERM_REQ:
1333 : 4 : nvme_tcp_c2h_term_req_payload_handle(tqpair, pdu);
1334 : 4 : break;
1335 : :
1336 : 0 : default:
1337 : : /* The code should not go to here */
1338 : 0 : SPDK_ERRLOG("The code should not go to here\n");
1339 : 0 : break;
1340 : : }
1341 : 7359991 : }
1342 : :
1343 : : static void
1344 : 328967 : nvme_tcp_req_copy_pdu(struct nvme_tcp_req *treq, struct nvme_tcp_pdu *pdu)
1345 : : {
1346 [ # # # # : 328967 : treq->pdu->hdr = pdu->hdr;
# # # # ]
1347 [ # # # # : 328967 : treq->pdu->req = treq;
# # # # ]
1348 [ # # # # : 328967 : memcpy(treq->pdu->data_digest, pdu->data_digest, sizeof(pdu->data_digest));
# # # # #
# # # ]
1349 [ - + - + : 328967 : memcpy(treq->pdu->data_iov, pdu->data_iov, sizeof(pdu->data_iov[0]) * pdu->data_iovcnt);
# # # # #
# # # # #
# # ]
1350 [ # # # # : 328967 : treq->pdu->data_iovcnt = pdu->data_iovcnt;
# # # # #
# # # ]
1351 [ # # # # : 328967 : treq->pdu->data_len = pdu->data_len;
# # # # #
# # # ]
1352 : 328967 : }
1353 : :
1354 : : static void
1355 : 328967 : nvme_tcp_accel_seq_recv_compute_crc32_done(void *cb_arg)
1356 : : {
1357 : 328967 : struct nvme_tcp_req *treq = cb_arg;
1358 [ # # # # ]: 328967 : struct nvme_tcp_qpair *tqpair = treq->tqpair;
1359 [ # # # # ]: 328967 : struct nvme_tcp_pdu *pdu = treq->pdu;
1360 : : bool result;
1361 : :
1362 [ # # # # ]: 328967 : pdu->data_digest_crc32 ^= SPDK_CRC32C_XOR;
1363 [ # # # # : 328967 : result = MATCH_DIGEST_WORD(pdu->data_digest, pdu->data_digest_crc32);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1364 [ + + # # ]: 328967 : if (spdk_unlikely(!result)) {
1365 : 1478 : SPDK_ERRLOG("data digest error on tqpair=(%p)\n", tqpair);
1366 [ # # # # : 1478 : treq->rsp.status.sc = SPDK_NVME_SC_COMMAND_TRANSIENT_TRANSPORT_ERROR;
# # # # ]
1367 : 0 : }
1368 : 328967 : }
1369 : :
1370 : : static bool
1371 : 503377 : nvme_tcp_accel_recv_compute_crc32(struct nvme_tcp_req *treq, struct nvme_tcp_pdu *pdu)
1372 : : {
1373 [ # # # # ]: 503377 : struct nvme_tcp_qpair *tqpair = treq->tqpair;
1374 [ # # # # : 503377 : struct nvme_tcp_poll_group *tgroup = nvme_tcp_poll_group(tqpair->qpair.poll_group);
# # ]
1375 [ # # # # ]: 503377 : struct nvme_request *req = treq->req;
1376 : 503377 : int rc, dummy = 0;
1377 : :
1378 : : /* Only support this limited case that the request has only one c2h pdu */
1379 [ + - + + : 503377 : if (spdk_unlikely(nvme_qpair_get_state(&tqpair->qpair) < NVME_QPAIR_CONNECTED ||
+ + - + +
+ - + + +
+ + # # #
# # # # #
# # # # #
# # # # #
# # ]
1380 : : tqpair->qpair.poll_group == NULL || pdu->dif_ctx != NULL ||
1381 : : pdu->data_len % SPDK_NVME_TCP_DIGEST_ALIGNMENT != 0 ||
1382 : : pdu->data_len != req->payload_size)) {
1383 : 158795 : return false;
1384 : : }
1385 : :
1386 [ + + # # : 344582 : if (tgroup->group.group->accel_fn_table.append_crc32c == NULL) {
# # # # #
# # # #
# ]
1387 : 15615 : return false;
1388 : : }
1389 : :
1390 : 328967 : nvme_tcp_req_copy_pdu(treq, pdu);
1391 [ # # ]: 657934 : rc = nvme_tcp_accel_append_crc32c(tgroup, &req->accel_sequence,
1392 [ # # # # : 328967 : &treq->pdu->data_digest_crc32,
# # ]
1393 [ # # # # : 657934 : treq->pdu->data_iov, treq->pdu->data_iovcnt, 0,
# # # # #
# # # #
# ]
1394 : 0 : nvme_tcp_accel_seq_recv_compute_crc32_done, treq);
1395 [ - + ]: 328967 : if (spdk_unlikely(rc != 0)) {
1396 : : /* If accel is out of resources, fall back to non-accelerated crc32 */
1397 [ # # ]: 0 : if (rc == -ENOMEM) {
1398 : 0 : return false;
1399 : : }
1400 : :
1401 : 0 : SPDK_ERRLOG("Failed to append crc32c operation: %d\n", rc);
1402 [ # # # # : 0 : treq->rsp.status.sc = SPDK_NVME_SC_COMMAND_TRANSIENT_TRANSPORT_ERROR;
# # # # ]
1403 : 0 : }
1404 : :
1405 : 328967 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY);
1406 [ # # # # ]: 328967 : nvme_tcp_c2h_data_payload_handle(tqpair, treq->pdu, &dummy);
1407 : :
1408 : 328967 : return true;
1409 : 0 : }
1410 : :
1411 : : static void
1412 : 7688958 : nvme_tcp_pdu_payload_handle(struct nvme_tcp_qpair *tqpair,
1413 : : uint32_t *reaped)
1414 : : {
1415 : 7688958 : int rc = 0;
1416 [ + - + - ]: 7688958 : struct nvme_tcp_pdu *pdu = tqpair->recv_pdu;
1417 : : uint32_t crc32c;
1418 [ + - + - ]: 7688958 : struct nvme_tcp_req *tcp_req = pdu->req;
1419 : :
1420 [ + + + - : 7688958 : assert(tqpair->recv_state == NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PAYLOAD);
+ - # # ]
1421 [ + + + + : 7688958 : SPDK_DEBUGLOG(nvme, "enter\n");
+ - ]
1422 : :
1423 : : /* The request can be NULL, e.g. in case of C2HTermReq */
1424 [ + + ]: 7688958 : if (spdk_likely(tcp_req != NULL)) {
1425 [ + - + - : 7688958 : tcp_req->expected_datao += pdu->data_len;
+ - + - ]
1426 : 3339 : }
1427 : :
1428 : : /* check data digest if need */
1429 [ + + + + : 7688958 : if (pdu->ddgst_enable) {
+ - + - ]
1430 : : /* But if the data digest is enabled, tcp_req cannot be NULL */
1431 [ - + # # ]: 503377 : assert(tcp_req != NULL);
1432 [ + + ]: 503377 : if (nvme_tcp_accel_recv_compute_crc32(tcp_req, pdu)) {
1433 : 328967 : return;
1434 : : }
1435 : :
1436 : 174410 : crc32c = nvme_tcp_pdu_calc_data_digest(pdu);
1437 : 174410 : crc32c = crc32c ^ SPDK_CRC32C_XOR;
1438 [ # # # # : 174410 : rc = MATCH_DIGEST_WORD(pdu->data_digest, crc32c);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1439 [ - + ]: 174410 : if (rc == 0) {
1440 : 0 : SPDK_ERRLOG("data digest error on tqpair=(%p) with pdu=%p\n", tqpair, pdu);
1441 [ # # # # ]: 0 : tcp_req = pdu->req;
1442 [ # # # # ]: 0 : assert(tcp_req != NULL);
1443 [ # # # # : 0 : tcp_req->rsp.status.sc = SPDK_NVME_SC_COMMAND_TRANSIENT_TRANSPORT_ERROR;
# # # # ]
1444 : 0 : }
1445 : 0 : }
1446 : :
1447 : 7359991 : _nvme_tcp_pdu_payload_handle(tqpair, reaped);
1448 : 3339 : }
1449 : :
1450 : : static void
1451 : 5416 : nvme_tcp_send_icreq_complete(void *cb_arg)
1452 : : {
1453 : 5416 : struct nvme_tcp_qpair *tqpair = cb_arg;
1454 : :
1455 [ + + + + : 5416 : SPDK_DEBUGLOG(nvme, "Complete the icreq send for tqpair=%p %u\n", tqpair, tqpair->qpair.id);
+ - # # #
# # # ]
1456 : :
1457 [ + - + - ]: 5416 : tqpair->flags.icreq_send_ack = true;
1458 : :
1459 [ + + + - : 5416 : if (tqpair->state == NVME_TCP_QPAIR_STATE_INITIALIZING) {
+ - ]
1460 [ # # # # : 0 : SPDK_DEBUGLOG(nvme, "tqpair %p %u, finalize icresp\n", tqpair, tqpair->qpair.id);
# # # # #
# # # ]
1461 [ # # # # ]: 0 : tqpair->state = NVME_TCP_QPAIR_STATE_FABRIC_CONNECT_SEND;
1462 : 0 : }
1463 : 5416 : }
1464 : :
1465 : : static void
1466 : 5440 : nvme_tcp_icresp_handle(struct nvme_tcp_qpair *tqpair,
1467 : : struct nvme_tcp_pdu *pdu)
1468 : : {
1469 [ + - + - ]: 5440 : struct spdk_nvme_tcp_ic_resp *ic_resp = &pdu->hdr.ic_resp;
1470 : 5440 : uint32_t error_offset = 0;
1471 : : enum spdk_nvme_tcp_term_req_fes fes;
1472 : : int recv_buf_size;
1473 : :
1474 : : /* Only PFV 0 is defined currently */
1475 [ + + + - : 5440 : if (ic_resp->pfv != 0) {
- + ]
1476 [ # # # # ]: 4 : SPDK_ERRLOG("Expected ICResp PFV %u, got %u\n", 0u, ic_resp->pfv);
1477 : 4 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1478 : 4 : error_offset = offsetof(struct spdk_nvme_tcp_ic_resp, pfv);
1479 : 4 : goto end;
1480 : : }
1481 : :
1482 [ + + + - : 5436 : if (ic_resp->maxh2cdata < NVME_TCP_PDU_H2C_MIN_DATA_SIZE) {
- + ]
1483 [ # # # # ]: 4 : SPDK_ERRLOG("Expected ICResp maxh2cdata >=%u, got %u\n", NVME_TCP_PDU_H2C_MIN_DATA_SIZE,
1484 : : ic_resp->maxh2cdata);
1485 : 4 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1486 : 4 : error_offset = offsetof(struct spdk_nvme_tcp_ic_resp, maxh2cdata);
1487 : 4 : goto end;
1488 : : }
1489 [ + - + - : 5432 : tqpair->maxh2cdata = ic_resp->maxh2cdata;
+ - + - ]
1490 : :
1491 [ + + + - : 5432 : if (ic_resp->cpda > SPDK_NVME_TCP_CPDA_MAX) {
- + ]
1492 [ # # # # ]: 4 : SPDK_ERRLOG("Expected ICResp cpda <=%u, got %u\n", SPDK_NVME_TCP_CPDA_MAX, ic_resp->cpda);
1493 : 4 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1494 : 4 : error_offset = offsetof(struct spdk_nvme_tcp_ic_resp, cpda);
1495 : 4 : goto end;
1496 : : }
1497 [ + - + - : 5428 : tqpair->cpda = ic_resp->cpda;
+ - + - ]
1498 : :
1499 [ + - + - : 5428 : tqpair->flags.host_hdgst_enable = ic_resp->dgst.bits.hdgst_enable ? true : false;
+ - + - +
- ]
1500 [ + - + - : 5428 : tqpair->flags.host_ddgst_enable = ic_resp->dgst.bits.ddgst_enable ? true : false;
+ - + - +
- ]
1501 [ + + + + : 5428 : SPDK_DEBUGLOG(nvme, "host_hdgst_enable: %u\n", tqpair->flags.host_hdgst_enable);
+ - # # #
# ]
1502 [ + + + + : 5428 : SPDK_DEBUGLOG(nvme, "host_ddgst_enable: %u\n", tqpair->flags.host_ddgst_enable);
+ - # # #
# ]
1503 : :
1504 : : /* Now that we know whether digests are enabled, properly size the receive buffer to
1505 : : * handle several incoming 4K read commands according to SPDK_NVMF_TCP_RECV_BUF_SIZE_FACTOR
1506 : : * parameter. */
1507 : 5428 : recv_buf_size = 0x1000 + sizeof(struct spdk_nvme_tcp_c2h_data_hdr);
1508 : :
1509 [ + + + - : 5428 : if (tqpair->flags.host_hdgst_enable) {
+ - ]
1510 [ # # ]: 32 : recv_buf_size += SPDK_NVME_TCP_DIGEST_LEN;
1511 : 2 : }
1512 : :
1513 [ + + + - : 5428 : if (tqpair->flags.host_ddgst_enable) {
+ - ]
1514 [ # # ]: 108 : recv_buf_size += SPDK_NVME_TCP_DIGEST_LEN;
1515 : 2 : }
1516 : :
1517 [ + + + - : 5428 : if (spdk_sock_set_recvbuf(tqpair->sock, recv_buf_size * SPDK_NVMF_TCP_RECV_BUF_SIZE_FACTOR) < 0) {
+ - + - ]
1518 : 0 : SPDK_WARNLOG("Unable to allocate enough memory for receive buffer on tqpair=%p with size=%d\n",
1519 : : tqpair,
1520 : : recv_buf_size);
1521 : : /* Not fatal. */
1522 : 0 : }
1523 : :
1524 : 5428 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY);
1525 : :
1526 [ + + + - : 5428 : if (!tqpair->flags.icreq_send_ack) {
+ - ]
1527 [ # # # # ]: 4 : tqpair->state = NVME_TCP_QPAIR_STATE_INITIALIZING;
1528 [ + + - + : 4 : SPDK_DEBUGLOG(nvme, "tqpair %p %u, waiting icreq ack\n", tqpair, tqpair->qpair.id);
# # # # #
# # # ]
1529 : 4 : return;
1530 : : }
1531 : :
1532 [ + - + - ]: 5424 : tqpair->state = NVME_TCP_QPAIR_STATE_FABRIC_CONNECT_SEND;
1533 : 5424 : return;
1534 : 9 : end:
1535 : 12 : nvme_tcp_qpair_send_h2c_term_req(tqpair, pdu, fes, error_offset);
1536 : 1662 : }
1537 : :
1538 : : static void
1539 : 14789554 : nvme_tcp_capsule_resp_hdr_handle(struct nvme_tcp_qpair *tqpair, struct nvme_tcp_pdu *pdu,
1540 : : uint32_t *reaped)
1541 : : {
1542 : : struct nvme_tcp_req *tcp_req;
1543 : : struct nvme_tcp_poll_group *tgroup;
1544 [ + - + - ]: 14789554 : struct spdk_nvme_tcp_rsp *capsule_resp = &pdu->hdr.capsule_resp;
1545 : 14789554 : uint32_t cid, error_offset = 0;
1546 : : enum spdk_nvme_tcp_term_req_fes fes;
1547 : :
1548 [ + + + + : 14789554 : SPDK_DEBUGLOG(nvme, "enter\n");
+ - ]
1549 [ + - + - : 14789554 : cid = capsule_resp->rccqe.cid;
+ - ]
1550 : 14789554 : tcp_req = get_nvme_active_req_by_cid(tqpair, cid);
1551 : :
1552 [ + + ]: 14789554 : if (!tcp_req) {
1553 : 4 : SPDK_ERRLOG("no tcp_req is found with cid=%u for tqpair=%p\n", cid, tqpair);
1554 : 4 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1555 : 4 : error_offset = offsetof(struct spdk_nvme_tcp_rsp, rccqe);
1556 : 4 : goto end;
1557 : : }
1558 : :
1559 [ + + + - : 14789550 : assert(tcp_req->req != NULL);
+ - # # ]
1560 : :
1561 [ + - + - ]: 14789550 : tcp_req->rsp = capsule_resp->rccqe;
1562 [ + - + - : 14789550 : tcp_req->ordering.bits.data_recv = 1;
+ - ]
1563 : :
1564 : : /* Recv the pdu again */
1565 : 14789550 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY);
1566 : :
1567 [ + + + - : 14789550 : if (tcp_req->req->accel_sequence != NULL) {
+ - + - -
+ ]
1568 [ # # # # : 261397 : tgroup = nvme_tcp_poll_group(tqpair->qpair.poll_group);
# # ]
1569 [ # # # # : 261397 : nvme_tcp_accel_reverse_sequence(tgroup, tcp_req->req->accel_sequence);
# # # # ]
1570 [ # # # # : 261397 : nvme_tcp_accel_finish_sequence(tgroup, tcp_req, tcp_req->req->accel_sequence,
# # # # ]
1571 : 0 : nvme_tcp_recv_payload_seq_cb, tcp_req);
1572 : 261397 : return;
1573 : : }
1574 : :
1575 [ + + ]: 14528153 : if (nvme_tcp_req_complete_safe(tcp_req)) {
1576 : 14528153 : (*reaped)++;
1577 : 17840 : }
1578 : :
1579 : 14528153 : return;
1580 : :
1581 : 3 : end:
1582 : 4 : nvme_tcp_qpair_send_h2c_term_req(tqpair, pdu, fes, error_offset);
1583 : 17841 : }
1584 : :
1585 : : static void
1586 : 0 : nvme_tcp_c2h_term_req_hdr_handle(struct nvme_tcp_qpair *tqpair,
1587 : : struct nvme_tcp_pdu *pdu)
1588 : : {
1589 [ # # # # ]: 0 : struct spdk_nvme_tcp_term_req_hdr *c2h_term_req = &pdu->hdr.term_req;
1590 : 0 : uint32_t error_offset = 0;
1591 : : enum spdk_nvme_tcp_term_req_fes fes;
1592 : :
1593 [ # # # # : 0 : if (c2h_term_req->fes > SPDK_NVME_TCP_TERM_REQ_FES_INVALID_DATA_UNSUPPORTED_PARAMETER) {
# # ]
1594 : 0 : SPDK_ERRLOG("Fatal Error Status(FES) is unknown for c2h_term_req pdu=%p\n", pdu);
1595 : 0 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1596 : 0 : error_offset = offsetof(struct spdk_nvme_tcp_term_req_hdr, fes);
1597 : 0 : goto end;
1598 : : }
1599 : :
1600 : : /* set the data buffer */
1601 [ # # # # : 0 : nvme_tcp_pdu_set_data(pdu, (uint8_t *)pdu->hdr.raw + c2h_term_req->common.hlen,
# # # # #
# # # ]
1602 [ # # # # : 0 : c2h_term_req->common.plen - c2h_term_req->common.hlen);
# # # # #
# # # ]
1603 : 0 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PAYLOAD);
1604 : 0 : return;
1605 : 0 : end:
1606 : 0 : nvme_tcp_qpair_send_h2c_term_req(tqpair, pdu, fes, error_offset);
1607 : 0 : }
1608 : :
1609 : : static void
1610 : 7688956 : nvme_tcp_c2h_data_hdr_handle(struct nvme_tcp_qpair *tqpair, struct nvme_tcp_pdu *pdu)
1611 : : {
1612 : : struct nvme_tcp_req *tcp_req;
1613 [ + - + - ]: 7688956 : struct spdk_nvme_tcp_c2h_data_hdr *c2h_data = &pdu->hdr.c2h_data;
1614 : 7688956 : uint32_t error_offset = 0;
1615 : : enum spdk_nvme_tcp_term_req_fes fes;
1616 [ + - + - : 7688956 : int flags = c2h_data->common.flags;
+ - ]
1617 : : int rc;
1618 : :
1619 [ + + + + : 7688956 : SPDK_DEBUGLOG(nvme, "enter\n");
+ - ]
1620 [ + + + + : 7688956 : SPDK_DEBUGLOG(nvme, "c2h_data info on tqpair(%p): datao=%u, datal=%u, cccid=%d\n",
+ - # # #
# # # # #
# # # # ]
1621 : : tqpair, c2h_data->datao, c2h_data->datal, c2h_data->cccid);
1622 [ + - + - ]: 7688956 : tcp_req = get_nvme_active_req_by_cid(tqpair, c2h_data->cccid);
1623 [ + + ]: 7688956 : if (!tcp_req) {
1624 [ # # # # ]: 0 : SPDK_ERRLOG("no tcp_req found for c2hdata cid=%d\n", c2h_data->cccid);
1625 : 0 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1626 : 0 : error_offset = offsetof(struct spdk_nvme_tcp_c2h_data_hdr, cccid);
1627 : 0 : goto end;
1628 : :
1629 : : }
1630 : :
1631 [ + + + + : 7688956 : SPDK_DEBUGLOG(nvme, "tcp_req(%p) on tqpair(%p): expected_datao=%u, payload_size=%u\n",
+ - # # #
# # # # #
# # # # ]
1632 : : tcp_req, tqpair, tcp_req->expected_datao, tcp_req->req->payload_size);
1633 : :
1634 [ + + + + : 7688956 : if (spdk_unlikely((flags & SPDK_NVME_TCP_C2H_DATA_FLAGS_SUCCESS) &&
# # - + ]
1635 : : !(flags & SPDK_NVME_TCP_C2H_DATA_FLAGS_LAST_PDU))) {
1636 : 0 : SPDK_ERRLOG("Invalid flag flags=%d in c2h_data=%p\n", flags, c2h_data);
1637 : 0 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1638 : 0 : error_offset = offsetof(struct spdk_nvme_tcp_c2h_data_hdr, common);
1639 : 0 : goto end;
1640 : : }
1641 : :
1642 [ + + + - : 7688956 : if (c2h_data->datal > tcp_req->req->payload_size) {
+ - + - +
- + - -
+ ]
1643 [ # # # # : 0 : SPDK_ERRLOG("Invalid datal for tcp_req(%p), datal(%u) exceeds payload_size(%u)\n",
# # # # #
# # # ]
1644 : : tcp_req, c2h_data->datal, tcp_req->req->payload_size);
1645 : 0 : fes = SPDK_NVME_TCP_TERM_REQ_FES_DATA_TRANSFER_OUT_OF_RANGE;
1646 : 0 : goto end;
1647 : : }
1648 : :
1649 [ + + + - : 7688956 : if (tcp_req->expected_datao != c2h_data->datao) {
+ - + - -
+ ]
1650 [ # # # # : 0 : SPDK_ERRLOG("Invalid datao for tcp_req(%p), received datal(%u) != expected datao(%u) in tcp_req\n",
# # # # ]
1651 : : tcp_req, c2h_data->datao, tcp_req->expected_datao);
1652 : 0 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1653 : 0 : error_offset = offsetof(struct spdk_nvme_tcp_c2h_data_hdr, datao);
1654 : 0 : goto end;
1655 : : }
1656 : :
1657 [ + + + - : 7688956 : if ((c2h_data->datao + c2h_data->datal) > tcp_req->req->payload_size) {
+ - + - +
- + - + -
+ - - + ]
1658 [ # # # # : 0 : SPDK_ERRLOG("Invalid data range for tcp_req(%p), received (datao(%u) + datal(%u)) > datao(%u) in tcp_req\n",
# # # # #
# # # # #
# # ]
1659 : : tcp_req, c2h_data->datao, c2h_data->datal, tcp_req->req->payload_size);
1660 : 0 : fes = SPDK_NVME_TCP_TERM_REQ_FES_DATA_TRANSFER_OUT_OF_RANGE;
1661 : 0 : error_offset = offsetof(struct spdk_nvme_tcp_c2h_data_hdr, datal);
1662 : 0 : goto end;
1663 : :
1664 : : }
1665 : :
1666 [ + + + - : 7688956 : if (nvme_payload_type(&tcp_req->req->payload) == NVME_PAYLOAD_TYPE_CONTIG) {
+ - + - ]
1667 : 7515039 : rc = nvme_tcp_build_contig_request(tqpair, tcp_req);
1668 : 3337 : } else {
1669 [ - + # # : 173917 : assert(nvme_payload_type(&tcp_req->req->payload) == NVME_PAYLOAD_TYPE_SGL);
# # # # #
# ]
1670 : 173917 : rc = nvme_tcp_build_sgl_request(tqpair, tcp_req);
1671 : : }
1672 : :
1673 [ - + ]: 7688956 : if (rc) {
1674 : : /* Not the right error message but at least it handles the failure. */
1675 : 0 : fes = SPDK_NVME_TCP_TERM_REQ_FES_DATA_TRANSFER_LIMIT_EXCEEDED;
1676 : 0 : goto end;
1677 : : }
1678 : :
1679 [ + - + - : 7692293 : nvme_tcp_pdu_set_data_buf(pdu, tcp_req->iov, tcp_req->iovcnt,
+ - ]
1680 [ + - + - : 3337 : c2h_data->datao, c2h_data->datal);
+ - + - ]
1681 [ + - + - ]: 7688956 : pdu->req = tcp_req;
1682 : :
1683 : 7688956 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PAYLOAD);
1684 : 7688956 : return;
1685 : :
1686 : 0 : end:
1687 : 0 : nvme_tcp_qpair_send_h2c_term_req(tqpair, pdu, fes, error_offset);
1688 : 3337 : }
1689 : :
1690 : : static void
1691 : 764458 : nvme_tcp_qpair_h2c_data_send_complete(void *cb_arg)
1692 : : {
1693 : 764458 : struct nvme_tcp_req *tcp_req = cb_arg;
1694 : :
1695 [ - + # # ]: 764458 : assert(tcp_req != NULL);
1696 : :
1697 [ # # # # : 764458 : tcp_req->ordering.bits.send_ack = 1;
# # ]
1698 [ - + # # : 764458 : if (tcp_req->r2tl_remain) {
# # ]
1699 : 0 : nvme_tcp_send_h2c_data(tcp_req);
1700 : 0 : } else {
1701 [ - + # # : 764458 : assert(tcp_req->active_r2ts > 0);
# # # # ]
1702 [ # # ]: 764458 : tcp_req->active_r2ts--;
1703 [ # # # # ]: 764458 : tcp_req->state = NVME_TCP_REQ_ACTIVE;
1704 : :
1705 [ - + # # : 764458 : if (tcp_req->ordering.bits.r2t_waiting_h2c_complete) {
# # # # ]
1706 [ # # # # : 0 : tcp_req->ordering.bits.r2t_waiting_h2c_complete = 0;
# # ]
1707 [ # # # # : 0 : SPDK_DEBUGLOG(nvme, "tcp_req %p: continue r2t\n", tcp_req);
# # ]
1708 [ # # # # : 0 : assert(tcp_req->active_r2ts > 0);
# # # # ]
1709 [ # # # # : 0 : tcp_req->ttag = tcp_req->ttag_r2t_next;
# # # # ]
1710 [ # # # # : 0 : tcp_req->r2tl_remain = tcp_req->r2tl_remain_next;
# # # # ]
1711 [ # # # # ]: 0 : tcp_req->state = NVME_TCP_REQ_ACTIVE_R2T;
1712 : 0 : nvme_tcp_send_h2c_data(tcp_req);
1713 : 0 : return;
1714 : : }
1715 : :
1716 [ + + # # : 764458 : if (tcp_req->ordering.bits.domain_in_use) {
# # # # ]
1717 [ # # # # : 22732 : spdk_memory_domain_invalidate_data(tcp_req->req->payload.opts->memory_domain,
# # # # #
# # # #
# ]
1718 [ # # # # : 11366 : tcp_req->req->payload.opts->memory_domain_ctx, tcp_req->iov, tcp_req->iovcnt);
# # # # #
# # # # #
# # # # #
# ]
1719 : 0 : }
1720 : :
1721 : : /* Need also call this function to free the resource */
1722 : 764458 : nvme_tcp_req_complete_safe(tcp_req);
1723 : : }
1724 : 0 : }
1725 : :
1726 : : static void
1727 : 764724 : nvme_tcp_send_h2c_data(struct nvme_tcp_req *tcp_req)
1728 : : {
1729 [ # # # # : 764724 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(tcp_req->req->qpair);
# # # # ]
1730 : : struct nvme_tcp_pdu *rsp_pdu;
1731 : : struct spdk_nvme_tcp_h2c_data_hdr *h2c_data;
1732 : : uint32_t plen, pdo, alignment;
1733 : :
1734 : : /* Reinit the send_ack and h2c_send_waiting_ack bits */
1735 [ # # # # : 764724 : tcp_req->ordering.bits.send_ack = 0;
# # ]
1736 [ # # # # : 764724 : tcp_req->ordering.bits.h2c_send_waiting_ack = 0;
# # ]
1737 [ # # # # ]: 764724 : rsp_pdu = tcp_req->pdu;
1738 [ - + ]: 764724 : memset(rsp_pdu, 0, sizeof(*rsp_pdu));
1739 [ # # # # ]: 764724 : rsp_pdu->req = tcp_req;
1740 [ # # # # ]: 764724 : h2c_data = &rsp_pdu->hdr.h2c_data;
1741 : :
1742 [ # # # # : 764724 : h2c_data->common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_H2C_DATA;
# # ]
1743 [ # # # # : 764724 : plen = h2c_data->common.hlen = sizeof(*h2c_data);
# # ]
1744 [ # # # # : 764724 : h2c_data->cccid = tcp_req->cid;
# # # # ]
1745 [ # # # # : 764724 : h2c_data->ttag = tcp_req->ttag;
# # # # ]
1746 [ # # # # : 764724 : h2c_data->datao = tcp_req->datao;
# # # # ]
1747 : :
1748 [ # # # # : 764724 : h2c_data->datal = spdk_min(tcp_req->r2tl_remain, tqpair->maxh2cdata);
# # # # #
# # # # #
# # # # #
# # # ]
1749 [ # # # # : 764724 : nvme_tcp_pdu_set_data_buf(rsp_pdu, tcp_req->iov, tcp_req->iovcnt,
# # ]
1750 [ # # # # : 0 : h2c_data->datao, h2c_data->datal);
# # # # ]
1751 [ # # # # : 764724 : tcp_req->r2tl_remain -= h2c_data->datal;
# # # # ]
1752 : :
1753 [ - + # # : 764724 : if (tqpair->flags.host_hdgst_enable) {
# # ]
1754 [ # # # # : 0 : h2c_data->common.flags |= SPDK_NVME_TCP_CH_FLAGS_HDGSTF;
# # # # ]
1755 : 0 : plen += SPDK_NVME_TCP_DIGEST_LEN;
1756 : 0 : }
1757 : :
1758 [ # # # # ]: 764724 : rsp_pdu->padding_len = 0;
1759 : 764724 : pdo = plen;
1760 [ - + # # : 764724 : if (tqpair->cpda) {
# # ]
1761 [ # # # # : 0 : alignment = (tqpair->cpda + 1) << 2;
# # # # #
# ]
1762 [ # # ]: 0 : if (alignment > plen) {
1763 [ # # # # ]: 0 : rsp_pdu->padding_len = alignment - plen;
1764 : 0 : pdo = plen = alignment;
1765 : 0 : }
1766 : 0 : }
1767 : :
1768 [ # # # # : 764724 : h2c_data->common.pdo = pdo;
# # ]
1769 [ # # # # ]: 764724 : plen += h2c_data->datal;
1770 [ + + # # : 764724 : if (tqpair->flags.host_ddgst_enable) {
# # ]
1771 [ # # # # : 73177 : h2c_data->common.flags |= SPDK_NVME_TCP_CH_FLAGS_DDGSTF;
# # # # ]
1772 : 73177 : plen += SPDK_NVME_TCP_DIGEST_LEN;
1773 : 0 : }
1774 : :
1775 [ # # # # : 764724 : h2c_data->common.plen = plen;
# # ]
1776 [ # # # # : 764724 : tcp_req->datao += h2c_data->datal;
# # # # ]
1777 [ + - # # : 764724 : if (!tcp_req->r2tl_remain) {
# # ]
1778 [ # # # # : 764724 : h2c_data->common.flags |= SPDK_NVME_TCP_H2C_DATA_FLAGS_LAST_PDU;
# # # # ]
1779 : 0 : }
1780 : :
1781 [ - + - + : 764724 : SPDK_DEBUGLOG(nvme, "h2c_data info: datao=%u, datal=%u, pdu_len=%u for tqpair=%p\n",
# # # # #
# # # # #
# # # # #
# ]
1782 : : h2c_data->datao, h2c_data->datal, h2c_data->common.plen, tqpair);
1783 : :
1784 : 764724 : nvme_tcp_qpair_write_pdu(tqpair, rsp_pdu, nvme_tcp_qpair_h2c_data_send_complete, tcp_req);
1785 : 764724 : }
1786 : :
1787 : : static void
1788 : 764724 : nvme_tcp_r2t_hdr_handle(struct nvme_tcp_qpair *tqpair, struct nvme_tcp_pdu *pdu)
1789 : : {
1790 : : struct nvme_tcp_req *tcp_req;
1791 [ # # # # ]: 764724 : struct spdk_nvme_tcp_r2t_hdr *r2t = &pdu->hdr.r2t;
1792 : 764724 : uint32_t cid, error_offset = 0;
1793 : : enum spdk_nvme_tcp_term_req_fes fes;
1794 : :
1795 [ - + - + : 764724 : SPDK_DEBUGLOG(nvme, "enter\n");
# # ]
1796 [ # # # # ]: 764724 : cid = r2t->cccid;
1797 : 764724 : tcp_req = get_nvme_active_req_by_cid(tqpair, cid);
1798 [ - + ]: 764724 : if (!tcp_req) {
1799 : 0 : SPDK_ERRLOG("Cannot find tcp_req for tqpair=%p\n", tqpair);
1800 : 0 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1801 : 0 : error_offset = offsetof(struct spdk_nvme_tcp_r2t_hdr, cccid);
1802 : 0 : goto end;
1803 : : }
1804 : :
1805 [ - + - + : 764724 : SPDK_DEBUGLOG(nvme, "r2t info: r2to=%u, r2tl=%u for tqpair=%p\n", r2t->r2to, r2t->r2tl,
# # # # #
# # # #
# ]
1806 : : tqpair);
1807 : :
1808 [ + - # # : 764724 : if (tcp_req->state == NVME_TCP_REQ_ACTIVE) {
# # ]
1809 [ - + # # : 764724 : assert(tcp_req->active_r2ts == 0);
# # # # ]
1810 [ # # # # ]: 764724 : tcp_req->state = NVME_TCP_REQ_ACTIVE_R2T;
1811 : 0 : }
1812 : :
1813 [ - + # # : 764724 : if (tcp_req->datao != r2t->r2to) {
# # # # #
# ]
1814 : 0 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1815 : 0 : error_offset = offsetof(struct spdk_nvme_tcp_r2t_hdr, r2to);
1816 : 0 : goto end;
1817 : :
1818 : : }
1819 : :
1820 [ - + # # : 764724 : if ((r2t->r2tl + r2t->r2to) > tcp_req->req->payload_size) {
# # # # #
# # # # #
# # # # ]
1821 [ # # # # : 0 : SPDK_ERRLOG("Invalid R2T info for tcp_req=%p: (r2to(%u) + r2tl(%u)) exceeds payload_size(%u)\n",
# # # # #
# # # ]
1822 : : tcp_req, r2t->r2to, r2t->r2tl, tqpair->maxh2cdata);
1823 : 0 : fes = SPDK_NVME_TCP_TERM_REQ_FES_DATA_TRANSFER_OUT_OF_RANGE;
1824 : 0 : error_offset = offsetof(struct spdk_nvme_tcp_r2t_hdr, r2tl);
1825 : 0 : goto end;
1826 : : }
1827 : :
1828 [ # # ]: 764724 : tcp_req->active_r2ts++;
1829 [ - + # # : 764724 : if (spdk_unlikely(tcp_req->active_r2ts > tqpair->maxr2t)) {
# # # # #
# ]
1830 [ # # # # : 0 : if (tcp_req->state == NVME_TCP_REQ_ACTIVE_R2T && !tcp_req->ordering.bits.send_ack) {
# # # # #
# # # #
# ]
1831 : : /* We receive a subsequent R2T while we are waiting for H2C transfer to complete */
1832 [ # # # # : 0 : SPDK_DEBUGLOG(nvme, "received a subsequent R2T\n");
# # ]
1833 [ # # # # : 0 : assert(tcp_req->active_r2ts == tqpair->maxr2t + 1);
# # # # #
# # # ]
1834 [ # # # # : 0 : tcp_req->ttag_r2t_next = r2t->ttag;
# # # # ]
1835 [ # # # # : 0 : tcp_req->r2tl_remain_next = r2t->r2tl;
# # # # ]
1836 [ # # # # : 0 : tcp_req->ordering.bits.r2t_waiting_h2c_complete = 1;
# # ]
1837 : 0 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY);
1838 : 0 : return;
1839 : : } else {
1840 : 0 : fes = SPDK_NVME_TCP_TERM_REQ_FES_R2T_LIMIT_EXCEEDED;
1841 [ # # # # ]: 0 : SPDK_ERRLOG("Invalid R2T: Maximum number of R2T exceeded! Max: %u for tqpair=%p\n", tqpair->maxr2t,
1842 : : tqpair);
1843 : 0 : goto end;
1844 : : }
1845 : : }
1846 : :
1847 [ # # # # : 764724 : tcp_req->ttag = r2t->ttag;
# # # # ]
1848 [ # # # # : 764724 : tcp_req->r2tl_remain = r2t->r2tl;
# # # # ]
1849 : 764724 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY);
1850 : :
1851 [ + - # # : 764724 : if (spdk_likely(tcp_req->ordering.bits.send_ack)) {
# # # # ]
1852 : 764724 : nvme_tcp_send_h2c_data(tcp_req);
1853 : 0 : } else {
1854 [ # # # # : 0 : tcp_req->ordering.bits.h2c_send_waiting_ack = 1;
# # ]
1855 : : }
1856 : :
1857 : 764724 : return;
1858 : :
1859 : 0 : end:
1860 : 0 : nvme_tcp_qpair_send_h2c_term_req(tqpair, pdu, fes, error_offset);
1861 : :
1862 : 0 : }
1863 : :
1864 : : static void
1865 : 23248646 : nvme_tcp_pdu_psh_handle(struct nvme_tcp_qpair *tqpair, uint32_t *reaped)
1866 : : {
1867 : : struct nvme_tcp_pdu *pdu;
1868 : : int rc;
1869 : 23248646 : uint32_t crc32c, error_offset = 0;
1870 : : enum spdk_nvme_tcp_term_req_fes fes;
1871 : :
1872 [ + + + - : 23248646 : assert(tqpair->recv_state == NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PSH);
+ - # # ]
1873 [ + - + - ]: 23248646 : pdu = tqpair->recv_pdu;
1874 : :
1875 [ + + + + : 23248646 : SPDK_DEBUGLOG(nvme, "enter: pdu type =%u\n", pdu->hdr.common.pdu_type);
+ - # # #
# # # #
# ]
1876 : : /* check header digest if needed */
1877 [ + + + + : 23248646 : if (pdu->has_hdgst) {
+ - + - ]
1878 : 223819 : crc32c = nvme_tcp_pdu_calc_header_digest(pdu);
1879 [ # # # # : 223819 : rc = MATCH_DIGEST_WORD((uint8_t *)pdu->hdr.raw + pdu->hdr.common.hlen, crc32c);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
1880 [ - + ]: 223819 : if (rc == 0) {
1881 : 0 : SPDK_ERRLOG("header digest error on tqpair=(%p) with pdu=%p\n", tqpair, pdu);
1882 : 0 : fes = SPDK_NVME_TCP_TERM_REQ_FES_HDGST_ERROR;
1883 : 0 : nvme_tcp_qpair_send_h2c_term_req(tqpair, pdu, fes, error_offset);
1884 : 0 : return;
1885 : :
1886 : : }
1887 : 0 : }
1888 : :
1889 [ + + + - : 23248646 : switch (pdu->hdr.common.pdu_type) {
+ - + - +
+ + - -
- ]
1890 : 3763 : case SPDK_NVME_TCP_PDU_TYPE_IC_RESP:
1891 : 5420 : nvme_tcp_icresp_handle(tqpair, pdu);
1892 : 5420 : break;
1893 : 14771707 : case SPDK_NVME_TCP_PDU_TYPE_CAPSULE_RESP:
1894 : 14789546 : nvme_tcp_capsule_resp_hdr_handle(tqpair, pdu, reaped);
1895 : 14789546 : break;
1896 : 7685619 : case SPDK_NVME_TCP_PDU_TYPE_C2H_DATA:
1897 : 7688956 : nvme_tcp_c2h_data_hdr_handle(tqpair, pdu);
1898 : 7688956 : break;
1899 : :
1900 : 0 : case SPDK_NVME_TCP_PDU_TYPE_C2H_TERM_REQ:
1901 : 0 : nvme_tcp_c2h_term_req_hdr_handle(tqpair, pdu);
1902 : 0 : break;
1903 : 764724 : case SPDK_NVME_TCP_PDU_TYPE_R2T:
1904 : 764724 : nvme_tcp_r2t_hdr_handle(tqpair, pdu);
1905 : 764724 : break;
1906 : :
1907 : 0 : default:
1908 [ # # # # : 0 : SPDK_ERRLOG("Unexpected PDU type 0x%02x\n", tqpair->recv_pdu->hdr.common.pdu_type);
# # # # #
# # # ]
1909 : 0 : fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1910 : 0 : error_offset = 1;
1911 : 0 : nvme_tcp_qpair_send_h2c_term_req(tqpair, pdu, fes, error_offset);
1912 : 0 : break;
1913 : : }
1914 : :
1915 : 22833 : }
1916 : :
1917 : : static int
1918 : 60519542 : nvme_tcp_read_pdu(struct nvme_tcp_qpair *tqpair, uint32_t *reaped, uint32_t max_completions)
1919 : : {
1920 : 60519542 : int rc = 0;
1921 : : struct nvme_tcp_pdu *pdu;
1922 : : uint32_t data_len;
1923 : : enum nvme_tcp_pdu_recv_state prev_state;
1924 : :
1925 [ + - + - : 60519542 : *reaped = tqpair->async_complete;
+ - ]
1926 [ + - + - ]: 60519542 : tqpair->async_complete = 0;
1927 : :
1928 : : /* The loop here is to allow for several back-to-back state changes. */
1929 : 1160959 : do {
1930 [ + + - + ]: 137959949 : if (*reaped >= max_completions) {
1931 : 262813 : break;
1932 : : }
1933 : :
1934 [ + - + - ]: 137697136 : prev_state = tqpair->recv_state;
1935 [ + - + - ]: 137697136 : pdu = tqpair->recv_pdu;
1936 [ + + + + : 137697136 : switch (tqpair->recv_state) {
+ + + + -
- - ]
1937 : : /* If in a new state */
1938 : 23229517 : case NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY:
1939 [ + + ]: 23254006 : memset(pdu, 0, sizeof(struct nvme_tcp_pdu));
1940 : 23254006 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_CH);
1941 : 23254006 : break;
1942 : : /* Wait for the pdu common header */
1943 : 74252249 : case NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_CH:
1944 [ + + + - : 75436039 : assert(pdu->ch_valid_bytes < sizeof(struct spdk_nvme_tcp_common_pdu_hdr));
+ - # # ]
1945 [ + - + - ]: 76619829 : rc = nvme_tcp_read_data(tqpair->sock,
1946 [ + - + - ]: 75436039 : sizeof(struct spdk_nvme_tcp_common_pdu_hdr) - pdu->ch_valid_bytes,
1947 [ + - + - : 75436039 : (uint8_t *)&pdu->hdr.common + pdu->ch_valid_bytes);
+ - + - +
- ]
1948 [ + + ]: 75436039 : if (rc < 0) {
1949 : 97 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_QUIESCING);
1950 : 97 : break;
1951 : : }
1952 [ + - + - : 75435942 : pdu->ch_valid_bytes += rc;
+ - ]
1953 [ + + + - : 75435942 : if (pdu->ch_valid_bytes < sizeof(struct spdk_nvme_tcp_common_pdu_hdr)) {
+ + ]
1954 : 52187289 : return NVME_TCP_PDU_IN_PROGRESS;
1955 : : }
1956 : :
1957 : : /* The command header of this PDU has now been read from the socket. */
1958 : 23248653 : nvme_tcp_pdu_ch_handle(tqpair);
1959 : 23248653 : break;
1960 : : /* Wait for the pdu specific header */
1961 : 23226082 : case NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PSH:
1962 [ + + + - : 23248915 : assert(pdu->psh_valid_bytes < pdu->psh_len);
+ - + - +
- # # ]
1963 [ + - + - ]: 23271748 : rc = nvme_tcp_read_data(tqpair->sock,
1964 [ + - + - : 23248915 : pdu->psh_len - pdu->psh_valid_bytes,
+ - + - ]
1965 [ + - + - : 23248915 : (uint8_t *)&pdu->hdr.raw + sizeof(struct spdk_nvme_tcp_common_pdu_hdr) + pdu->psh_valid_bytes);
+ - + - +
- + - ]
1966 [ + + ]: 23248915 : if (rc < 0) {
1967 : 0 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_QUIESCING);
1968 : 0 : break;
1969 : : }
1970 : :
1971 [ + - + - : 23248915 : pdu->psh_valid_bytes += rc;
+ - ]
1972 [ + + + - : 23248915 : if (pdu->psh_valid_bytes < pdu->psh_len) {
+ - + - +
- ]
1973 : 269 : return NVME_TCP_PDU_IN_PROGRESS;
1974 : : }
1975 : :
1976 : : /* All header(ch, psh, head digits) of this PDU has now been read from the socket. */
1977 : 23248646 : nvme_tcp_pdu_psh_handle(tqpair, reaped);
1978 : 23248646 : break;
1979 : 15754630 : case NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PAYLOAD:
1980 : : /* check whether the data is valid, if not we just return */
1981 [ + + + - : 15757967 : if (!pdu->data_len) {
- + ]
1982 : 0 : return NVME_TCP_PDU_IN_PROGRESS;
1983 : : }
1984 : :
1985 [ + - + - ]: 15757967 : data_len = pdu->data_len;
1986 : : /* data digest */
1987 [ + - + + : 15757967 : if (spdk_unlikely((pdu->hdr.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_C2H_DATA) &&
+ - + - -
+ + - + -
+ - ]
1988 : : tqpair->flags.host_ddgst_enable)) {
1989 : 870340 : data_len += SPDK_NVME_TCP_DIGEST_LEN;
1990 [ # # # # ]: 870340 : pdu->ddgst_enable = true;
1991 : 0 : }
1992 : :
1993 [ + - + - ]: 15757967 : rc = nvme_tcp_read_payload_data(tqpair->sock, pdu);
1994 [ + + ]: 15757967 : if (rc < 0) {
1995 : 3 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_QUIESCING);
1996 : 3 : break;
1997 : : }
1998 : :
1999 [ + - + - ]: 15757964 : pdu->rw_offset += rc;
2000 [ + + + - : 15757964 : if (pdu->rw_offset < data_len) {
- + ]
2001 : 8069014 : return NVME_TCP_PDU_IN_PROGRESS;
2002 : : }
2003 : :
2004 [ + + + - : 7688950 : assert(pdu->rw_offset == data_len);
- + # # ]
2005 : : /* All of this PDU has now been read from the socket. */
2006 : 7688950 : nvme_tcp_pdu_payload_handle(tqpair, reaped);
2007 : 7688950 : break;
2008 : 155 : case NVME_TCP_PDU_RECV_STATE_QUIESCING:
2009 [ + + # # : 157 : if (TAILQ_EMPTY(&tqpair->outstanding_reqs)) {
# # # # ]
2010 [ + + # # ]: 52 : if (nvme_qpair_get_state(&tqpair->qpair) == NVME_QPAIR_DISCONNECTING) {
2011 [ # # ]: 45 : nvme_transport_ctrlr_disconnect_qpair_done(&tqpair->qpair);
2012 : 1 : }
2013 : :
2014 : 52 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_ERROR);
2015 : 1 : }
2016 : 157 : break;
2017 : 51 : case NVME_TCP_PDU_RECV_STATE_ERROR:
2018 [ - + ]: 52 : memset(pdu, 0, sizeof(struct nvme_tcp_pdu));
2019 : 52 : return NVME_TCP_PDU_FATAL;
2020 : 0 : default:
2021 [ # # ]: 0 : assert(0);
2022 : : break;
2023 : : }
2024 [ + + + - : 77440512 : } while (prev_state != tqpair->recv_state);
+ - ]
2025 : :
2026 [ - + ]: 262918 : return rc > 0 ? 0 : rc;
2027 : 1160959 : }
2028 : :
2029 : : static void
2030 : 0 : nvme_tcp_qpair_check_timeout(struct spdk_nvme_qpair *qpair)
2031 : : {
2032 : : uint64_t t02;
2033 : : struct nvme_tcp_req *tcp_req, *tmp;
2034 : 0 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(qpair);
2035 [ # # # # ]: 0 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
2036 : : struct spdk_nvme_ctrlr_process *active_proc;
2037 : :
2038 : : /* Don't check timeouts during controller initialization. */
2039 [ # # # # : 0 : if (ctrlr->state != NVME_CTRLR_STATE_READY) {
# # ]
2040 : 0 : return;
2041 : : }
2042 : :
2043 [ # # ]: 0 : if (nvme_qpair_is_admin_queue(qpair)) {
2044 : 0 : active_proc = nvme_ctrlr_get_current_process(ctrlr);
2045 : 0 : } else {
2046 [ # # # # ]: 0 : active_proc = qpair->active_proc;
2047 : : }
2048 : :
2049 : : /* Only check timeouts if the current process has a timeout callback. */
2050 [ # # # # : 0 : if (active_proc == NULL || active_proc->timeout_cb_fn == NULL) {
# # # # ]
2051 : 0 : return;
2052 : : }
2053 : :
2054 : 0 : t02 = spdk_get_ticks();
2055 [ # # # # : 0 : TAILQ_FOREACH_SAFE(tcp_req, &tqpair->outstanding_reqs, link, tmp) {
# # # # #
# # # # #
# # ]
2056 [ # # # # : 0 : if (ctrlr->is_failed) {
# # # # ]
2057 : : /* The controller state may be changed to failed in one of the nvme_request_check_timeout callbacks. */
2058 : 0 : return;
2059 : : }
2060 [ # # # # : 0 : assert(tcp_req->req != NULL);
# # # # ]
2061 : :
2062 [ # # # # : 0 : if (nvme_request_check_timeout(tcp_req->req, tcp_req->cid, active_proc, t02)) {
# # # # #
# ]
2063 : : /*
2064 : : * The requests are in order, so as soon as one has not timed out,
2065 : : * stop iterating.
2066 : : */
2067 : 0 : break;
2068 : : }
2069 : 0 : }
2070 : 0 : }
2071 : :
2072 : : static int nvme_tcp_ctrlr_connect_qpair_poll(struct spdk_nvme_ctrlr *ctrlr,
2073 : : struct spdk_nvme_qpair *qpair);
2074 : :
2075 : : static int
2076 : 60520069 : nvme_tcp_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions)
2077 : : {
2078 : 60520069 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(qpair);
2079 : 59359108 : uint32_t reaped;
2080 : : int rc;
2081 : :
2082 [ + + + - : 60520069 : if (qpair->poll_group == NULL) {
- + ]
2083 [ + - + - ]: 31366538 : rc = spdk_sock_flush(tqpair->sock);
2084 [ + + + + : 31366538 : if (rc < 0 && errno != EAGAIN) {
# # ]
2085 [ # # # # ]: 527 : SPDK_ERRLOG("Failed to flush tqpair=%p (%d): %s\n", tqpair,
2086 : : errno, spdk_strerror(errno));
2087 [ + + - + : 527 : if (spdk_unlikely(tqpair->qpair.ctrlr->timeout_enabled)) {
# # # # #
# # # #
# ]
2088 : 0 : nvme_tcp_qpair_check_timeout(qpair);
2089 : 0 : }
2090 : :
2091 [ + + ]: 527 : if (nvme_qpair_get_state(qpair) == NVME_QPAIR_DISCONNECTING) {
2092 [ + - # # : 508 : if (TAILQ_EMPTY(&tqpair->outstanding_reqs)) {
# # # # ]
2093 : 508 : nvme_transport_ctrlr_disconnect_qpair_done(qpair);
2094 : 1 : }
2095 : :
2096 : : /* Don't return errors until the qpair gets disconnected */
2097 : 508 : return 0;
2098 : : }
2099 : :
2100 : 19 : goto fail;
2101 : : }
2102 : 1160959 : }
2103 : :
2104 [ + + ]: 60519542 : if (max_completions == 0) {
2105 [ + + + - : 56752285 : max_completions = spdk_max(tqpair->num_entries, 1);
+ - + - +
- ]
2106 : 1160959 : } else {
2107 [ # # # # : 3767257 : max_completions = spdk_min(max_completions, tqpair->num_entries);
# # # # #
# ]
2108 : : }
2109 : :
2110 : 60519542 : reaped = 0;
2111 : 60519542 : rc = nvme_tcp_read_pdu(tqpair, &reaped, max_completions);
2112 [ + + ]: 60519542 : if (rc < 0) {
2113 [ + + - + : 145 : SPDK_DEBUGLOG(nvme, "Error polling CQ! (%d): %s\n",
# # # # #
# ]
2114 : : errno, spdk_strerror(errno));
2115 : 145 : goto fail;
2116 : : }
2117 : :
2118 [ + + + + : 60519397 : if (spdk_unlikely(tqpair->qpair.ctrlr->timeout_enabled)) {
+ - + - +
- + - +
- ]
2119 : 0 : nvme_tcp_qpair_check_timeout(qpair);
2120 : 0 : }
2121 : :
2122 [ + + ]: 60519397 : if (spdk_unlikely(nvme_qpair_get_state(qpair) == NVME_QPAIR_CONNECTING)) {
2123 [ + - + - ]: 6467342 : rc = nvme_tcp_ctrlr_connect_qpair_poll(qpair->ctrlr, qpair);
2124 [ + + + + ]: 6467342 : if (rc != 0 && rc != -EAGAIN) {
2125 : 50 : SPDK_ERRLOG("Failed to connect tqpair=%p\n", tqpair);
2126 : 50 : goto fail;
2127 [ + + ]: 6467292 : } else if (rc == 0) {
2128 : : /* Once the connection is completed, we can submit queued requests */
2129 [ + - + - ]: 5383 : nvme_qpair_resubmit_requests(qpair, tqpair->num_entries);
2130 : 1657 : }
2131 : 977706 : }
2132 : :
2133 : 60519347 : return reaped;
2134 : 212 : fail:
2135 : :
2136 : : /*
2137 : : * Since admin queues take the ctrlr_lock before entering this function,
2138 : : * we can call nvme_transport_ctrlr_disconnect_qpair. For other qpairs we need
2139 : : * to call the generic function which will take the lock for us.
2140 : : */
2141 [ # # ]: 214 : qpair->transport_failure_reason = SPDK_NVME_QPAIR_FAILURE_UNKNOWN;
2142 : :
2143 [ + + ]: 214 : if (nvme_qpair_is_admin_queue(qpair)) {
2144 : 130 : enum nvme_qpair_state state_prev = nvme_qpair_get_state(qpair);
2145 : :
2146 [ # # # # ]: 130 : nvme_transport_ctrlr_disconnect_qpair(qpair->ctrlr, qpair);
2147 : :
2148 [ + + + + : 130 : if (state_prev == NVME_QPAIR_CONNECTING && qpair->poll_status != NULL) {
# # # # ]
2149 : : /* Needed to free the poll_status */
2150 [ # # # # ]: 10 : nvme_tcp_ctrlr_connect_qpair_poll(qpair->ctrlr, qpair);
2151 : 0 : }
2152 : 2 : } else {
2153 : 84 : nvme_ctrlr_disconnect_qpair(qpair);
2154 : : }
2155 : 214 : return -ENXIO;
2156 : 1160961 : }
2157 : :
2158 : : static void
2159 : 29153531 : nvme_tcp_qpair_sock_cb(void *ctx, struct spdk_sock_group *group, struct spdk_sock *sock)
2160 : : {
2161 : 29153531 : struct spdk_nvme_qpair *qpair = ctx;
2162 [ # # # # ]: 29153531 : struct nvme_tcp_poll_group *pgroup = nvme_tcp_poll_group(qpair->poll_group);
2163 : : int32_t num_completions;
2164 : 29153531 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(qpair);
2165 : :
2166 [ - + + + : 29153531 : if (tqpair->needs_poll) {
# # # # ]
2167 [ + + # # : 1216558 : TAILQ_REMOVE(&pgroup->needs_poll, tqpair, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
2168 [ # # # # ]: 1216558 : tqpair->needs_poll = false;
2169 : 0 : }
2170 : :
2171 [ # # # # ]: 29153531 : num_completions = spdk_nvme_qpair_process_completions(qpair, pgroup->completions_per_qpair);
2172 : :
2173 [ + + + + : 29153531 : if (pgroup->num_completions >= 0 && num_completions >= 0) {
# # # # ]
2174 [ # # # # : 29153490 : pgroup->num_completions += num_completions;
# # ]
2175 [ # # # # : 29153490 : pgroup->stats.nvme_completions += num_completions;
# # ]
2176 : 0 : } else {
2177 [ # # # # ]: 41 : pgroup->num_completions = -ENXIO;
2178 : : }
2179 : 29153531 : }
2180 : :
2181 : : static int
2182 : 5439 : nvme_tcp_qpair_icreq_send(struct nvme_tcp_qpair *tqpair)
2183 : : {
2184 : : struct spdk_nvme_tcp_ic_req *ic_req;
2185 : : struct nvme_tcp_pdu *pdu;
2186 : : uint32_t timeout_in_sec;
2187 : :
2188 [ + - + - ]: 5439 : pdu = tqpair->send_pdu;
2189 [ + + + - : 5439 : memset(tqpair->send_pdu, 0, sizeof(*tqpair->send_pdu));
+ - ]
2190 [ + - + - ]: 5439 : ic_req = &pdu->hdr.ic_req;
2191 : :
2192 [ + - + - : 5439 : ic_req->common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_IC_REQ;
+ - ]
2193 [ + - + - : 5439 : ic_req->common.hlen = ic_req->common.plen = sizeof(*ic_req);
+ - + - +
- + - ]
2194 [ + - + - ]: 5439 : ic_req->pfv = 0;
2195 [ + - + - ]: 5439 : ic_req->maxr2t = NVME_TCP_MAX_R2T_DEFAULT - 1;
2196 [ + - + - ]: 5439 : ic_req->hpda = NVME_TCP_HPDA_DEFAULT;
2197 : :
2198 [ + + + - : 5439 : ic_req->dgst.bits.hdgst_enable = tqpair->qpair.ctrlr->opts.header_digest;
+ - + - +
- + - + -
+ - + - +
- ]
2199 [ + + + - : 5439 : ic_req->dgst.bits.ddgst_enable = tqpair->qpair.ctrlr->opts.data_digest;
+ - + - +
- + - + -
+ - + - +
- ]
2200 : :
2201 : 5439 : nvme_tcp_qpair_write_pdu(tqpair, pdu, nvme_tcp_send_icreq_complete, tqpair);
2202 : :
2203 [ + + + - ]: 5439 : timeout_in_sec = tqpair->qpair.async ? ICREQ_TIMEOUT_ASYNC : ICREQ_TIMEOUT_SYNC;
2204 [ + - + - ]: 5439 : tqpair->icreq_timeout_tsc = spdk_get_ticks() + (timeout_in_sec * spdk_get_ticks_hz());
2205 : 5439 : return 0;
2206 : : }
2207 : :
2208 : : static int
2209 : 21704 : nvme_tcp_qpair_connect_sock(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair)
2210 : : {
2211 : 20038 : struct sockaddr_storage dst_addr;
2212 : 20038 : struct sockaddr_storage src_addr;
2213 : : int rc;
2214 : : struct nvme_tcp_qpair *tqpair;
2215 : : int family;
2216 : 21704 : long int port, src_port = 0;
2217 : : char *sock_impl_name;
2218 : 21704 : struct spdk_sock_impl_opts impl_opts = {};
2219 : 21704 : size_t impl_opts_size = sizeof(impl_opts);
2220 : 20038 : struct spdk_sock_opts opts;
2221 : : struct nvme_tcp_ctrlr *tcp_ctrlr;
2222 : :
2223 : 21704 : tqpair = nvme_tcp_qpair(qpair);
2224 : :
2225 [ + + + - : 21704 : switch (ctrlr->trid.adrfam) {
+ - - +
- ]
2226 : 20032 : case SPDK_NVMF_ADRFAM_IPV4:
2227 : 21696 : family = AF_INET;
2228 : 21696 : break;
2229 : 0 : case SPDK_NVMF_ADRFAM_IPV6:
2230 : 0 : family = AF_INET6;
2231 : 0 : break;
2232 : 6 : default:
2233 [ # # # # : 8 : SPDK_ERRLOG("Unhandled ADRFAM %d\n", ctrlr->trid.adrfam);
# # ]
2234 : 8 : rc = -1;
2235 : 8 : return rc;
2236 : : }
2237 : :
2238 [ + + + + : 21696 : SPDK_DEBUGLOG(nvme, "adrfam %d ai_family %d\n", ctrlr->trid.adrfam, family);
+ - # # #
# # # ]
2239 : :
2240 [ + + ]: 21696 : memset(&dst_addr, 0, sizeof(dst_addr));
2241 : :
2242 [ + + + + : 21696 : SPDK_DEBUGLOG(nvme, "trsvcid is %s\n", ctrlr->trid.trsvcid);
+ - # # #
# ]
2243 [ + - + - : 21696 : rc = nvme_parse_addr(&dst_addr, family, ctrlr->trid.traddr, ctrlr->trid.trsvcid, &port);
+ - + - ]
2244 [ + + ]: 21696 : if (rc != 0) {
2245 : 8 : SPDK_ERRLOG("dst_addr nvme_parse_addr() failed\n");
2246 : 8 : return rc;
2247 : : }
2248 : :
2249 [ + + + + : 21688 : if (ctrlr->opts.src_addr[0] || ctrlr->opts.src_svcid[0]) {
+ - + - +
- + - + -
+ - + - +
- + - -
+ ]
2250 [ - + ]: 36 : memset(&src_addr, 0, sizeof(src_addr));
2251 : 72 : rc = nvme_parse_addr(&src_addr, family,
2252 [ + - # # : 36 : ctrlr->opts.src_addr[0] ? ctrlr->opts.src_addr : NULL,
# # # # #
# # # # #
# # ]
2253 [ + + # # : 36 : ctrlr->opts.src_svcid[0] ? ctrlr->opts.src_svcid : NULL,
# # # # #
# # # # #
# # ]
2254 : : &src_port);
2255 [ - + ]: 36 : if (rc != 0) {
2256 : 0 : SPDK_ERRLOG("src_addr nvme_parse_addr() failed\n");
2257 : 0 : return rc;
2258 : : }
2259 : 6 : }
2260 : :
2261 : 21688 : tcp_ctrlr = SPDK_CONTAINEROF(ctrlr, struct nvme_tcp_ctrlr, ctrlr);
2262 [ + + + - : 21688 : sock_impl_name = tcp_ctrlr->psk[0] ? "ssl" : NULL;
+ - + - ]
2263 [ + + + + : 21688 : SPDK_DEBUGLOG(nvme, "sock_impl_name is %s\n", sock_impl_name);
+ - ]
2264 : :
2265 [ + + ]: 21688 : if (sock_impl_name) {
2266 : 130 : spdk_sock_impl_get_opts(sock_impl_name, &impl_opts, &impl_opts_size);
2267 [ # # ]: 130 : impl_opts.tls_version = SPDK_TLS_VERSION_1_3;
2268 [ # # # # ]: 130 : impl_opts.psk_identity = tcp_ctrlr->psk_identity;
2269 [ # # # # ]: 130 : impl_opts.psk_key = tcp_ctrlr->psk;
2270 [ # # # # : 130 : impl_opts.psk_key_size = tcp_ctrlr->psk_size;
# # ]
2271 [ # # # # : 130 : impl_opts.tls_cipher_suites = tcp_ctrlr->tls_cipher_suite;
# # ]
2272 : 0 : }
2273 : 21688 : opts.opts_size = sizeof(opts);
2274 : 21688 : spdk_sock_get_default_opts(&opts);
2275 [ + - + - : 21688 : opts.priority = ctrlr->trid.priority;
+ - + - ]
2276 [ + - ]: 21688 : opts.zcopy = !nvme_qpair_is_admin_queue(qpair);
2277 [ + + + - : 21688 : opts.src_addr = ctrlr->opts.src_addr[0] ? ctrlr->opts.src_addr : NULL;
+ - + - +
- - + # #
# # + - ]
2278 [ + - ]: 21688 : opts.src_port = src_port;
2279 [ + + + - : 21688 : if (ctrlr->opts.transport_ack_timeout) {
+ - + - ]
2280 [ - + # # : 39 : opts.ack_timeout = 1ULL << ctrlr->opts.transport_ack_timeout;
# # # # #
# ]
2281 : 3 : }
2282 [ + + ]: 21688 : if (sock_impl_name) {
2283 [ # # ]: 130 : opts.impl_opts = &impl_opts;
2284 [ # # ]: 130 : opts.impl_opts_size = sizeof(impl_opts);
2285 : 0 : }
2286 [ + - + - : 21688 : tqpair->sock = spdk_sock_connect_ext(ctrlr->trid.traddr, port, sock_impl_name, &opts);
+ - + - ]
2287 [ + + + - : 21688 : if (!tqpair->sock) {
+ - ]
2288 [ # # # # ]: 16237 : SPDK_ERRLOG("sock connection error of tqpair=%p with addr=%s, port=%ld\n",
2289 : : tqpair, ctrlr->trid.traddr, port);
2290 : 16237 : rc = -1;
2291 : 16237 : return rc;
2292 : : }
2293 : :
2294 : 5451 : return 0;
2295 : 1666 : }
2296 : :
2297 : : static int
2298 : 6467352 : nvme_tcp_ctrlr_connect_qpair_poll(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair)
2299 : : {
2300 : : struct nvme_tcp_qpair *tqpair;
2301 : : int rc;
2302 : :
2303 : 6467352 : tqpair = nvme_tcp_qpair(qpair);
2304 : :
2305 : : /* Prevent this function from being called recursively, as it could lead to issues with
2306 : : * nvme_fabric_qpair_connect_poll() if the connect response is received in the recursive
2307 : : * call.
2308 : : */
2309 [ + + + - : 6467352 : if (tqpair->flags.in_connect_poll) {
+ + ]
2310 : 271730 : return -EAGAIN;
2311 : : }
2312 : :
2313 [ + - + - ]: 6195622 : tqpair->flags.in_connect_poll = 1;
2314 : :
2315 [ + + + + : 6195622 : switch (tqpair->state) {
+ - + + +
- ]
2316 : 4897034 : case NVME_TCP_QPAIR_STATE_INVALID:
2317 : : case NVME_TCP_QPAIR_STATE_INITIALIZING:
2318 [ + + + - : 5839546 : if (spdk_get_ticks() > tqpair->icreq_timeout_tsc) {
- + ]
2319 : 0 : SPDK_ERRLOG("Failed to construct the tqpair=%p via correct icresp\n", tqpair);
2320 : 0 : rc = -ETIMEDOUT;
2321 : 0 : break;
2322 : : }
2323 : 5839546 : rc = -EAGAIN;
2324 : 5839546 : break;
2325 : 3763 : case NVME_TCP_QPAIR_STATE_FABRIC_CONNECT_SEND:
2326 [ + - + - : 5420 : rc = nvme_fabric_qpair_connect_async(&tqpair->qpair, tqpair->num_entries + 1);
+ - + - ]
2327 [ + + ]: 5420 : if (rc < 0) {
2328 : 0 : SPDK_ERRLOG("Failed to send an NVMe-oF Fabric CONNECT command\n");
2329 : 0 : break;
2330 : : }
2331 [ + - + - ]: 5420 : tqpair->state = NVME_TCP_QPAIR_STATE_FABRIC_CONNECT_POLL;
2332 : 5420 : rc = -EAGAIN;
2333 : 5420 : break;
2334 : 147702 : case NVME_TCP_QPAIR_STATE_FABRIC_CONNECT_POLL:
2335 [ + - ]: 164471 : rc = nvme_fabric_qpair_connect_poll(&tqpair->qpair);
2336 [ + + ]: 164471 : if (rc == 0) {
2337 [ + + ]: 5419 : if (nvme_fabric_qpair_auth_required(qpair)) {
2338 : 759 : rc = nvme_fabric_qpair_authenticate_async(qpair);
2339 [ + + ]: 759 : if (rc == 0) {
2340 [ # # # # ]: 748 : tqpair->state = NVME_TCP_QPAIR_STATE_AUTHENTICATING;
2341 : 748 : rc = -EAGAIN;
2342 : 0 : }
2343 : 0 : } else {
2344 [ + - + - ]: 4660 : tqpair->state = NVME_TCP_QPAIR_STATE_RUNNING;
2345 : 4660 : nvme_qpair_set_state(qpair, NVME_QPAIR_CONNECTED);
2346 : : }
2347 [ + + ]: 160709 : } else if (rc != -EAGAIN) {
2348 : 1 : SPDK_ERRLOG("Failed to poll NVMe-oF Fabric CONNECT command\n");
2349 : 0 : }
2350 : 164471 : break;
2351 : 186185 : case NVME_TCP_QPAIR_STATE_AUTHENTICATING:
2352 : 186185 : rc = nvme_fabric_qpair_authenticate_poll(qpair);
2353 [ + + ]: 186185 : if (rc == 0) {
2354 [ # # # # ]: 723 : tqpair->state = NVME_TCP_QPAIR_STATE_RUNNING;
2355 : 723 : nvme_qpair_set_state(qpair, NVME_QPAIR_CONNECTED);
2356 : 0 : }
2357 : 186185 : break;
2358 : 0 : case NVME_TCP_QPAIR_STATE_RUNNING:
2359 : 0 : rc = 0;
2360 : 0 : break;
2361 : 0 : default:
2362 [ # # ]: 0 : assert(false);
2363 : : rc = -EINVAL;
2364 : : break;
2365 : : }
2366 : :
2367 [ + - + - ]: 6195622 : tqpair->flags.in_connect_poll = 0;
2368 : 6195622 : return rc;
2369 : 977706 : }
2370 : :
2371 : : static int
2372 : 21654 : nvme_tcp_ctrlr_connect_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair)
2373 : : {
2374 : 21654 : int rc = 0;
2375 : : struct nvme_tcp_qpair *tqpair;
2376 : : struct nvme_tcp_poll_group *tgroup;
2377 : :
2378 : 21654 : tqpair = nvme_tcp_qpair(qpair);
2379 : :
2380 [ + + + - : 21654 : if (!tqpair->sock) {
+ - ]
2381 : 16270 : rc = nvme_tcp_qpair_connect_sock(ctrlr, qpair);
2382 [ + + ]: 16270 : if (rc < 0) {
2383 : 16219 : return rc;
2384 : : }
2385 : 0 : }
2386 : :
2387 [ + + + - : 5435 : if (qpair->poll_group) {
- + ]
2388 : 1063 : rc = nvme_poll_group_connect_qpair(qpair);
2389 [ - + ]: 1063 : if (rc) {
2390 : 0 : SPDK_ERRLOG("Unable to activate the tcp qpair.\n");
2391 : 0 : return rc;
2392 : : }
2393 [ # # # # ]: 1063 : tgroup = nvme_tcp_poll_group(qpair->poll_group);
2394 [ # # # # : 1063 : tqpair->stats = &tgroup->stats;
# # ]
2395 [ # # # # ]: 1063 : tqpair->shared_stats = true;
2396 : 0 : } else {
2397 : : /* When resetting a controller, we disconnect adminq and then reconnect. The stats
2398 : : * is not freed when disconnecting. So when reconnecting, don't allocate memory
2399 : : * again.
2400 : : */
2401 [ + + + - : 4372 : if (tqpair->stats == NULL) {
- + ]
2402 [ + - + - ]: 4321 : tqpair->stats = calloc(1, sizeof(*tqpair->stats));
2403 [ + + + - : 4321 : if (!tqpair->stats) {
- + ]
2404 : 0 : SPDK_ERRLOG("tcp stats memory allocation failed\n");
2405 : 0 : return -ENOMEM;
2406 : : }
2407 : 1657 : }
2408 : : }
2409 : :
2410 [ + - + - ]: 5435 : tqpair->maxr2t = NVME_TCP_MAX_R2T_DEFAULT;
2411 : : /* Explicitly set the state and recv_state of tqpair */
2412 [ + - + - ]: 5435 : tqpair->state = NVME_TCP_QPAIR_STATE_INVALID;
2413 [ + + + - : 5435 : if (tqpair->recv_state != NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY) {
+ - ]
2414 : 51 : nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY);
2415 : 0 : }
2416 : 5435 : rc = nvme_tcp_qpair_icreq_send(tqpair);
2417 [ + + ]: 5435 : if (rc != 0) {
2418 : 0 : SPDK_ERRLOG("Unable to connect the tqpair\n");
2419 : 0 : return rc;
2420 : : }
2421 : :
2422 : 5435 : return rc;
2423 : 1657 : }
2424 : :
2425 : : static struct spdk_nvme_qpair *
2426 : 5430 : nvme_tcp_ctrlr_create_qpair(struct spdk_nvme_ctrlr *ctrlr,
2427 : : uint16_t qid, uint32_t qsize,
2428 : : enum spdk_nvme_qprio qprio,
2429 : : uint32_t num_requests, bool async)
2430 : : {
2431 : : struct nvme_tcp_qpair *tqpair;
2432 : : struct spdk_nvme_qpair *qpair;
2433 : : int rc;
2434 : :
2435 [ + + ]: 5430 : if (qsize < SPDK_NVME_QUEUE_MIN_ENTRIES) {
2436 : 12 : SPDK_ERRLOG("Failed to create qpair with size %u. Minimum queue size is %d.\n",
2437 : : qsize, SPDK_NVME_QUEUE_MIN_ENTRIES);
2438 : 12 : return NULL;
2439 : : }
2440 : :
2441 : 5418 : tqpair = calloc(1, sizeof(struct nvme_tcp_qpair));
2442 [ + + ]: 5418 : if (!tqpair) {
2443 : 0 : SPDK_ERRLOG("failed to get create tqpair\n");
2444 : 0 : return NULL;
2445 : : }
2446 : :
2447 : : /* Set num_entries one less than queue size. According to NVMe
2448 : : * and NVMe-oF specs we can not submit queue size requests,
2449 : : * one slot shall always remain empty.
2450 : : */
2451 [ - + - + ]: 5418 : tqpair->num_entries = qsize - 1;
2452 [ - + ]: 5418 : qpair = &tqpair->qpair;
2453 [ - + ]: 5418 : rc = nvme_qpair_init(qpair, qid, ctrlr, qprio, num_requests, async);
2454 [ - + ]: 5418 : if (rc != 0) {
2455 : 0 : free(tqpair);
2456 : 0 : return NULL;
2457 : : }
2458 : :
2459 : 5418 : rc = nvme_tcp_alloc_reqs(tqpair);
2460 [ - + ]: 5418 : if (rc) {
2461 : 0 : nvme_tcp_ctrlr_delete_io_qpair(ctrlr, qpair);
2462 : 0 : return NULL;
2463 : : }
2464 : :
2465 : : /* spdk_nvme_qpair_get_optimal_poll_group needs socket information.
2466 : : * So create the socket first when creating a qpair. */
2467 : 5418 : rc = nvme_tcp_qpair_connect_sock(ctrlr, qpair);
2468 [ + + ]: 5418 : if (rc) {
2469 : 22 : nvme_tcp_ctrlr_delete_io_qpair(ctrlr, qpair);
2470 : 22 : return NULL;
2471 : : }
2472 : :
2473 : 5396 : return qpair;
2474 : 1665 : }
2475 : :
2476 : : static struct spdk_nvme_qpair *
2477 : 3231 : nvme_tcp_ctrlr_create_io_qpair(struct spdk_nvme_ctrlr *ctrlr, uint16_t qid,
2478 : : const struct spdk_nvme_io_qpair_opts *opts)
2479 : : {
2480 [ + - + - : 4063 : return nvme_tcp_ctrlr_create_qpair(ctrlr, qid, opts->io_queue_size, opts->qprio,
+ - + - ]
2481 [ + + + - : 3231 : opts->io_queue_requests, opts->async_mode);
+ - + - +
- ]
2482 : : }
2483 : :
2484 : : static int
2485 : 62 : nvme_tcp_generate_tls_credentials(struct nvme_tcp_ctrlr *tctrlr)
2486 : : {
2487 [ # # ]: 62 : struct spdk_nvme_ctrlr *ctrlr = &tctrlr->ctrlr;
2488 : : int rc;
2489 : 62 : uint8_t psk_retained[SPDK_TLS_PSK_MAX_LEN] = {};
2490 : 62 : uint8_t psk_configured[SPDK_TLS_PSK_MAX_LEN] = {};
2491 : 62 : uint8_t pskbuf[SPDK_TLS_PSK_MAX_LEN + 1] = {};
2492 : : uint8_t tls_cipher_suite;
2493 : 62 : uint8_t psk_retained_hash;
2494 : 62 : uint64_t psk_configured_size;
2495 : :
2496 [ # # # # : 62 : rc = spdk_key_get_key(ctrlr->opts.tls_psk, pskbuf, SPDK_TLS_PSK_MAX_LEN);
# # ]
2497 [ + + ]: 62 : if (rc < 0) {
2498 [ # # # # : 3 : SPDK_ERRLOG("Failed to obtain key '%s': %s\n",
# # # # ]
2499 : : spdk_key_get_name(ctrlr->opts.tls_psk), spdk_strerror(-rc));
2500 : 3 : goto finish;
2501 : : }
2502 : :
2503 : 59 : rc = nvme_tcp_parse_interchange_psk(pskbuf, psk_configured, sizeof(psk_configured),
2504 : : &psk_configured_size, &psk_retained_hash);
2505 [ - + ]: 59 : if (rc < 0) {
2506 : 0 : SPDK_ERRLOG("Failed to parse PSK interchange!\n");
2507 : 0 : goto finish;
2508 : : }
2509 : :
2510 : : /* The Base64 string encodes the configured PSK (32 or 48 bytes binary).
2511 : : * This check also ensures that psk_configured_size is smaller than
2512 : : * psk_retained buffer size. */
2513 [ + + ]: 59 : if (psk_configured_size == SHA256_DIGEST_LENGTH) {
2514 : 41 : tls_cipher_suite = NVME_TCP_CIPHER_AES_128_GCM_SHA256;
2515 [ # # # # ]: 41 : tctrlr->tls_cipher_suite = "TLS_AES_128_GCM_SHA256";
2516 [ + - ]: 18 : } else if (psk_configured_size == SHA384_DIGEST_LENGTH) {
2517 : 18 : tls_cipher_suite = NVME_TCP_CIPHER_AES_256_GCM_SHA384;
2518 [ # # # # ]: 18 : tctrlr->tls_cipher_suite = "TLS_AES_256_GCM_SHA384";
2519 : 0 : } else {
2520 : 0 : SPDK_ERRLOG("Unrecognized cipher suite!\n");
2521 : 0 : rc = -ENOTSUP;
2522 : 0 : goto finish;
2523 : : }
2524 : :
2525 [ # # ]: 59 : rc = nvme_tcp_generate_psk_identity(tctrlr->psk_identity, sizeof(tctrlr->psk_identity),
2526 [ # # # # : 59 : ctrlr->opts.hostnqn, ctrlr->trid.subnqn,
# # # # ]
2527 : 0 : tls_cipher_suite);
2528 [ - + ]: 59 : if (rc) {
2529 : 0 : SPDK_ERRLOG("could not generate PSK identity\n");
2530 : 0 : goto finish;
2531 : : }
2532 : :
2533 : : /* No hash indicates that Configured PSK must be used as Retained PSK. */
2534 [ + + ]: 59 : if (psk_retained_hash == NVME_TCP_HASH_ALGORITHM_NONE) {
2535 [ - + # # ]: 21 : assert(psk_configured_size < sizeof(psk_retained));
2536 [ - + - + ]: 21 : memcpy(psk_retained, psk_configured, psk_configured_size);
2537 : 21 : rc = psk_configured_size;
2538 : 0 : } else {
2539 : : /* Derive retained PSK. */
2540 [ # # # # ]: 38 : rc = nvme_tcp_derive_retained_psk(psk_configured, psk_configured_size, ctrlr->opts.hostnqn,
2541 : 0 : psk_retained, sizeof(psk_retained), psk_retained_hash);
2542 [ - + ]: 38 : if (rc < 0) {
2543 : 0 : SPDK_ERRLOG("Unable to derive retained PSK!\n");
2544 : 0 : goto finish;
2545 : : }
2546 : : }
2547 : :
2548 [ # # # # ]: 59 : rc = nvme_tcp_derive_tls_psk(psk_retained, rc, tctrlr->psk_identity, tctrlr->psk,
2549 : 0 : sizeof(tctrlr->psk), tls_cipher_suite);
2550 [ - + ]: 59 : if (rc < 0) {
2551 : 0 : SPDK_ERRLOG("Could not generate TLS PSK!\n");
2552 : 0 : goto finish;
2553 : : }
2554 : :
2555 [ # # # # ]: 59 : tctrlr->psk_size = rc;
2556 : 59 : rc = 0;
2557 : 62 : finish:
2558 : 62 : spdk_memset_s(psk_configured, sizeof(psk_configured), 0, sizeof(psk_configured));
2559 : 62 : spdk_memset_s(pskbuf, sizeof(pskbuf), 0, sizeof(pskbuf));
2560 : :
2561 : 62 : return rc;
2562 : : }
2563 : :
2564 : : /* We have to use the typedef in the function declaration to appease astyle. */
2565 : : typedef struct spdk_nvme_ctrlr spdk_nvme_ctrlr_t;
2566 : :
2567 : : static spdk_nvme_ctrlr_t *
2568 : 2202 : nvme_tcp_ctrlr_construct(const struct spdk_nvme_transport_id *trid,
2569 : : const struct spdk_nvme_ctrlr_opts *opts,
2570 : : void *devhandle)
2571 : : {
2572 : : struct nvme_tcp_ctrlr *tctrlr;
2573 : : struct nvme_tcp_qpair *tqpair;
2574 : : int rc;
2575 : :
2576 : 2202 : tctrlr = calloc(1, sizeof(*tctrlr));
2577 [ + + ]: 2202 : if (tctrlr == NULL) {
2578 : 0 : SPDK_ERRLOG("could not allocate ctrlr\n");
2579 : 0 : return NULL;
2580 : : }
2581 : :
2582 [ + - + - ]: 2202 : tctrlr->ctrlr.opts = *opts;
2583 [ + - + - ]: 2202 : tctrlr->ctrlr.trid = *trid;
2584 : :
2585 [ + + + - : 2202 : if (opts->tls_psk != NULL) {
+ - ]
2586 : 62 : rc = nvme_tcp_generate_tls_credentials(tctrlr);
2587 [ + + ]: 62 : if (rc != 0) {
2588 : 3 : free(tctrlr);
2589 : 3 : return NULL;
2590 : : }
2591 : 0 : }
2592 : :
2593 [ + + + - : 2199 : if (opts->transport_ack_timeout > NVME_TCP_CTRLR_MAX_TRANSPORT_ACK_TIMEOUT) {
+ - ]
2594 : 20 : SPDK_NOTICELOG("transport_ack_timeout exceeds max value %d, use max value\n",
2595 : : NVME_TCP_CTRLR_MAX_TRANSPORT_ACK_TIMEOUT);
2596 [ # # # # : 20 : tctrlr->ctrlr.opts.transport_ack_timeout = NVME_TCP_CTRLR_MAX_TRANSPORT_ACK_TIMEOUT;
# # # # ]
2597 : 5 : }
2598 : :
2599 [ + - ]: 2199 : rc = nvme_ctrlr_construct(&tctrlr->ctrlr);
2600 [ - + ]: 2199 : if (rc != 0) {
2601 : 0 : free(tctrlr);
2602 : 0 : return NULL;
2603 : : }
2604 : :
2605 : : /* Sequence might be used not only for data digest offload purposes but
2606 : : * to handle a potential COPY operation appended as the result of translation. */
2607 [ + - + - : 2199 : tctrlr->ctrlr.flags |= SPDK_NVME_CTRLR_ACCEL_SEQUENCE_SUPPORTED;
+ - ]
2608 [ + - + - : 3032 : tctrlr->ctrlr.adminq = nvme_tcp_ctrlr_create_qpair(&tctrlr->ctrlr, 0,
+ - + - ]
2609 [ + - + - : 2199 : tctrlr->ctrlr.opts.admin_queue_size, 0,
+ - + - ]
2610 [ + - + - : 2199 : tctrlr->ctrlr.opts.admin_queue_size, true);
+ - + - ]
2611 [ + + + - : 2199 : if (!tctrlr->ctrlr.adminq) {
+ - + - ]
2612 : 26 : SPDK_ERRLOG("failed to create admin qpair\n");
2613 [ # # ]: 26 : nvme_tcp_ctrlr_destruct(&tctrlr->ctrlr);
2614 : 26 : return NULL;
2615 : : }
2616 : :
2617 [ + - + - : 2173 : tqpair = nvme_tcp_qpair(tctrlr->ctrlr.adminq);
+ - ]
2618 [ + - + - : 2173 : tctrlr->ctrlr.numa.id_valid = 1;
+ - ]
2619 [ + - + - : 2173 : tctrlr->ctrlr.numa.id = spdk_sock_get_numa_id(tqpair->sock);
+ - + - +
- ]
2620 : :
2621 [ + + - + ]: 2173 : if (nvme_ctrlr_add_process(&tctrlr->ctrlr, 0) != 0) {
2622 : 0 : SPDK_ERRLOG("nvme_ctrlr_add_process() failed\n");
2623 [ # # ]: 0 : nvme_ctrlr_destruct(&tctrlr->ctrlr);
2624 : 0 : return NULL;
2625 : : }
2626 : :
2627 [ - + ]: 2173 : return &tctrlr->ctrlr;
2628 : 833 : }
2629 : :
2630 : : static uint32_t
2631 : 2154 : nvme_tcp_ctrlr_get_max_xfer_size(struct spdk_nvme_ctrlr *ctrlr)
2632 : : {
2633 : : /* TCP transport doesn't limit maximum IO transfer size. */
2634 : 2154 : return UINT32_MAX;
2635 : : }
2636 : :
2637 : : static uint16_t
2638 : 2154 : nvme_tcp_ctrlr_get_max_sges(struct spdk_nvme_ctrlr *ctrlr)
2639 : : {
2640 : 2154 : return NVME_TCP_MAX_SGL_DESCRIPTORS;
2641 : : }
2642 : :
2643 : : static int
2644 : 349894 : nvme_tcp_qpair_iterate_requests(struct spdk_nvme_qpair *qpair,
2645 : : int (*iter_fn)(struct nvme_request *req, void *arg),
2646 : : void *arg)
2647 : : {
2648 : 349894 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(qpair);
2649 : : struct nvme_tcp_req *tcp_req, *tmp;
2650 : : int rc;
2651 : :
2652 [ - + # # ]: 349894 : assert(iter_fn != NULL);
2653 : :
2654 [ + + # # : 21066493 : TAILQ_FOREACH_SAFE(tcp_req, &tqpair->outstanding_reqs, link, tmp) {
# # # # #
# # # # #
# # ]
2655 [ - + # # : 20716631 : assert(tcp_req->req != NULL);
# # # # ]
2656 : :
2657 [ # # # # : 20716631 : rc = iter_fn(tcp_req->req, arg);
# # # # ]
2658 [ + + ]: 20716631 : if (rc != 0) {
2659 : 32 : return rc;
2660 : : }
2661 : 0 : }
2662 : :
2663 : 349862 : return 0;
2664 : 0 : }
2665 : :
2666 : : static int
2667 : 18 : nvme_tcp_qpair_authenticate(struct spdk_nvme_qpair *qpair)
2668 : : {
2669 : 18 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(qpair);
2670 : : int rc;
2671 : :
2672 : : /* If the qpair is still connecting, it'll be forced to authenticate later on */
2673 [ - + # # : 18 : if (tqpair->state < NVME_TCP_QPAIR_STATE_RUNNING) {
# # ]
2674 : 0 : return 0;
2675 [ - + # # : 18 : } else if (tqpair->state != NVME_TCP_QPAIR_STATE_RUNNING) {
# # ]
2676 : 0 : return -ENOTCONN;
2677 : : }
2678 : :
2679 : 18 : rc = nvme_fabric_qpair_authenticate_async(qpair);
2680 [ + + ]: 18 : if (rc == 0) {
2681 : 14 : nvme_qpair_set_state(qpair, NVME_QPAIR_CONNECTING);
2682 [ # # # # ]: 14 : tqpair->state = NVME_TCP_QPAIR_STATE_AUTHENTICATING;
2683 : 0 : }
2684 : :
2685 : 18 : return rc;
2686 : 0 : }
2687 : :
2688 : : static void
2689 : 2602 : nvme_tcp_admin_qpair_abort_aers(struct spdk_nvme_qpair *qpair)
2690 : : {
2691 : : struct nvme_tcp_req *tcp_req, *tmp;
2692 : 2602 : struct spdk_nvme_cpl cpl = {};
2693 : 2602 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(qpair);
2694 : :
2695 [ + - + - ]: 2602 : cpl.status.sc = SPDK_NVME_SC_ABORTED_SQ_DELETION;
2696 [ + - + - ]: 2602 : cpl.status.sct = SPDK_NVME_SCT_GENERIC;
2697 : :
2698 [ + + + - : 10933 : TAILQ_FOREACH_SAFE(tcp_req, &tqpair->outstanding_reqs, link, tmp) {
+ - + + +
- + - + -
+ + ]
2699 [ + + + - : 8331 : assert(tcp_req->req != NULL);
+ - # # ]
2700 [ + + + - : 8331 : if (tcp_req->req->cmd.opc != SPDK_NVME_OPC_ASYNC_EVENT_REQUEST) {
+ - + - -
+ ]
2701 : 2 : continue;
2702 : : }
2703 : :
2704 : 8329 : nvme_tcp_req_complete(tcp_req, tqpair, &cpl, false);
2705 : 3312 : }
2706 : 2602 : }
2707 : :
2708 : : static struct spdk_nvme_transport_poll_group *
2709 : 955 : nvme_tcp_poll_group_create(void)
2710 : : {
2711 : 955 : struct nvme_tcp_poll_group *group = calloc(1, sizeof(*group));
2712 : :
2713 [ + + ]: 955 : if (group == NULL) {
2714 : 0 : SPDK_ERRLOG("Unable to allocate poll group.\n");
2715 : 0 : return NULL;
2716 : : }
2717 : :
2718 [ # # # # : 955 : TAILQ_INIT(&group->needs_poll);
# # # # #
# # # # #
# # ]
2719 : :
2720 [ # # # # ]: 955 : group->sock_group = spdk_sock_group_create(group);
2721 [ - + # # : 955 : if (group->sock_group == NULL) {
# # ]
2722 : 0 : free(group);
2723 : 0 : SPDK_ERRLOG("Unable to allocate sock group.\n");
2724 : 0 : return NULL;
2725 : : }
2726 : :
2727 [ # # ]: 955 : return &group->group;
2728 : 1 : }
2729 : :
2730 : : static struct spdk_nvme_transport_poll_group *
2731 : 0 : nvme_tcp_qpair_get_optimal_poll_group(struct spdk_nvme_qpair *qpair)
2732 : : {
2733 : 0 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(qpair);
2734 : 0 : struct spdk_sock_group *group = NULL;
2735 : : int rc;
2736 : :
2737 [ # # # # ]: 0 : rc = spdk_sock_get_optimal_sock_group(tqpair->sock, &group, NULL);
2738 [ # # # # ]: 0 : if (!rc && group != NULL) {
2739 : 0 : return spdk_sock_group_get_ctx(group);
2740 : : }
2741 : :
2742 : 0 : return NULL;
2743 : 0 : }
2744 : :
2745 : : static int
2746 : 1063 : nvme_tcp_poll_group_connect_qpair(struct spdk_nvme_qpair *qpair)
2747 : : {
2748 [ # # # # ]: 1063 : struct nvme_tcp_poll_group *group = nvme_tcp_poll_group(qpair->poll_group);
2749 : 1063 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(qpair);
2750 : :
2751 [ - + # # : 1063 : if (spdk_sock_group_add_sock(group->sock_group, tqpair->sock, nvme_tcp_qpair_sock_cb, qpair)) {
# # # # #
# ]
2752 : 0 : return -EPROTO;
2753 : : }
2754 : 1063 : return 0;
2755 : 0 : }
2756 : :
2757 : : static int
2758 : 1063 : nvme_tcp_poll_group_disconnect_qpair(struct spdk_nvme_qpair *qpair)
2759 : : {
2760 [ # # # # ]: 1063 : struct nvme_tcp_poll_group *group = nvme_tcp_poll_group(qpair->poll_group);
2761 : 1063 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(qpair);
2762 : :
2763 [ - + + + : 1063 : if (tqpair->needs_poll) {
# # # # ]
2764 [ - + # # : 9 : TAILQ_REMOVE(&group->needs_poll, tqpair, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
2765 [ # # # # ]: 9 : tqpair->needs_poll = false;
2766 : 0 : }
2767 : :
2768 [ + - + - : 1063 : if (tqpair->sock && group->sock_group) {
# # # # #
# # # ]
2769 [ - + # # : 1063 : if (spdk_sock_group_remove_sock(group->sock_group, tqpair->sock)) {
# # # # #
# ]
2770 : 0 : return -EPROTO;
2771 : : }
2772 : 0 : }
2773 : 1063 : return 0;
2774 : 0 : }
2775 : :
2776 : : static int
2777 : 1063 : nvme_tcp_poll_group_add(struct spdk_nvme_transport_poll_group *tgroup,
2778 : : struct spdk_nvme_qpair *qpair)
2779 : : {
2780 : 1063 : struct nvme_tcp_qpair *tqpair = nvme_tcp_qpair(qpair);
2781 : 1063 : struct nvme_tcp_poll_group *group = nvme_tcp_poll_group(tgroup);
2782 : :
2783 : : /* disconnected qpairs won't have a sock to add. */
2784 [ - + ]: 1063 : if (nvme_qpair_get_state(qpair) >= NVME_QPAIR_CONNECTED) {
2785 [ # # # # : 0 : if (spdk_sock_group_add_sock(group->sock_group, tqpair->sock, nvme_tcp_qpair_sock_cb, qpair)) {
# # # # #
# ]
2786 : 0 : return -EPROTO;
2787 : : }
2788 : 0 : }
2789 : :
2790 : 1063 : return 0;
2791 : 0 : }
2792 : :
2793 : : static int
2794 : 1063 : nvme_tcp_poll_group_remove(struct spdk_nvme_transport_poll_group *tgroup,
2795 : : struct spdk_nvme_qpair *qpair)
2796 : : {
2797 : : struct nvme_tcp_qpair *tqpair;
2798 : : struct nvme_tcp_poll_group *group;
2799 : :
2800 [ - + # # : 1063 : assert(qpair->poll_group_tailq_head == &tgroup->disconnected_qpairs);
# # # # #
# ]
2801 : :
2802 : 1063 : tqpair = nvme_tcp_qpair(qpair);
2803 : 1063 : group = nvme_tcp_poll_group(tgroup);
2804 : :
2805 [ - + - + : 1063 : assert(tqpair->shared_stats == true);
# # # # #
# ]
2806 [ # # # # ]: 1063 : tqpair->stats = &g_dummy_stats;
2807 : :
2808 [ - + + + : 1063 : if (tqpair->needs_poll) {
# # # # ]
2809 [ - + # # : 2 : TAILQ_REMOVE(&group->needs_poll, tqpair, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
2810 [ # # # # ]: 2 : tqpair->needs_poll = false;
2811 : 0 : }
2812 : :
2813 : 1063 : return 0;
2814 : : }
2815 : :
2816 : : static int64_t
2817 : 293881472 : nvme_tcp_poll_group_process_completions(struct spdk_nvme_transport_poll_group *tgroup,
2818 : : uint32_t completions_per_qpair, spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb)
2819 : : {
2820 : 293881472 : struct nvme_tcp_poll_group *group = nvme_tcp_poll_group(tgroup);
2821 : : struct spdk_nvme_qpair *qpair, *tmp_qpair;
2822 : : struct nvme_tcp_qpair *tqpair, *tmp_tqpair;
2823 : : int num_events;
2824 : :
2825 [ # # # # ]: 293881472 : group->completions_per_qpair = completions_per_qpair;
2826 [ # # # # ]: 293881472 : group->num_completions = 0;
2827 [ # # # # ]: 293881472 : group->stats.polls++;
2828 : :
2829 [ # # # # ]: 293881472 : num_events = spdk_sock_group_poll(group->sock_group);
2830 : :
2831 [ + + + + : 297554479 : STAILQ_FOREACH_SAFE(qpair, &tgroup->disconnected_qpairs, poll_group_stailq, tmp_qpair) {
# # # # #
# # # # #
# # ]
2832 : 3673007 : tqpair = nvme_tcp_qpair(qpair);
2833 [ + + ]: 3673007 : if (nvme_qpair_get_state(qpair) == NVME_QPAIR_DISCONNECTING) {
2834 [ + + # # : 912 : if (TAILQ_EMPTY(&tqpair->outstanding_reqs)) {
# # # # ]
2835 : 908 : nvme_transport_ctrlr_disconnect_qpair_done(qpair);
2836 : 1 : }
2837 : 2 : }
2838 : : /* Wait until the qpair transitions to the DISCONNECTED state, otherwise user might
2839 : : * want to free it from disconnect_qpair_cb, while it's not fully disconnected (and
2840 : : * might still have outstanding requests) */
2841 [ + + ]: 3673007 : if (nvme_qpair_get_state(qpair) == NVME_QPAIR_DISCONNECTED) {
2842 [ # # # # : 3673003 : disconnected_qpair_cb(qpair, tgroup->group->ctx);
# # # # #
# # # ]
2843 : 1 : }
2844 : 2 : }
2845 : :
2846 : : /* If any qpairs were marked as needing to be polled due to an asynchronous write completion
2847 : : * and they weren't polled as a consequence of calling spdk_sock_group_poll above, poll them now. */
2848 [ + + - + : 294393679 : TAILQ_FOREACH_SAFE(tqpair, &group->needs_poll, link, tmp_tqpair) {
# # # # #
# # # # #
# # ]
2849 [ # # # # : 512207 : nvme_tcp_qpair_sock_cb(&tqpair->qpair, group->sock_group, tqpair->sock);
# # # # #
# ]
2850 : 0 : }
2851 : :
2852 [ + + ]: 293881472 : if (spdk_unlikely(num_events < 0)) {
2853 : 0 : return num_events;
2854 : : }
2855 : :
2856 [ # # # # : 293881472 : group->stats.idle_polls += !num_events;
# # ]
2857 [ # # # # : 293881472 : group->stats.socket_completions += num_events;
# # ]
2858 : :
2859 [ # # # # ]: 293881472 : return group->num_completions;
2860 : 2 : }
2861 : :
2862 : : /*
2863 : : * Handle disconnected qpairs when interrupt support gets added.
2864 : : */
2865 : : static void
2866 : 0 : nvme_tcp_poll_group_check_disconnected_qpairs(struct spdk_nvme_transport_poll_group *tgroup,
2867 : : spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb)
2868 : : {
2869 : 0 : }
2870 : :
2871 : : static int
2872 : 955 : nvme_tcp_poll_group_destroy(struct spdk_nvme_transport_poll_group *tgroup)
2873 : : {
2874 : : int rc;
2875 : 955 : struct nvme_tcp_poll_group *group = nvme_tcp_poll_group(tgroup);
2876 : :
2877 [ + - - + : 955 : if (!STAILQ_EMPTY(&tgroup->connected_qpairs) || !STAILQ_EMPTY(&tgroup->disconnected_qpairs)) {
# # # # #
# # # # #
# # ]
2878 : 0 : return -EBUSY;
2879 : : }
2880 : :
2881 [ # # ]: 955 : rc = spdk_sock_group_close(&group->sock_group);
2882 [ - + ]: 955 : if (rc != 0) {
2883 : 0 : SPDK_ERRLOG("Failed to close the sock group for a tcp poll group.\n");
2884 [ # # ]: 0 : assert(false);
2885 : : }
2886 : :
2887 : 955 : free(tgroup);
2888 : :
2889 : 955 : return 0;
2890 : 1 : }
2891 : :
2892 : : static int
2893 : 18 : nvme_tcp_poll_group_get_stats(struct spdk_nvme_transport_poll_group *tgroup,
2894 : : struct spdk_nvme_transport_poll_group_stat **_stats)
2895 : : {
2896 : : struct nvme_tcp_poll_group *group;
2897 : : struct spdk_nvme_transport_poll_group_stat *stats;
2898 : :
2899 [ + + + + ]: 18 : if (tgroup == NULL || _stats == NULL) {
2900 : 8 : SPDK_ERRLOG("Invalid stats or group pointer\n");
2901 : 8 : return -EINVAL;
2902 : : }
2903 : :
2904 : 10 : group = nvme_tcp_poll_group(tgroup);
2905 : :
2906 : 10 : stats = calloc(1, sizeof(*stats));
2907 [ - + ]: 10 : if (!stats) {
2908 : 0 : SPDK_ERRLOG("Can't allocate memory for TCP stats\n");
2909 : 0 : return -ENOMEM;
2910 : : }
2911 [ # # # # ]: 10 : stats->trtype = SPDK_NVME_TRANSPORT_TCP;
2912 [ - + - + : 10 : memcpy(&stats->tcp, &group->stats, sizeof(group->stats));
# # # # #
# ]
2913 : :
2914 [ # # ]: 10 : *_stats = stats;
2915 : :
2916 : 10 : return 0;
2917 : 3 : }
2918 : :
2919 : : static void
2920 : 10 : nvme_tcp_poll_group_free_stats(struct spdk_nvme_transport_poll_group *tgroup,
2921 : : struct spdk_nvme_transport_poll_group_stat *stats)
2922 : : {
2923 : 10 : free(stats);
2924 : 10 : }
2925 : :
2926 : : static int
2927 : 3518 : nvme_tcp_ctrlr_get_memory_domains(const struct spdk_nvme_ctrlr *ctrlr,
2928 : : struct spdk_memory_domain **domains, int array_size)
2929 : : {
2930 [ + + + - ]: 3518 : if (domains && array_size > 0) {
2931 [ # # # # ]: 220 : domains[0] = spdk_memory_domain_get_system_domain();
2932 : 0 : }
2933 : :
2934 : 3518 : return 1;
2935 : : }
2936 : :
2937 : : const struct spdk_nvme_transport_ops tcp_ops = {
2938 : : .name = "TCP",
2939 : : .type = SPDK_NVME_TRANSPORT_TCP,
2940 : : .ctrlr_construct = nvme_tcp_ctrlr_construct,
2941 : : .ctrlr_scan = nvme_fabric_ctrlr_scan,
2942 : : .ctrlr_destruct = nvme_tcp_ctrlr_destruct,
2943 : : .ctrlr_enable = nvme_tcp_ctrlr_enable,
2944 : :
2945 : : .ctrlr_set_reg_4 = nvme_fabric_ctrlr_set_reg_4,
2946 : : .ctrlr_set_reg_8 = nvme_fabric_ctrlr_set_reg_8,
2947 : : .ctrlr_get_reg_4 = nvme_fabric_ctrlr_get_reg_4,
2948 : : .ctrlr_get_reg_8 = nvme_fabric_ctrlr_get_reg_8,
2949 : : .ctrlr_set_reg_4_async = nvme_fabric_ctrlr_set_reg_4_async,
2950 : : .ctrlr_set_reg_8_async = nvme_fabric_ctrlr_set_reg_8_async,
2951 : : .ctrlr_get_reg_4_async = nvme_fabric_ctrlr_get_reg_4_async,
2952 : : .ctrlr_get_reg_8_async = nvme_fabric_ctrlr_get_reg_8_async,
2953 : :
2954 : : .ctrlr_get_max_xfer_size = nvme_tcp_ctrlr_get_max_xfer_size,
2955 : : .ctrlr_get_max_sges = nvme_tcp_ctrlr_get_max_sges,
2956 : :
2957 : : .ctrlr_create_io_qpair = nvme_tcp_ctrlr_create_io_qpair,
2958 : : .ctrlr_delete_io_qpair = nvme_tcp_ctrlr_delete_io_qpair,
2959 : : .ctrlr_connect_qpair = nvme_tcp_ctrlr_connect_qpair,
2960 : : .ctrlr_disconnect_qpair = nvme_tcp_ctrlr_disconnect_qpair,
2961 : :
2962 : : .ctrlr_get_memory_domains = nvme_tcp_ctrlr_get_memory_domains,
2963 : :
2964 : : .qpair_abort_reqs = nvme_tcp_qpair_abort_reqs,
2965 : : .qpair_reset = nvme_tcp_qpair_reset,
2966 : : .qpair_submit_request = nvme_tcp_qpair_submit_request,
2967 : : .qpair_process_completions = nvme_tcp_qpair_process_completions,
2968 : : .qpair_iterate_requests = nvme_tcp_qpair_iterate_requests,
2969 : : .qpair_authenticate = nvme_tcp_qpair_authenticate,
2970 : : .admin_qpair_abort_aers = nvme_tcp_admin_qpair_abort_aers,
2971 : :
2972 : : .poll_group_create = nvme_tcp_poll_group_create,
2973 : : .qpair_get_optimal_poll_group = nvme_tcp_qpair_get_optimal_poll_group,
2974 : : .poll_group_connect_qpair = nvme_tcp_poll_group_connect_qpair,
2975 : : .poll_group_disconnect_qpair = nvme_tcp_poll_group_disconnect_qpair,
2976 : : .poll_group_add = nvme_tcp_poll_group_add,
2977 : : .poll_group_remove = nvme_tcp_poll_group_remove,
2978 : : .poll_group_process_completions = nvme_tcp_poll_group_process_completions,
2979 : : .poll_group_check_disconnected_qpairs = nvme_tcp_poll_group_check_disconnected_qpairs,
2980 : : .poll_group_destroy = nvme_tcp_poll_group_destroy,
2981 : : .poll_group_get_stats = nvme_tcp_poll_group_get_stats,
2982 : : .poll_group_free_stats = nvme_tcp_poll_group_free_stats,
2983 : : };
2984 : :
2985 : 2809 : SPDK_NVME_TRANSPORT_REGISTER(tcp, &tcp_ops);
2986 : :
2987 : : static void
2988 : 2138 : nvme_tcp_trace(void)
2989 : : {
2990 : 2138 : struct spdk_trace_tpoint_opts opts[] = {
2991 : : {
2992 : : "NVME_TCP_SUBMIT", TRACE_NVME_TCP_SUBMIT,
2993 : : OWNER_TYPE_NVME_TCP_QP, OBJECT_NVME_TCP_REQ, 1,
2994 : : { { "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 },
2995 : : { "cid", SPDK_TRACE_ARG_TYPE_INT, 4 },
2996 : : { "opc", SPDK_TRACE_ARG_TYPE_INT, 4 },
2997 : : { "dw10", SPDK_TRACE_ARG_TYPE_PTR, 4 },
2998 : : { "dw11", SPDK_TRACE_ARG_TYPE_PTR, 4 },
2999 : : { "dw12", SPDK_TRACE_ARG_TYPE_PTR, 4 },
3000 : : { "qd", SPDK_TRACE_ARG_TYPE_INT, 4 }
3001 : : }
3002 : : },
3003 : : {
3004 : : "NVME_TCP_COMPLETE", TRACE_NVME_TCP_COMPLETE,
3005 : : OWNER_TYPE_NVME_TCP_QP, OBJECT_NVME_TCP_REQ, 0,
3006 : : { { "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 },
3007 : : { "cid", SPDK_TRACE_ARG_TYPE_INT, 4 },
3008 : : { "cpl", SPDK_TRACE_ARG_TYPE_PTR, 4 },
3009 : : { "qd", SPDK_TRACE_ARG_TYPE_INT, 4 }
3010 : : }
3011 : : },
3012 : : };
3013 : :
3014 : 2138 : spdk_trace_register_object(OBJECT_NVME_TCP_REQ, 'p');
3015 : 2138 : spdk_trace_register_owner_type(OWNER_TYPE_NVME_TCP_QP, 'q');
3016 : 2138 : spdk_trace_register_description_ext(opts, SPDK_COUNTOF(opts));
3017 : :
3018 : 2138 : spdk_trace_tpoint_register_relation(TRACE_SOCK_REQ_QUEUE, OBJECT_NVME_TCP_REQ, 0);
3019 : 2138 : spdk_trace_tpoint_register_relation(TRACE_SOCK_REQ_PEND, OBJECT_NVME_TCP_REQ, 0);
3020 : 2138 : spdk_trace_tpoint_register_relation(TRACE_SOCK_REQ_COMPLETE, OBJECT_NVME_TCP_REQ, 0);
3021 : 2138 : }
3022 : 2809 : SPDK_TRACE_REGISTER_FN(nvme_tcp_trace, "nvme_tcp", TRACE_GROUP_NVME_TCP)
|