Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2022 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/dif.h"
7 : : #include "spdk/crc16.h"
8 : : #include "spdk/crc32.h"
9 : : #include "spdk/crc64.h"
10 : : #include "spdk/endian.h"
11 : : #include "spdk/log.h"
12 : : #include "spdk/util.h"
13 : :
14 : : #define REFTAG_MASK_16 0x00000000FFFFFFFF
15 : : #define REFTAG_MASK_32 0xFFFFFFFFFFFFFFFF
16 : : #define REFTAG_MASK_64 0x0000FFFFFFFFFFFF
17 : :
18 : : /* The variable size Storage Tag and Reference Tag is not supported yet,
19 : : * so the maximum size of the Reference Tag is assumed.
20 : : */
21 : : struct spdk_dif {
22 : : union {
23 : : struct {
24 : : uint16_t guard;
25 : : uint16_t app_tag;
26 : : uint32_t stor_ref_space;
27 : : } g16;
28 : : struct {
29 : : uint32_t guard;
30 : : uint16_t app_tag;
31 : : uint16_t stor_ref_space_p1;
32 : : uint64_t stor_ref_space_p2;
33 : : } g32;
34 : : struct {
35 : : uint64_t guard;
36 : : uint16_t app_tag;
37 : : uint16_t stor_ref_space_p1;
38 : : uint32_t stor_ref_space_p2;
39 : : } g64;
40 : : };
41 : : };
42 : : SPDK_STATIC_ASSERT(SPDK_SIZEOF_MEMBER(struct spdk_dif, g16) == 8, "Incorrect size");
43 : : SPDK_STATIC_ASSERT(SPDK_SIZEOF_MEMBER(struct spdk_dif, g32) == 16, "Incorrect size");
44 : : SPDK_STATIC_ASSERT(SPDK_SIZEOF_MEMBER(struct spdk_dif, g64) == 16, "Incorrect size");
45 : :
46 : : /* Context to iterate or create a iovec array.
47 : : * Each sgl is either iterated or created at a time.
48 : : */
49 : : struct _dif_sgl {
50 : : /* Current iovec in the iteration or creation */
51 : : struct iovec *iov;
52 : :
53 : : /* Remaining count of iovecs in the iteration or creation. */
54 : : int iovcnt;
55 : :
56 : : /* Current offset in the iovec */
57 : : uint32_t iov_offset;
58 : :
59 : : /* Size of the created iovec array in bytes */
60 : : uint32_t total_size;
61 : : };
62 : :
63 : : static inline void
64 : 6517493 : _dif_sgl_init(struct _dif_sgl *s, struct iovec *iovs, int iovcnt)
65 : : {
66 : 6517493 : s->iov = iovs;
67 : 6517493 : s->iovcnt = iovcnt;
68 : 6517493 : s->iov_offset = 0;
69 : 6517493 : s->total_size = 0;
70 : 6517493 : }
71 : :
72 : : static void
73 : 124906104 : _dif_sgl_advance(struct _dif_sgl *s, uint32_t step)
74 : : {
75 : 124906104 : s->iov_offset += step;
76 [ + + ]: 129317678 : while (s->iovcnt != 0) {
77 [ + + ]: 125069481 : if (s->iov_offset < s->iov->iov_len) {
78 : 120657907 : break;
79 : : }
80 : :
81 : 4411574 : s->iov_offset -= s->iov->iov_len;
82 : 4411574 : s->iov++;
83 : 4411574 : s->iovcnt--;
84 : : }
85 : 124906104 : }
86 : :
87 : : static inline void
88 : 96222196 : _dif_sgl_get_buf(struct _dif_sgl *s, uint8_t **_buf, uint32_t *_buf_len)
89 : : {
90 [ + - ]: 96222196 : if (_buf != NULL) {
91 : 96222196 : *_buf = (uint8_t *)s->iov->iov_base + s->iov_offset;
92 : : }
93 [ + + ]: 96222196 : if (_buf_len != NULL) {
94 : 80021462 : *_buf_len = s->iov->iov_len - s->iov_offset;
95 : : }
96 : 96222196 : }
97 : :
98 : : static inline bool
99 : 26774794 : _dif_sgl_append(struct _dif_sgl *s, uint8_t *data, uint32_t data_len)
100 : : {
101 [ - + ]: 26774794 : assert(s->iovcnt > 0);
102 : 26774794 : s->iov->iov_base = data;
103 : 26774794 : s->iov->iov_len = data_len;
104 : 26774794 : s->total_size += data_len;
105 : 26774794 : s->iov++;
106 : 26774794 : s->iovcnt--;
107 : :
108 [ + + ]: 26774794 : if (s->iovcnt > 0) {
109 : 26434564 : return true;
110 : : } else {
111 : 340230 : return false;
112 : : }
113 : : }
114 : :
115 : : static inline bool
116 : 26711988 : _dif_sgl_append_split(struct _dif_sgl *dst, struct _dif_sgl *src, uint32_t data_len)
117 : : {
118 : 416 : uint8_t *buf;
119 : 416 : uint32_t buf_len;
120 : :
121 [ + + ]: 53146552 : while (data_len != 0) {
122 : 26774794 : _dif_sgl_get_buf(src, &buf, &buf_len);
123 : 26774794 : buf_len = spdk_min(buf_len, data_len);
124 : :
125 [ + + ]: 26774794 : if (!_dif_sgl_append(dst, buf, buf_len)) {
126 : 340230 : return false;
127 : : }
128 : :
129 : 26434564 : _dif_sgl_advance(src, buf_len);
130 : 26434564 : data_len -= buf_len;
131 : : }
132 : :
133 : 26371758 : return true;
134 : : }
135 : :
136 : : /* This function must be used before starting iteration. */
137 : : static bool
138 : 1619775 : _dif_sgl_is_bytes_multiple(struct _dif_sgl *s, uint32_t bytes)
139 : : {
140 : : int i;
141 : :
142 [ + + ]: 3210304 : for (i = 0; i < s->iovcnt; i++) {
143 [ + + + + ]: 1624062 : if (s->iov[i].iov_len % bytes) {
144 : 33533 : return false;
145 : : }
146 : : }
147 : :
148 : 1586242 : return true;
149 : : }
150 : :
151 : : static bool
152 : 312886 : _dif_sgl_is_valid_block_aligned(struct _dif_sgl *s, uint32_t num_blocks, uint32_t block_size)
153 : : {
154 : 312886 : uint32_t count = 0;
155 : : int i;
156 : :
157 [ + + ]: 625769 : for (i = 0; i < s->iovcnt; i++) {
158 [ - + + + ]: 312886 : if (s->iov[i].iov_len % block_size) {
159 : 3 : return false;
160 : : }
161 [ - + ]: 312883 : count += s->iov[i].iov_len / block_size;
162 : : }
163 : :
164 : 312883 : return count >= num_blocks;
165 : : }
166 : :
167 : : /* This function must be used before starting iteration. */
168 : : static bool
169 : 4557614 : _dif_sgl_is_valid(struct _dif_sgl *s, uint32_t bytes)
170 : : {
171 : 4557614 : uint64_t total = 0;
172 : : int i;
173 : :
174 [ + + ]: 9530850 : for (i = 0; i < s->iovcnt; i++) {
175 : 4973236 : total += s->iov[i].iov_len;
176 : : }
177 : :
178 : 4557614 : return total >= bytes;
179 : : }
180 : :
181 : : static void
182 : 360 : _dif_sgl_copy(struct _dif_sgl *to, struct _dif_sgl *from)
183 : : {
184 [ - + - + ]: 360 : memcpy(to, from, sizeof(struct _dif_sgl));
185 : 360 : }
186 : :
187 : : static bool
188 : 1759334 : _dif_is_disabled(enum spdk_dif_type dif_type)
189 : : {
190 [ + + ]: 1759334 : if (dif_type == SPDK_DIF_DISABLE) {
191 : 139514 : return true;
192 : : } else {
193 : 1619820 : return false;
194 : : }
195 : : }
196 : :
197 : : static inline size_t
198 : 66740589 : _dif_size(enum spdk_dif_pi_format dif_pi_format)
199 : : {
200 : : uint8_t size;
201 : :
202 [ + + ]: 66740589 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
203 : 66729709 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g16);
204 [ + + ]: 10880 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
205 : 5545 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g32);
206 : : } else {
207 : 5335 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g64);
208 : : }
209 : :
210 : 66740589 : return size;
211 : : }
212 : :
213 : : static uint32_t
214 : 1287214 : _get_guard_interval(uint32_t block_size, uint32_t md_size, bool dif_loc, bool md_interleave,
215 : : size_t dif_size)
216 : : {
217 [ + + ]: 1287214 : if (!dif_loc) {
218 : : /* For metadata formats with more than 8/16 bytes (depending on
219 : : * the PI format), if the DIF is contained in the last 8/16 bytes
220 : : * of metadata, then the CRC covers all metadata up to but excluding
221 : : * these last 8/16 bytes.
222 : : */
223 [ + + ]: 1285799 : if (md_interleave) {
224 : 1145905 : return block_size - dif_size;
225 : : } else {
226 : 139894 : return md_size - dif_size;
227 : : }
228 : : } else {
229 : : /* For metadata formats with more than 8/16 bytes (depending on
230 : : * the PI format), if the DIF is contained in the first 8/16 bytes
231 : : * of metadata, then the CRC does not cover any metadata.
232 : : */
233 [ + + ]: 1415 : if (md_interleave) {
234 : 1235 : return block_size - md_size;
235 : : } else {
236 : 180 : return 0;
237 : : }
238 : : }
239 : : }
240 : :
241 : : static inline uint8_t
242 : 900 : _dif_guard_size(enum spdk_dif_pi_format dif_pi_format)
243 : : {
244 : : uint8_t size;
245 : :
246 [ + + ]: 900 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
247 : 300 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g16.guard);
248 [ + + ]: 600 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
249 : 300 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g32.guard);
250 : : } else {
251 : 300 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g64.guard);
252 : : }
253 : :
254 : 900 : return size;
255 : : }
256 : :
257 : : static inline void
258 : 19114579 : _dif_set_guard(struct spdk_dif *dif, uint64_t guard, enum spdk_dif_pi_format dif_pi_format)
259 : : {
260 [ + + ]: 19114579 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
261 : 19109359 : to_be16(&(dif->g16.guard), (uint16_t)guard);
262 [ + + ]: 5220 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
263 : 2655 : to_be32(&(dif->g32.guard), (uint32_t)guard);
264 : : } else {
265 : 2565 : to_be64(&(dif->g64.guard), guard);
266 : : }
267 : 19114579 : }
268 : :
269 : : static inline uint64_t
270 : 15959250 : _dif_get_guard(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
271 : : {
272 : : uint64_t guard;
273 : :
274 [ + + ]: 15959250 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
275 : 15955017 : guard = (uint64_t)from_be16(&(dif->g16.guard));
276 [ + + ]: 4233 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
277 : 2114 : guard = (uint64_t)from_be32(&(dif->g32.guard));
278 : : } else {
279 : 2119 : guard = from_be64(&(dif->g64.guard));
280 : : }
281 : :
282 : 15959250 : return guard;
283 : : }
284 : :
285 : : static inline uint64_t
286 : 35146680 : _dif_generate_guard(uint64_t guard_seed, void *buf, size_t buf_len,
287 : : enum spdk_dif_pi_format dif_pi_format)
288 : : {
289 : : uint64_t guard;
290 : :
291 [ + + ]: 35146680 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
292 : 35132767 : guard = (uint64_t)spdk_crc16_t10dif((uint16_t)guard_seed, buf, buf_len);
293 [ + + ]: 13913 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
294 : 7029 : guard = (uint64_t)spdk_crc32c_nvme(buf, buf_len, guard_seed);
295 : : } else {
296 : 6884 : guard = spdk_crc64_nvme(buf, buf_len, guard_seed);
297 : : }
298 : :
299 : 35146680 : return guard;
300 : : }
301 : :
302 : : static inline uint64_t
303 : 2500673 : _dif_generate_guard_copy(uint64_t guard_seed, void *dst, void *src, size_t buf_len,
304 : : enum spdk_dif_pi_format dif_pi_format)
305 : : {
306 : : uint64_t guard;
307 : :
308 [ + + ]: 2500673 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
309 : 2498013 : guard = (uint64_t)spdk_crc16_t10dif_copy((uint16_t)guard_seed, dst, src, buf_len);
310 [ + + ]: 2660 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
311 [ - + - + ]: 1330 : memcpy(dst, src, buf_len);
312 : 1330 : guard = (uint64_t)spdk_crc32c_nvme(src, buf_len, guard_seed);
313 : : } else {
314 [ - + - + ]: 1330 : memcpy(dst, src, buf_len);
315 : 1330 : guard = spdk_crc64_nvme(src, buf_len, guard_seed);
316 : : }
317 : :
318 : 2500673 : return guard;
319 : : }
320 : :
321 : : static inline uint8_t
322 : 600 : _dif_apptag_offset(enum spdk_dif_pi_format dif_pi_format)
323 : : {
324 : 600 : return _dif_guard_size(dif_pi_format);
325 : : }
326 : :
327 : : static inline uint8_t
328 : 600 : _dif_apptag_size(void)
329 : : {
330 : 600 : return SPDK_SIZEOF_MEMBER(struct spdk_dif, g16.app_tag);
331 : : }
332 : :
333 : : static inline void
334 : 5758853 : _dif_set_apptag(struct spdk_dif *dif, uint16_t app_tag, enum spdk_dif_pi_format dif_pi_format)
335 : : {
336 [ + + ]: 5758853 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
337 : 5753668 : to_be16(&(dif->g16.app_tag), app_tag);
338 [ + + ]: 5185 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
339 : 2640 : to_be16(&(dif->g32.app_tag), app_tag);
340 : : } else {
341 : 2545 : to_be16(&(dif->g64.app_tag), app_tag);
342 : : }
343 : 5758853 : }
344 : :
345 : : static inline uint16_t
346 : 18565435 : _dif_get_apptag(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
347 : : {
348 : : uint16_t app_tag;
349 : :
350 [ + + ]: 18565435 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
351 : 18555854 : app_tag = from_be16(&(dif->g16.app_tag));
352 [ + + ]: 9581 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
353 : 4793 : app_tag = from_be16(&(dif->g32.app_tag));
354 : : } else {
355 : 4788 : app_tag = from_be16(&(dif->g64.app_tag));
356 : : }
357 : :
358 : 18565435 : return app_tag;
359 : : }
360 : :
361 : : static inline bool
362 : 15962552 : _dif_apptag_ignore(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
363 : : {
364 : 15962552 : return _dif_get_apptag(dif, dif_pi_format) == SPDK_DIF_APPTAG_IGNORE;
365 : : }
366 : :
367 : : static inline uint8_t
368 : 300 : _dif_reftag_offset(enum spdk_dif_pi_format dif_pi_format)
369 : : {
370 : : uint8_t offset;
371 : :
372 [ + + ]: 300 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
373 : 100 : offset = _dif_apptag_offset(dif_pi_format) + _dif_apptag_size();
374 [ + + ]: 200 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
375 : 100 : offset = _dif_apptag_offset(dif_pi_format) + _dif_apptag_size()
376 : : + SPDK_SIZEOF_MEMBER(struct spdk_dif, g32.stor_ref_space_p1);
377 : : } else {
378 : 100 : offset = _dif_apptag_offset(dif_pi_format) + _dif_apptag_size();
379 : : }
380 : :
381 : 300 : return offset;
382 : : }
383 : :
384 : : static inline uint8_t
385 : 300 : _dif_reftag_size(enum spdk_dif_pi_format dif_pi_format)
386 : : {
387 : : uint8_t size;
388 : :
389 [ + + ]: 300 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
390 : 100 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g16.stor_ref_space);
391 [ + + ]: 200 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
392 : 100 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g32.stor_ref_space_p2);
393 : : } else {
394 : 100 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g64.stor_ref_space_p1) +
395 : : SPDK_SIZEOF_MEMBER(struct spdk_dif, g64.stor_ref_space_p2);
396 : : }
397 : :
398 : 300 : return size;
399 : : }
400 : :
401 : : static inline void
402 : 11086614 : _dif_set_reftag(struct spdk_dif *dif, uint64_t ref_tag, enum spdk_dif_pi_format dif_pi_format)
403 : : {
404 [ + + ]: 11086614 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
405 : 11080959 : to_be32(&(dif->g16.stor_ref_space), (uint32_t)ref_tag);
406 [ + + ]: 5655 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
407 : 2870 : to_be64(&(dif->g32.stor_ref_space_p2), ref_tag);
408 : : } else {
409 : 2785 : to_be16(&(dif->g64.stor_ref_space_p1), (uint16_t)(ref_tag >> 32));
410 : 2785 : to_be32(&(dif->g64.stor_ref_space_p2), (uint32_t)ref_tag);
411 : : }
412 : 11086614 : }
413 : :
414 : : static inline uint64_t
415 : 7930014 : _dif_get_reftag(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
416 : : {
417 : : uint64_t ref_tag;
418 : :
419 [ + + ]: 7930014 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
420 : 7925756 : ref_tag = (uint64_t)from_be32(&(dif->g16.stor_ref_space));
421 [ + + ]: 4258 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
422 : 2129 : ref_tag = from_be64(&(dif->g32.stor_ref_space_p2));
423 : : } else {
424 : 2129 : ref_tag = (uint64_t)from_be16(&(dif->g64.stor_ref_space_p1));
425 : 2129 : ref_tag <<= 32;
426 : 2129 : ref_tag |= (uint64_t)from_be32(&(dif->g64.stor_ref_space_p2));
427 : : }
428 : :
429 : 7930014 : return ref_tag;
430 : : }
431 : :
432 : : static inline bool
433 : 7929665 : _dif_reftag_match(struct spdk_dif *dif, uint64_t ref_tag,
434 : : enum spdk_dif_pi_format dif_pi_format)
435 : : {
436 : : uint64_t _ref_tag;
437 : : bool match;
438 : :
439 : 7929665 : _ref_tag = _dif_get_reftag(dif, dif_pi_format);
440 : :
441 [ + + ]: 7929665 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
442 : 7925627 : match = (_ref_tag == (ref_tag & REFTAG_MASK_16));
443 [ + + ]: 4038 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
444 : 2019 : match = (_ref_tag == ref_tag);
445 : : } else {
446 : 2019 : match = (_ref_tag == (ref_tag & REFTAG_MASK_64));
447 : : }
448 : :
449 : 7929665 : return match;
450 : : }
451 : :
452 : : static inline bool
453 : 35 : _dif_reftag_ignore(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
454 : : {
455 : 35 : return _dif_reftag_match(dif, REFTAG_MASK_32, dif_pi_format);
456 : : }
457 : :
458 : : static bool
459 : 15962552 : _dif_ignore(struct spdk_dif *dif, const struct spdk_dif_ctx *ctx)
460 : : {
461 [ + + - ]: 15962552 : switch (ctx->dif_type) {
462 : 7933151 : case SPDK_DIF_TYPE1:
463 : : case SPDK_DIF_TYPE2:
464 : : /* If Type 1 or 2 is used, then all DIF checks are disabled when
465 : : * the Application Tag is 0xFFFF.
466 : : */
467 [ + + ]: 7933151 : if (_dif_apptag_ignore(dif, ctx->dif_pi_format)) {
468 : 78 : return true;
469 : : }
470 : 7933073 : break;
471 : 8029401 : case SPDK_DIF_TYPE3:
472 : : /* If Type 3 is used, then all DIF checks are disabled when the
473 : : * Application Tag is 0xFFFF and the Reference Tag is 0xFFFFFFFF
474 : : * or 0xFFFFFFFFFFFFFFFF depending on the PI format.
475 : : */
476 : :
477 [ + + + + ]: 8029436 : if (_dif_apptag_ignore(dif, ctx->dif_pi_format) &&
478 : 35 : _dif_reftag_ignore(dif, ctx->dif_pi_format)) {
479 : 20 : return true;
480 : : }
481 : 8029381 : break;
482 : 0 : default:
483 : 0 : break;
484 : : }
485 : :
486 : 15962454 : return false;
487 : : }
488 : :
489 : : static bool
490 : 1287219 : _dif_pi_format_is_valid(enum spdk_dif_pi_format dif_pi_format)
491 : : {
492 [ + + ]: 1287219 : switch (dif_pi_format) {
493 : 1287214 : case SPDK_DIF_PI_FORMAT_16:
494 : : case SPDK_DIF_PI_FORMAT_32:
495 : : case SPDK_DIF_PI_FORMAT_64:
496 : 1287214 : return true;
497 : 5 : default:
498 : 5 : return false;
499 : : }
500 : : }
501 : :
502 : : static bool
503 : 1287224 : _dif_type_is_valid(enum spdk_dif_type dif_type)
504 : : {
505 [ + + ]: 1287224 : switch (dif_type) {
506 : 1287219 : case SPDK_DIF_DISABLE:
507 : : case SPDK_DIF_TYPE1:
508 : : case SPDK_DIF_TYPE2:
509 : : case SPDK_DIF_TYPE3:
510 : 1287219 : return true;
511 : 5 : default:
512 : 5 : return false;
513 : : }
514 : : }
515 : :
516 : : int
517 : 1287199 : spdk_dif_ctx_init(struct spdk_dif_ctx *ctx, uint32_t block_size, uint32_t md_size,
518 : : bool md_interleave, bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
519 : : uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag,
520 : : uint32_t data_offset, uint64_t guard_seed, struct spdk_dif_ctx_init_ext_opts *opts)
521 : : {
522 : : uint32_t data_block_size;
523 : 1287199 : enum spdk_dif_pi_format dif_pi_format = SPDK_DIF_PI_FORMAT_16;
524 : :
525 [ + - ]: 1287199 : if (opts != NULL) {
526 [ - + ]: 1287199 : if (!_dif_pi_format_is_valid(opts->dif_pi_format)) {
527 : 0 : SPDK_ERRLOG("No valid DIF PI format provided.\n");
528 : 0 : return -EINVAL;
529 : : }
530 : :
531 : 1287199 : dif_pi_format = opts->dif_pi_format;
532 : : }
533 : :
534 [ - + ]: 1287199 : if (!_dif_type_is_valid(dif_type)) {
535 : 0 : SPDK_ERRLOG("No valid DIF type was provided.\n");
536 : 0 : return -EINVAL;
537 : : }
538 : :
539 [ + + ]: 1287199 : if (md_size < _dif_size(dif_pi_format)) {
540 : 50 : SPDK_ERRLOG("Metadata size is smaller than DIF size.\n");
541 : 50 : return -EINVAL;
542 : : }
543 : :
544 [ + + ]: 1287149 : if (md_interleave) {
545 [ - + ]: 1147050 : if (block_size < md_size) {
546 : 0 : SPDK_ERRLOG("Block size is smaller than DIF size.\n");
547 : 0 : return -EINVAL;
548 : : }
549 : 1147050 : data_block_size = block_size - md_size;
550 : : } else {
551 : 140099 : data_block_size = block_size;
552 : : }
553 : :
554 [ + + ]: 1287149 : if (data_block_size == 0) {
555 : 10 : SPDK_ERRLOG("Zero data block size is not allowed\n");
556 : 10 : return -EINVAL;
557 : : }
558 : :
559 [ + + ]: 1287139 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
560 [ - + ]: 1285619 : if ((data_block_size % 512) != 0) {
561 : 0 : SPDK_ERRLOG("Data block size should be a multiple of 512B\n");
562 : 0 : return -EINVAL;
563 : : }
564 : : } else {
565 [ + + ]: 1520 : if ((data_block_size % 4096) != 0) {
566 : 30 : SPDK_ERRLOG("Data block size should be a multiple of 4kB\n");
567 : 30 : return -EINVAL;
568 : : }
569 : : }
570 : :
571 : 1287109 : ctx->block_size = block_size;
572 : 1287109 : ctx->md_size = md_size;
573 : 1287109 : ctx->md_interleave = md_interleave;
574 : 1287109 : ctx->dif_pi_format = dif_pi_format;
575 : 1287109 : ctx->guard_interval = _get_guard_interval(block_size, md_size, dif_loc, md_interleave,
576 : 1287109 : _dif_size(ctx->dif_pi_format));
577 : 1287109 : ctx->dif_type = dif_type;
578 : 1287109 : ctx->dif_flags = dif_flags;
579 : 1287109 : ctx->init_ref_tag = init_ref_tag;
580 : 1287109 : ctx->apptag_mask = apptag_mask;
581 : 1287109 : ctx->app_tag = app_tag;
582 : 1287109 : ctx->data_offset = data_offset;
583 [ - + ]: 1287109 : ctx->ref_tag_offset = data_offset / data_block_size;
584 : 1287109 : ctx->last_guard = guard_seed;
585 : 1287109 : ctx->guard_seed = guard_seed;
586 : 1287109 : ctx->remapped_init_ref_tag = 0;
587 : :
588 : 1287109 : return 0;
589 : : }
590 : :
591 : : void
592 : 1074508 : spdk_dif_ctx_set_data_offset(struct spdk_dif_ctx *ctx, uint32_t data_offset)
593 : : {
594 : : uint32_t data_block_size;
595 : :
596 [ + + + - ]: 1074508 : if (ctx->md_interleave) {
597 : 1074508 : data_block_size = ctx->block_size - ctx->md_size;
598 : : } else {
599 : 0 : data_block_size = ctx->block_size;
600 : : }
601 : :
602 : 1074508 : ctx->data_offset = data_offset;
603 [ - + ]: 1074508 : ctx->ref_tag_offset = data_offset / data_block_size;
604 : 1074508 : }
605 : :
606 : : void
607 : 120 : spdk_dif_ctx_set_remapped_init_ref_tag(struct spdk_dif_ctx *ctx,
608 : : uint32_t remapped_init_ref_tag)
609 : : {
610 : 120 : ctx->remapped_init_ref_tag = remapped_init_ref_tag;
611 : 120 : }
612 : :
613 : : static void
614 : 19116397 : _dif_generate(void *_dif, uint64_t guard, uint32_t offset_blocks,
615 : : const struct spdk_dif_ctx *ctx)
616 : : {
617 : 19116397 : struct spdk_dif *dif = _dif;
618 : : uint64_t ref_tag;
619 : :
620 [ + + ]: 19116397 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
621 : 19114579 : _dif_set_guard(dif, guard, ctx->dif_pi_format);
622 : : }
623 : :
624 [ + + ]: 19116397 : if (ctx->dif_flags & SPDK_DIF_FLAGS_APPTAG_CHECK) {
625 : 5758853 : _dif_set_apptag(dif, ctx->app_tag, ctx->dif_pi_format);
626 : : }
627 : :
628 [ + + ]: 19116397 : if (ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK) {
629 : : /* For type 1 and 2, the reference tag is incremented for each
630 : : * subsequent logical block. For type 3, the reference tag
631 : : * remains the same as the initial reference tag.
632 : : */
633 [ + + ]: 11085254 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
634 : 11085219 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
635 : : } else {
636 : 35 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset;
637 : : }
638 : :
639 : : /* Overwrite reference tag if initialization reference tag is SPDK_DIF_REFTAG_IGNORE */
640 [ + + ]: 11085254 : if (ctx->init_ref_tag == SPDK_DIF_REFTAG_IGNORE) {
641 [ + - ]: 10 : if (ctx->dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
642 : 10 : ref_tag = REFTAG_MASK_16;
643 [ # # ]: 0 : } else if (ctx->dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
644 : 0 : ref_tag = REFTAG_MASK_32;
645 : : } else {
646 : 0 : ref_tag = REFTAG_MASK_64;
647 : : }
648 : : }
649 : :
650 : 11085254 : _dif_set_reftag(dif, ref_tag, ctx->dif_pi_format);
651 : : }
652 : 19116397 : }
653 : :
654 : : static void
655 : 948167 : dif_generate(struct _dif_sgl *sgl, uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
656 : : {
657 : 948167 : uint32_t offset_blocks = 0;
658 : 140572 : uint8_t *buf;
659 : 948167 : uint64_t guard = 0;
660 : :
661 [ + + ]: 9531186 : while (offset_blocks < num_blocks) {
662 : 8583019 : _dif_sgl_get_buf(sgl, &buf, NULL);
663 : :
664 [ + + ]: 8583019 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
665 : 8582365 : guard = _dif_generate_guard(ctx->guard_seed, buf, ctx->guard_interval, ctx->dif_pi_format);
666 : : }
667 : :
668 : 8583019 : _dif_generate(buf + ctx->guard_interval, guard, offset_blocks, ctx);
669 : :
670 : 8583019 : _dif_sgl_advance(sgl, ctx->block_size);
671 : 8583019 : offset_blocks++;
672 : : }
673 : 948167 : }
674 : :
675 : : static uint64_t
676 : 8030238 : _dif_generate_split(struct _dif_sgl *sgl, uint32_t offset_in_block, uint32_t data_len,
677 : : uint64_t guard, uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
678 : : {
679 : 1048 : uint32_t offset_in_dif, buf_len;
680 : 1048 : uint8_t *buf;
681 : 8030238 : struct spdk_dif dif = {};
682 : :
683 [ - + ]: 8030238 : assert(offset_in_block < ctx->guard_interval);
684 [ + + - + ]: 8030238 : assert(offset_in_block + data_len < ctx->guard_interval ||
685 : : offset_in_block + data_len == ctx->block_size);
686 : :
687 : : /* Compute CRC over split logical block data. */
688 [ + + + + ]: 16092739 : while (data_len != 0 && offset_in_block < ctx->guard_interval) {
689 : 8062501 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
690 : 8062501 : buf_len = spdk_min(buf_len, data_len);
691 : 8062501 : buf_len = spdk_min(buf_len, ctx->guard_interval - offset_in_block);
692 : :
693 [ + - ]: 8062501 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
694 : 8062501 : guard = _dif_generate_guard(guard, buf, buf_len, ctx->dif_pi_format);
695 : : }
696 : :
697 : 8062501 : _dif_sgl_advance(sgl, buf_len);
698 : 8062501 : offset_in_block += buf_len;
699 : 8062501 : data_len -= buf_len;
700 : : }
701 : :
702 [ + + ]: 8030238 : if (offset_in_block < ctx->guard_interval) {
703 : 195 : return guard;
704 : : }
705 : :
706 : : /* If a whole logical block data is parsed, generate DIF
707 : : * and save it to the temporary DIF area.
708 : : */
709 : 8030043 : _dif_generate(&dif, guard, offset_blocks, ctx);
710 : :
711 : : /* Copy generated DIF field to the split DIF field, and then
712 : : * skip metadata field after DIF field (if any).
713 : : */
714 [ + + ]: 16060936 : while (offset_in_block < ctx->block_size) {
715 : 8030893 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
716 : :
717 [ + + ]: 8030893 : if (offset_in_block < ctx->guard_interval + _dif_size(ctx->dif_pi_format)) {
718 : 8030473 : offset_in_dif = offset_in_block - ctx->guard_interval;
719 [ + + ]: 8030473 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset_in_dif);
720 : :
721 [ - + - + ]: 8030473 : memcpy(buf, ((uint8_t *)&dif) + offset_in_dif, buf_len);
722 : : } else {
723 : 420 : buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block);
724 : : }
725 : :
726 : 8030893 : _dif_sgl_advance(sgl, buf_len);
727 : 8030893 : offset_in_block += buf_len;
728 : : }
729 : :
730 [ + - ]: 8030043 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
731 : 8030043 : guard = ctx->guard_seed;
732 : : }
733 : :
734 : 8030043 : return guard;
735 : : }
736 : :
737 : : static void
738 : 32123 : dif_generate_split(struct _dif_sgl *sgl, uint32_t num_blocks,
739 : : const struct spdk_dif_ctx *ctx)
740 : : {
741 : : uint32_t offset_blocks;
742 : 32123 : uint64_t guard = 0;
743 : :
744 [ + - ]: 32123 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
745 : 32123 : guard = ctx->guard_seed;
746 : : }
747 : :
748 [ + + ]: 8061936 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
749 : 8029813 : _dif_generate_split(sgl, 0, ctx->block_size, guard, offset_blocks, ctx);
750 : : }
751 : 32123 : }
752 : :
753 : : int
754 : 980250 : spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
755 : : const struct spdk_dif_ctx *ctx)
756 : : {
757 : 141148 : struct _dif_sgl sgl;
758 : :
759 : 980250 : _dif_sgl_init(&sgl, iovs, iovcnt);
760 : :
761 [ - + ]: 980250 : if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) {
762 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
763 : 0 : return -EINVAL;
764 : : }
765 : :
766 [ + + ]: 980250 : if (_dif_is_disabled(ctx->dif_type)) {
767 : 5 : return 0;
768 : : }
769 : :
770 [ + + ]: 980245 : if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
771 : 948122 : dif_generate(&sgl, num_blocks, ctx);
772 : : } else {
773 : 32123 : dif_generate_split(&sgl, num_blocks, ctx);
774 : : }
775 : :
776 : 980245 : return 0;
777 : : }
778 : :
779 : : static void
780 : 1334 : _dif_error_set(struct spdk_dif_error *err_blk, uint8_t err_type,
781 : : uint64_t expected, uint64_t actual, uint32_t err_offset)
782 : : {
783 [ + + ]: 1334 : if (err_blk) {
784 : 1289 : err_blk->err_type = err_type;
785 : 1289 : err_blk->expected = expected;
786 : 1289 : err_blk->actual = actual;
787 : 1289 : err_blk->err_offset = err_offset;
788 : : }
789 : 1334 : }
790 : :
791 : : static bool
792 : 15960819 : _dif_reftag_check(struct spdk_dif *dif, const struct spdk_dif_ctx *ctx,
793 : : uint64_t expected_reftag, uint32_t offset_blocks, struct spdk_dif_error *err_blk)
794 : : {
795 : : uint64_t reftag;
796 : :
797 [ + + ]: 15960819 : if (ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK) {
798 [ + - - ]: 7929630 : switch (ctx->dif_type) {
799 : 7929630 : case SPDK_DIF_TYPE1:
800 : : case SPDK_DIF_TYPE2:
801 : : /* Compare the DIF Reference Tag field to the passed Reference Tag.
802 : : * The passed Reference Tag will be the least significant 4 bytes
803 : : * or 8 bytes (depending on the PI format)
804 : : * of the LBA when Type 1 is used, and application specific value
805 : : * if Type 2 is used.
806 : : */
807 [ + + ]: 7929630 : if (!_dif_reftag_match(dif, expected_reftag, ctx->dif_pi_format)) {
808 : 339 : reftag = _dif_get_reftag(dif, ctx->dif_pi_format);
809 : 339 : _dif_error_set(err_blk, SPDK_DIF_REFTAG_ERROR, expected_reftag,
810 : : reftag, offset_blocks);
811 : 339 : SPDK_ERRLOG("Failed to compare Ref Tag: LBA=%" PRIu64 "," \
812 : : " Expected=%lx, Actual=%lx\n",
813 : : expected_reftag, expected_reftag, reftag);
814 : 339 : return false;
815 : : }
816 : 7929291 : break;
817 : 0 : case SPDK_DIF_TYPE3:
818 : : /* For Type 3, computed Reference Tag remains unchanged.
819 : : * Hence ignore the Reference Tag field.
820 : : */
821 : 0 : break;
822 : 0 : default:
823 : 0 : break;
824 : : }
825 : : }
826 : :
827 : 15960480 : return true;
828 : : }
829 : :
830 : : static int
831 : 15961192 : _dif_verify(void *_dif, uint64_t guard, uint32_t offset_blocks,
832 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
833 : : {
834 : 15961192 : struct spdk_dif *dif = _dif;
835 : : uint64_t _guard;
836 : : uint16_t _app_tag;
837 : : uint64_t ref_tag;
838 : :
839 [ + + ]: 15961192 : if (_dif_ignore(dif, ctx)) {
840 : 98 : return 0;
841 : : }
842 : :
843 : : /* For type 1 and 2, the reference tag is incremented for each
844 : : * subsequent logical block. For type 3, the reference tag
845 : : * remains the same as the initial reference tag.
846 : : */
847 [ + + ]: 15961094 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
848 : 7931713 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
849 : : } else {
850 : 8029381 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset;
851 : : }
852 : :
853 [ + + ]: 15961094 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
854 : : /* Compare the DIF Guard field to the CRC computed over the logical
855 : : * block data.
856 : : */
857 : 15959200 : _guard = _dif_get_guard(dif, ctx->dif_pi_format);
858 [ + + ]: 15959200 : if (_guard != guard) {
859 : 626 : _dif_error_set(err_blk, SPDK_DIF_GUARD_ERROR, _guard, guard,
860 : : offset_blocks);
861 : 626 : SPDK_ERRLOG("Failed to compare Guard: LBA=%" PRIu64 "," \
862 : : " Expected=%lx, Actual=%lx\n",
863 : : ref_tag, _guard, guard);
864 : 626 : return -1;
865 : : }
866 : : }
867 : :
868 [ + + ]: 15960468 : if (ctx->dif_flags & SPDK_DIF_FLAGS_APPTAG_CHECK) {
869 : : /* Compare unmasked bits in the DIF Application Tag field to the
870 : : * passed Application Tag.
871 : : */
872 : 2602873 : _app_tag = _dif_get_apptag(dif, ctx->dif_pi_format);
873 [ + + ]: 2602873 : if ((_app_tag & ctx->apptag_mask) != (ctx->app_tag & ctx->apptag_mask)) {
874 : 369 : _dif_error_set(err_blk, SPDK_DIF_APPTAG_ERROR, ctx->app_tag,
875 : 369 : (_app_tag & ctx->apptag_mask), offset_blocks);
876 : 369 : SPDK_ERRLOG("Failed to compare App Tag: LBA=%" PRIu64 "," \
877 : : " Expected=%x, Actual=%x\n",
878 : : ref_tag, ctx->app_tag, (_app_tag & ctx->apptag_mask));
879 : 369 : return -1;
880 : : }
881 : : }
882 : :
883 [ + + ]: 15960099 : if (!_dif_reftag_check(dif, ctx, ref_tag, offset_blocks, err_blk)) {
884 : 339 : return -1;
885 : : }
886 : :
887 : 15959760 : return 0;
888 : : }
889 : :
890 : : static int
891 : 324922 : dif_verify(struct _dif_sgl *sgl, uint32_t num_blocks,
892 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
893 : : {
894 : 324922 : uint32_t offset_blocks = 0;
895 : : int rc;
896 : 108275 : uint8_t *buf;
897 : 324922 : uint64_t guard = 0;
898 : :
899 [ + + ]: 2922331 : while (offset_blocks < num_blocks) {
900 : 2597609 : _dif_sgl_get_buf(sgl, &buf, NULL);
901 : :
902 [ + + ]: 2597609 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
903 : 2596861 : guard = _dif_generate_guard(ctx->guard_seed, buf, ctx->guard_interval, ctx->dif_pi_format);
904 : : }
905 : :
906 : 2597609 : rc = _dif_verify(buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
907 [ + + ]: 2597609 : if (rc != 0) {
908 : 200 : return rc;
909 : : }
910 : :
911 : 2597409 : _dif_sgl_advance(sgl, ctx->block_size);
912 : 2597409 : offset_blocks++;
913 : : }
914 : :
915 : 324722 : return 0;
916 : : }
917 : :
918 : : static int
919 : 13356714 : _dif_verify_split(struct _dif_sgl *sgl, uint32_t offset_in_block, uint32_t data_len,
920 : : uint64_t *_guard, uint32_t offset_blocks,
921 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
922 : : {
923 : 784 : uint32_t offset_in_dif, buf_len;
924 : 784 : uint8_t *buf;
925 : : uint64_t guard;
926 : 13356714 : struct spdk_dif dif = {};
927 : : int rc;
928 : :
929 [ - + ]: 13356714 : assert(_guard != NULL);
930 [ - + ]: 13356714 : assert(offset_in_block < ctx->guard_interval);
931 [ + + - + ]: 13356714 : assert(offset_in_block + data_len < ctx->guard_interval ||
932 : : offset_in_block + data_len == ctx->block_size);
933 : :
934 : 13356714 : guard = *_guard;
935 : :
936 : : /* Compute CRC over split logical block data. */
937 [ + + + + ]: 26745616 : while (data_len != 0 && offset_in_block < ctx->guard_interval) {
938 : 13388902 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
939 : 13388902 : buf_len = spdk_min(buf_len, data_len);
940 : 13388902 : buf_len = spdk_min(buf_len, ctx->guard_interval - offset_in_block);
941 : :
942 [ + - ]: 13388902 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
943 : 13388902 : guard = _dif_generate_guard(guard, buf, buf_len, ctx->dif_pi_format);
944 : : }
945 : :
946 : 13388902 : _dif_sgl_advance(sgl, buf_len);
947 : 13388902 : offset_in_block += buf_len;
948 : 13388902 : data_len -= buf_len;
949 : : }
950 : :
951 [ + + ]: 13356714 : if (offset_in_block < ctx->guard_interval) {
952 : 75 : *_guard = guard;
953 : 75 : return 0;
954 : : }
955 : :
956 : : /* Copy the split DIF field to the temporary DIF buffer, and then
957 : : * skip metadata field after DIF field (if any). */
958 [ + + ]: 26714113 : while (offset_in_block < ctx->block_size) {
959 : 13357474 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
960 : :
961 [ + + ]: 13357474 : if (offset_in_block < ctx->guard_interval + _dif_size(ctx->dif_pi_format)) {
962 : 13357054 : offset_in_dif = offset_in_block - ctx->guard_interval;
963 [ + + ]: 13357054 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset_in_dif);
964 : :
965 [ - + - + ]: 13357054 : memcpy((uint8_t *)&dif + offset_in_dif, buf, buf_len);
966 : : } else {
967 : 420 : buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block);
968 : : }
969 : 13357474 : _dif_sgl_advance(sgl, buf_len);
970 : 13357474 : offset_in_block += buf_len;
971 : : }
972 : :
973 : 13356639 : rc = _dif_verify(&dif, guard, offset_blocks, ctx, err_blk);
974 [ + + ]: 13356639 : if (rc != 0) {
975 : 600 : return rc;
976 : : }
977 : :
978 [ + - ]: 13356039 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
979 : 13356039 : guard = ctx->guard_seed;
980 : : }
981 : :
982 : 13356039 : *_guard = guard;
983 : 13356039 : return 0;
984 : : }
985 : :
986 : : static int
987 : 750 : dif_verify_split(struct _dif_sgl *sgl, uint32_t num_blocks,
988 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
989 : : {
990 : : uint32_t offset_blocks;
991 : 750 : uint64_t guard = 0;
992 : : int rc;
993 : :
994 [ + - ]: 750 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
995 : 750 : guard = ctx->guard_seed;
996 : : }
997 : :
998 [ + + ]: 995 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
999 : 845 : rc = _dif_verify_split(sgl, 0, ctx->block_size, &guard, offset_blocks,
1000 : : ctx, err_blk);
1001 [ + + ]: 845 : if (rc != 0) {
1002 : 600 : return rc;
1003 : : }
1004 : : }
1005 : :
1006 : 150 : return 0;
1007 : : }
1008 : :
1009 : : int
1010 : 325632 : spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
1011 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
1012 : : {
1013 : 108843 : struct _dif_sgl sgl;
1014 : :
1015 : 325632 : _dif_sgl_init(&sgl, iovs, iovcnt);
1016 : :
1017 [ - + ]: 325632 : if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) {
1018 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
1019 : 0 : return -EINVAL;
1020 : : }
1021 : :
1022 [ + + ]: 325632 : if (_dif_is_disabled(ctx->dif_type)) {
1023 : 5 : return 0;
1024 : : }
1025 : :
1026 [ + + ]: 325627 : if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
1027 : 324877 : return dif_verify(&sgl, num_blocks, ctx, err_blk);
1028 : : } else {
1029 : 750 : return dif_verify_split(&sgl, num_blocks, ctx, err_blk);
1030 : : }
1031 : : }
1032 : :
1033 : : static uint32_t
1034 : 45 : dif_update_crc32c(struct _dif_sgl *sgl, uint32_t num_blocks,
1035 : : uint32_t crc32c, const struct spdk_dif_ctx *ctx)
1036 : : {
1037 : : uint32_t offset_blocks;
1038 : 36 : uint8_t *buf;
1039 : :
1040 [ + + ]: 225 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1041 : 180 : _dif_sgl_get_buf(sgl, &buf, NULL);
1042 : :
1043 : 180 : crc32c = spdk_crc32c_update(buf, ctx->block_size - ctx->md_size, crc32c);
1044 : :
1045 : 180 : _dif_sgl_advance(sgl, ctx->block_size);
1046 : : }
1047 : :
1048 : 45 : return crc32c;
1049 : : }
1050 : :
1051 : : static uint32_t
1052 : 5177818 : _dif_update_crc32c_split(struct _dif_sgl *sgl, uint32_t offset_in_block, uint32_t data_len,
1053 : : uint32_t crc32c, const struct spdk_dif_ctx *ctx)
1054 : : {
1055 : 204 : uint32_t data_block_size, buf_len;
1056 : 204 : uint8_t *buf;
1057 : :
1058 : 5177818 : data_block_size = ctx->block_size - ctx->md_size;
1059 : :
1060 [ - + ]: 5177818 : assert(offset_in_block + data_len <= ctx->block_size);
1061 : :
1062 [ + + ]: 15553783 : while (data_len != 0) {
1063 : 10375965 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
1064 : 10375965 : buf_len = spdk_min(buf_len, data_len);
1065 : :
1066 [ + + ]: 10375965 : if (offset_in_block < data_block_size) {
1067 : 5198132 : buf_len = spdk_min(buf_len, data_block_size - offset_in_block);
1068 : 5198132 : crc32c = spdk_crc32c_update(buf, buf_len, crc32c);
1069 : : }
1070 : :
1071 : 10375965 : _dif_sgl_advance(sgl, buf_len);
1072 : 10375965 : offset_in_block += buf_len;
1073 : 10375965 : data_len -= buf_len;
1074 : : }
1075 : :
1076 : 5177818 : return crc32c;
1077 : : }
1078 : :
1079 : : static uint32_t
1080 : 30 : dif_update_crc32c_split(struct _dif_sgl *sgl, uint32_t num_blocks,
1081 : : uint32_t crc32c, const struct spdk_dif_ctx *ctx)
1082 : : {
1083 : : uint32_t offset_blocks;
1084 : :
1085 [ + + ]: 150 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1086 : 120 : crc32c = _dif_update_crc32c_split(sgl, 0, ctx->block_size, crc32c, ctx);
1087 : : }
1088 : :
1089 : 30 : return crc32c;
1090 : : }
1091 : :
1092 : : int
1093 : 75 : spdk_dif_update_crc32c(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
1094 : : uint32_t *_crc32c, const struct spdk_dif_ctx *ctx)
1095 : : {
1096 : 60 : struct _dif_sgl sgl;
1097 : :
1098 [ - + ]: 75 : if (_crc32c == NULL) {
1099 : 0 : return -EINVAL;
1100 : : }
1101 : :
1102 : 75 : _dif_sgl_init(&sgl, iovs, iovcnt);
1103 : :
1104 [ - + ]: 75 : if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) {
1105 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
1106 : 0 : return -EINVAL;
1107 : : }
1108 : :
1109 [ + + ]: 75 : if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
1110 : 45 : *_crc32c = dif_update_crc32c(&sgl, num_blocks, *_crc32c, ctx);
1111 : : } else {
1112 : 30 : *_crc32c = dif_update_crc32c_split(&sgl, num_blocks, *_crc32c, ctx);
1113 : : }
1114 : :
1115 : 75 : return 0;
1116 : : }
1117 : :
1118 : : static void
1119 : 312325 : dif_generate_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1120 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1121 : : {
1122 : 312325 : uint32_t offset_blocks = 0, data_block_size;
1123 : 106055 : uint8_t *src, *dst;
1124 : : uint64_t guard;
1125 : :
1126 : 312325 : data_block_size = ctx->block_size - ctx->md_size;
1127 : :
1128 [ + + ]: 2811225 : while (offset_blocks < num_blocks) {
1129 : 2498900 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1130 : 2498900 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1131 : :
1132 : 2498900 : guard = 0;
1133 [ + + ]: 2498900 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1134 : 2498306 : guard = _dif_generate_guard_copy(ctx->guard_seed, dst, src, data_block_size,
1135 : 2498306 : ctx->dif_pi_format);
1136 : 2498306 : guard = _dif_generate_guard(guard, dst + data_block_size,
1137 : 2498306 : ctx->guard_interval - data_block_size, ctx->dif_pi_format);
1138 : : } else {
1139 [ - + - + ]: 594 : memcpy(dst, src, data_block_size);
1140 : : }
1141 : :
1142 : 2498900 : _dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx);
1143 : :
1144 : 2498900 : _dif_sgl_advance(src_sgl, data_block_size);
1145 : 2498900 : _dif_sgl_advance(dst_sgl, ctx->block_size);
1146 : 2498900 : offset_blocks++;
1147 : : }
1148 : 312325 : }
1149 : :
1150 : : static void
1151 : 315 : _dif_generate_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1152 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
1153 : : {
1154 : 252 : uint32_t offset_in_block, src_len, data_block_size;
1155 : 252 : uint8_t *src, *dst;
1156 : 315 : uint64_t guard = 0;
1157 : :
1158 : 315 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1159 : :
1160 : 315 : data_block_size = ctx->block_size - ctx->md_size;
1161 : :
1162 [ + - ]: 315 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1163 : 315 : guard = ctx->guard_seed;
1164 : : }
1165 : 315 : offset_in_block = 0;
1166 : :
1167 [ + + ]: 960 : while (offset_in_block < data_block_size) {
1168 : : /* Compute CRC over split logical block data and copy
1169 : : * data to bounce buffer.
1170 : : */
1171 : 645 : _dif_sgl_get_buf(src_sgl, &src, &src_len);
1172 : 645 : src_len = spdk_min(src_len, data_block_size - offset_in_block);
1173 : :
1174 [ + - ]: 645 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1175 : 645 : guard = _dif_generate_guard_copy(guard, dst + offset_in_block,
1176 : 645 : src, src_len, ctx->dif_pi_format);
1177 : : } else {
1178 [ # # # # ]: 0 : memcpy(dst + offset_in_block, src, src_len);
1179 : : }
1180 : :
1181 : 645 : _dif_sgl_advance(src_sgl, src_len);
1182 : 645 : offset_in_block += src_len;
1183 : : }
1184 : :
1185 [ + - ]: 315 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1186 : 315 : guard = _dif_generate_guard(guard, dst + data_block_size,
1187 : 315 : ctx->guard_interval - data_block_size, ctx->dif_pi_format);
1188 : : }
1189 : :
1190 : 315 : _dif_sgl_advance(dst_sgl, ctx->block_size);
1191 : :
1192 : 315 : _dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx);
1193 : 315 : }
1194 : :
1195 : : static void
1196 : 150 : dif_generate_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1197 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1198 : : {
1199 : : uint32_t offset_blocks;
1200 : :
1201 [ + + ]: 465 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1202 : 315 : _dif_generate_copy_split(src_sgl, dst_sgl, offset_blocks, ctx);
1203 : : }
1204 : 150 : }
1205 : :
1206 : : int
1207 : 312478 : spdk_dif_generate_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iovs,
1208 : : int bounce_iovcnt, uint32_t num_blocks,
1209 : : const struct spdk_dif_ctx *ctx)
1210 : : {
1211 : 106176 : struct _dif_sgl src_sgl, dst_sgl;
1212 : : uint32_t data_block_size;
1213 : :
1214 : 312478 : _dif_sgl_init(&src_sgl, iovs, iovcnt);
1215 : 312478 : _dif_sgl_init(&dst_sgl, bounce_iovs, bounce_iovcnt);
1216 : :
1217 : 312478 : data_block_size = ctx->block_size - ctx->md_size;
1218 : :
1219 [ - + ]: 312478 : if (!_dif_sgl_is_valid(&src_sgl, data_block_size * num_blocks)) {
1220 : 0 : SPDK_ERRLOG("Size of iovec arrays are not valid.\n");
1221 : 0 : return -EINVAL;
1222 : : }
1223 : :
1224 [ + + ]: 312478 : if (!_dif_sgl_is_valid_block_aligned(&dst_sgl, num_blocks, ctx->block_size)) {
1225 : 3 : SPDK_ERRLOG("Size of bounce_iovs arrays are not valid or misaligned with block_size.\n");
1226 : 3 : return -EINVAL;
1227 : : }
1228 : :
1229 [ - + ]: 312475 : if (_dif_is_disabled(ctx->dif_type)) {
1230 : 0 : return 0;
1231 : : }
1232 : :
1233 [ + + ]: 312475 : if (_dif_sgl_is_bytes_multiple(&src_sgl, data_block_size)) {
1234 : 312325 : dif_generate_copy(&src_sgl, &dst_sgl, num_blocks, ctx);
1235 : : } else {
1236 : 150 : dif_generate_copy_split(&src_sgl, &dst_sgl, num_blocks, ctx);
1237 : : }
1238 : :
1239 : 312475 : return 0;
1240 : : }
1241 : :
1242 : : static int
1243 : 258 : dif_verify_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1244 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1245 : : struct spdk_dif_error *err_blk)
1246 : : {
1247 : 258 : uint32_t offset_blocks = 0, data_block_size;
1248 : 198 : uint8_t *src, *dst;
1249 : : int rc;
1250 : : uint64_t guard;
1251 : :
1252 : 258 : data_block_size = ctx->block_size - ctx->md_size;
1253 : :
1254 [ + + ]: 1974 : while (offset_blocks < num_blocks) {
1255 : 1845 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1256 : 1845 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1257 : :
1258 : 1845 : guard = 0;
1259 [ + + ]: 1845 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1260 : 1221 : guard = _dif_generate_guard_copy(ctx->guard_seed, dst, src, data_block_size,
1261 : 1221 : ctx->dif_pi_format);
1262 : 1221 : guard = _dif_generate_guard(guard, src + data_block_size,
1263 : 1221 : ctx->guard_interval - data_block_size, ctx->dif_pi_format);
1264 : : } else {
1265 [ - + - + ]: 624 : memcpy(dst, src, data_block_size);
1266 : : }
1267 : :
1268 : 1845 : rc = _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
1269 [ + + ]: 1845 : if (rc != 0) {
1270 : 129 : return rc;
1271 : : }
1272 : :
1273 : 1716 : _dif_sgl_advance(src_sgl, ctx->block_size);
1274 : 1716 : _dif_sgl_advance(dst_sgl, data_block_size);
1275 : 1716 : offset_blocks++;
1276 : : }
1277 : :
1278 : 129 : return 0;
1279 : : }
1280 : :
1281 : : static int
1282 : 243 : _dif_verify_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1283 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx,
1284 : : struct spdk_dif_error *err_blk)
1285 : : {
1286 : 180 : uint32_t offset_in_block, dst_len, data_block_size;
1287 : 180 : uint8_t *src, *dst;
1288 : 243 : uint64_t guard = 0;
1289 : :
1290 : 243 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1291 : :
1292 : 243 : data_block_size = ctx->block_size - ctx->md_size;
1293 : :
1294 [ + - ]: 243 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1295 : 243 : guard = ctx->guard_seed;
1296 : : }
1297 : 243 : offset_in_block = 0;
1298 : :
1299 [ + + ]: 744 : while (offset_in_block < data_block_size) {
1300 : : /* Compute CRC over split logical block data and copy
1301 : : * data to bounce buffer.
1302 : : */
1303 : 501 : _dif_sgl_get_buf(dst_sgl, &dst, &dst_len);
1304 : 501 : dst_len = spdk_min(dst_len, data_block_size - offset_in_block);
1305 : :
1306 [ + - ]: 501 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1307 : 501 : guard = _dif_generate_guard_copy(guard, dst, src + offset_in_block,
1308 : 501 : dst_len, ctx->dif_pi_format);
1309 : : } else {
1310 [ # # # # ]: 0 : memcpy(dst, src + offset_in_block, dst_len);
1311 : : }
1312 : :
1313 : 501 : _dif_sgl_advance(dst_sgl, dst_len);
1314 : 501 : offset_in_block += dst_len;
1315 : : }
1316 : :
1317 [ + - ]: 243 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1318 : 243 : guard = _dif_generate_guard(guard, src + data_block_size,
1319 : 243 : ctx->guard_interval - data_block_size, ctx->dif_pi_format);
1320 : : }
1321 : :
1322 : 243 : _dif_sgl_advance(src_sgl, ctx->block_size);
1323 : :
1324 : 243 : return _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
1325 : : }
1326 : :
1327 : : static int
1328 : 150 : dif_verify_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1329 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1330 : : struct spdk_dif_error *err_blk)
1331 : : {
1332 : : uint32_t offset_blocks;
1333 : : int rc;
1334 : :
1335 [ + + ]: 273 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1336 : 243 : rc = _dif_verify_copy_split(src_sgl, dst_sgl, offset_blocks, ctx, err_blk);
1337 [ + + ]: 243 : if (rc != 0) {
1338 : 120 : return rc;
1339 : : }
1340 : : }
1341 : :
1342 : 30 : return 0;
1343 : : }
1344 : :
1345 : : int
1346 : 408 : spdk_dif_verify_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iovs,
1347 : : int bounce_iovcnt, uint32_t num_blocks,
1348 : : const struct spdk_dif_ctx *ctx,
1349 : : struct spdk_dif_error *err_blk)
1350 : : {
1351 : 318 : struct _dif_sgl src_sgl, dst_sgl;
1352 : : uint32_t data_block_size;
1353 : :
1354 : 408 : _dif_sgl_init(&src_sgl, bounce_iovs, bounce_iovcnt);
1355 : 408 : _dif_sgl_init(&dst_sgl, iovs, iovcnt);
1356 : :
1357 : 408 : data_block_size = ctx->block_size - ctx->md_size;
1358 : :
1359 [ - + ]: 408 : if (!_dif_sgl_is_valid(&dst_sgl, data_block_size * num_blocks)) {
1360 : 0 : SPDK_ERRLOG("Size of iovec arrays are not valid\n");
1361 : 0 : return -EINVAL;
1362 : : }
1363 : :
1364 [ - + ]: 408 : if (!_dif_sgl_is_valid_block_aligned(&src_sgl, num_blocks, ctx->block_size)) {
1365 : 0 : SPDK_ERRLOG("Size of bounce_iovs arrays are not valid or misaligned with block_size.\n");
1366 : 0 : return -EINVAL;
1367 : : }
1368 : :
1369 [ - + ]: 408 : if (_dif_is_disabled(ctx->dif_type)) {
1370 : 0 : return 0;
1371 : : }
1372 : :
1373 [ + + ]: 408 : if (_dif_sgl_is_bytes_multiple(&dst_sgl, data_block_size)) {
1374 : 258 : return dif_verify_copy(&src_sgl, &dst_sgl, num_blocks, ctx, err_blk);
1375 : : } else {
1376 : 150 : return dif_verify_copy_split(&src_sgl, &dst_sgl, num_blocks, ctx, err_blk);
1377 : : }
1378 : : }
1379 : :
1380 : : static void
1381 : 1200 : _bit_flip(uint8_t *buf, uint32_t flip_bit)
1382 : : {
1383 : : uint8_t byte;
1384 : :
1385 : 1200 : byte = *buf;
1386 [ - + ]: 1200 : byte ^= 1 << flip_bit;
1387 : 1200 : *buf = byte;
1388 : 1200 : }
1389 : :
1390 : : static int
1391 : 1200 : _dif_inject_error(struct _dif_sgl *sgl,
1392 : : uint32_t block_size, uint32_t num_blocks,
1393 : : uint32_t inject_offset_blocks,
1394 : : uint32_t inject_offset_bytes,
1395 : : uint32_t inject_offset_bits)
1396 : : {
1397 : 960 : uint32_t offset_in_block, buf_len;
1398 : 960 : uint8_t *buf;
1399 : :
1400 : 1200 : _dif_sgl_advance(sgl, block_size * inject_offset_blocks);
1401 : :
1402 : 1200 : offset_in_block = 0;
1403 : :
1404 [ + - ]: 1620 : while (offset_in_block < block_size) {
1405 : 1620 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
1406 : 1620 : buf_len = spdk_min(buf_len, block_size - offset_in_block);
1407 : :
1408 [ + - ]: 1620 : if (inject_offset_bytes >= offset_in_block &&
1409 [ + + ]: 1620 : inject_offset_bytes < offset_in_block + buf_len) {
1410 : 1200 : buf += inject_offset_bytes - offset_in_block;
1411 : 1200 : _bit_flip(buf, inject_offset_bits);
1412 : 1200 : return 0;
1413 : : }
1414 : :
1415 : 420 : _dif_sgl_advance(sgl, buf_len);
1416 : 420 : offset_in_block += buf_len;
1417 : : }
1418 : :
1419 : 0 : return -1;
1420 : : }
1421 : :
1422 : : static int
1423 : 1200 : dif_inject_error(struct _dif_sgl *sgl, uint32_t block_size, uint32_t num_blocks,
1424 : : uint32_t start_inject_bytes, uint32_t inject_range_bytes,
1425 : : uint32_t *inject_offset)
1426 : : {
1427 : : uint32_t inject_offset_blocks, inject_offset_bytes, inject_offset_bits;
1428 : : uint32_t offset_blocks;
1429 : : int rc;
1430 : :
1431 : 1200 : srand(time(0));
1432 : :
1433 [ - + ]: 1200 : inject_offset_blocks = rand() % num_blocks;
1434 [ - + ]: 1200 : inject_offset_bytes = start_inject_bytes + (rand() % inject_range_bytes);
1435 : 1200 : inject_offset_bits = rand() % 8;
1436 : :
1437 [ + - ]: 3312 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1438 [ + + ]: 3312 : if (offset_blocks == inject_offset_blocks) {
1439 : 1200 : rc = _dif_inject_error(sgl, block_size, num_blocks,
1440 : : inject_offset_blocks,
1441 : : inject_offset_bytes,
1442 : : inject_offset_bits);
1443 [ + - ]: 1200 : if (rc == 0) {
1444 : 1200 : *inject_offset = inject_offset_blocks;
1445 : : }
1446 : 1200 : return rc;
1447 : : }
1448 : : }
1449 : :
1450 : 0 : return -1;
1451 : : }
1452 : :
1453 : : int
1454 : 960 : spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
1455 : : const struct spdk_dif_ctx *ctx, uint32_t inject_flags,
1456 : : uint32_t *inject_offset)
1457 : : {
1458 : 768 : struct _dif_sgl sgl;
1459 : : int rc;
1460 : :
1461 : 960 : _dif_sgl_init(&sgl, iovs, iovcnt);
1462 : :
1463 [ - + ]: 960 : if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) {
1464 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
1465 : 0 : return -EINVAL;
1466 : : }
1467 : :
1468 [ + + ]: 960 : if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
1469 : 288 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1470 : 240 : ctx->guard_interval + _dif_reftag_offset(ctx->dif_pi_format),
1471 : 240 : _dif_reftag_size(ctx->dif_pi_format),
1472 : : inject_offset);
1473 [ - + ]: 240 : if (rc != 0) {
1474 : 0 : SPDK_ERRLOG("Failed to inject error to Reference Tag.\n");
1475 : 0 : return rc;
1476 : : }
1477 : : }
1478 : :
1479 [ + + ]: 960 : if (inject_flags & SPDK_DIF_APPTAG_ERROR) {
1480 : 288 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1481 : 240 : ctx->guard_interval + _dif_apptag_offset(ctx->dif_pi_format),
1482 : 240 : _dif_apptag_size(),
1483 : : inject_offset);
1484 [ - + ]: 240 : if (rc != 0) {
1485 : 0 : SPDK_ERRLOG("Failed to inject error to Application Tag.\n");
1486 : 0 : return rc;
1487 : : }
1488 : : }
1489 [ + + ]: 960 : if (inject_flags & SPDK_DIF_GUARD_ERROR) {
1490 : 240 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1491 : 240 : ctx->guard_interval,
1492 : 240 : _dif_guard_size(ctx->dif_pi_format),
1493 : : inject_offset);
1494 [ - + ]: 240 : if (rc != 0) {
1495 : 0 : SPDK_ERRLOG("Failed to inject error to Guard.\n");
1496 : 0 : return rc;
1497 : : }
1498 : : }
1499 : :
1500 [ + + ]: 960 : if (inject_flags & SPDK_DIF_DATA_ERROR) {
1501 : : /* If the DIF information is contained within the last 8/16 bytes of
1502 : : * metadata (depending on the PI format), then the CRC covers all metadata
1503 : : * bytes up to but excluding the last 8/16 bytes. But error injection does not
1504 : : * cover these metadata because classification is not determined yet.
1505 : : *
1506 : : * Note: Error injection to data block is expected to be detected as
1507 : : * guard error.
1508 : : */
1509 : 240 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1510 : : 0,
1511 : 240 : ctx->block_size - ctx->md_size,
1512 : : inject_offset);
1513 [ - + ]: 240 : if (rc != 0) {
1514 : 0 : SPDK_ERRLOG("Failed to inject error to data block.\n");
1515 : 0 : return rc;
1516 : : }
1517 : : }
1518 : :
1519 : 960 : return 0;
1520 : : }
1521 : :
1522 : : static void
1523 : 295 : dix_generate(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl,
1524 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1525 : : {
1526 : 295 : uint32_t offset_blocks = 0;
1527 : 236 : uint8_t *data_buf, *md_buf;
1528 : : uint64_t guard;
1529 : :
1530 [ + + ]: 3935 : while (offset_blocks < num_blocks) {
1531 : 3640 : _dif_sgl_get_buf(data_sgl, &data_buf, NULL);
1532 : 3640 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1533 : :
1534 : 3640 : guard = 0;
1535 [ + + ]: 3640 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1536 : 3070 : guard = _dif_generate_guard(ctx->guard_seed, data_buf, ctx->block_size,
1537 : 3070 : ctx->dif_pi_format);
1538 : 3070 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1539 : 3070 : ctx->dif_pi_format);
1540 : : }
1541 : :
1542 : 3640 : _dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx);
1543 : :
1544 : 3640 : _dif_sgl_advance(data_sgl, ctx->block_size);
1545 : 3640 : _dif_sgl_advance(md_sgl, ctx->md_size);
1546 : 3640 : offset_blocks++;
1547 : : }
1548 : 295 : }
1549 : :
1550 : : static void
1551 : 375 : _dix_generate_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl,
1552 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
1553 : : {
1554 : 300 : uint32_t offset_in_block, data_buf_len;
1555 : 300 : uint8_t *data_buf, *md_buf;
1556 : 375 : uint64_t guard = 0;
1557 : :
1558 : 375 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1559 : :
1560 [ + - ]: 375 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1561 : 375 : guard = ctx->guard_seed;
1562 : : }
1563 : 375 : offset_in_block = 0;
1564 : :
1565 [ + + ]: 1155 : while (offset_in_block < ctx->block_size) {
1566 : 780 : _dif_sgl_get_buf(data_sgl, &data_buf, &data_buf_len);
1567 : 780 : data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block);
1568 : :
1569 [ + - ]: 780 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1570 : 780 : guard = _dif_generate_guard(guard, data_buf, data_buf_len,
1571 : 780 : ctx->dif_pi_format);
1572 : : }
1573 : :
1574 : 780 : _dif_sgl_advance(data_sgl, data_buf_len);
1575 : 780 : offset_in_block += data_buf_len;
1576 : : }
1577 : :
1578 [ + - ]: 375 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1579 : 375 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1580 : 375 : ctx->dif_pi_format);
1581 : : }
1582 : :
1583 : 375 : _dif_sgl_advance(md_sgl, ctx->md_size);
1584 : :
1585 : 375 : _dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx);
1586 : 375 : }
1587 : :
1588 : : static void
1589 : 165 : dix_generate_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl,
1590 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1591 : : {
1592 : : uint32_t offset_blocks;
1593 : :
1594 [ + + ]: 540 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1595 : 375 : _dix_generate_split(data_sgl, md_sgl, offset_blocks, ctx);
1596 : : }
1597 : 165 : }
1598 : :
1599 : : int
1600 : 13708 : spdk_dix_generate(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1601 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1602 : : {
1603 : 13616 : struct _dif_sgl data_sgl, md_sgl;
1604 : :
1605 : 13708 : _dif_sgl_init(&data_sgl, iovs, iovcnt);
1606 : 13708 : _dif_sgl_init(&md_sgl, md_iov, 1);
1607 : :
1608 [ + - ]: 13708 : if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) ||
1609 [ - + ]: 13708 : !_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) {
1610 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
1611 : 0 : return -EINVAL;
1612 : : }
1613 : :
1614 [ + + ]: 13708 : if (_dif_is_disabled(ctx->dif_type)) {
1615 : 13248 : return 0;
1616 : : }
1617 : :
1618 [ + + ]: 460 : if (_dif_sgl_is_bytes_multiple(&data_sgl, ctx->block_size)) {
1619 : 295 : dix_generate(&data_sgl, &md_sgl, num_blocks, ctx);
1620 : : } else {
1621 : 165 : dix_generate_split(&data_sgl, &md_sgl, num_blocks, ctx);
1622 : : }
1623 : :
1624 : 460 : return 0;
1625 : : }
1626 : :
1627 : : static int
1628 : 320 : dix_verify(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl,
1629 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1630 : : struct spdk_dif_error *err_blk)
1631 : : {
1632 : 320 : uint32_t offset_blocks = 0;
1633 : 256 : uint8_t *data_buf, *md_buf;
1634 : : uint64_t guard;
1635 : : int rc;
1636 : :
1637 [ + + ]: 4672 : while (offset_blocks < num_blocks) {
1638 : 4472 : _dif_sgl_get_buf(data_sgl, &data_buf, NULL);
1639 : 4472 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1640 : :
1641 : 4472 : guard = 0;
1642 [ + + ]: 4472 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1643 : 3902 : guard = _dif_generate_guard(ctx->guard_seed, data_buf, ctx->block_size,
1644 : 3902 : ctx->dif_pi_format);
1645 : 3902 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1646 : 3902 : ctx->dif_pi_format);
1647 : : }
1648 : :
1649 : 4472 : rc = _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
1650 [ + + ]: 4472 : if (rc != 0) {
1651 : 120 : return rc;
1652 : : }
1653 : :
1654 : 4352 : _dif_sgl_advance(data_sgl, ctx->block_size);
1655 : 4352 : _dif_sgl_advance(md_sgl, ctx->md_size);
1656 : 4352 : offset_blocks++;
1657 : : }
1658 : :
1659 : 200 : return 0;
1660 : : }
1661 : :
1662 : : static int
1663 : 279 : _dix_verify_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl,
1664 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx,
1665 : : struct spdk_dif_error *err_blk)
1666 : : {
1667 : 228 : uint32_t offset_in_block, data_buf_len;
1668 : 228 : uint8_t *data_buf, *md_buf;
1669 : 279 : uint64_t guard = 0;
1670 : :
1671 : 279 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1672 : :
1673 [ + - ]: 279 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1674 : 279 : guard = ctx->guard_seed;
1675 : : }
1676 : 279 : offset_in_block = 0;
1677 : :
1678 [ + + ]: 867 : while (offset_in_block < ctx->block_size) {
1679 : 588 : _dif_sgl_get_buf(data_sgl, &data_buf, &data_buf_len);
1680 : 588 : data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block);
1681 : :
1682 [ + - ]: 588 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1683 : 588 : guard = _dif_generate_guard(guard, data_buf, data_buf_len,
1684 : 588 : ctx->dif_pi_format);
1685 : : }
1686 : :
1687 : 588 : _dif_sgl_advance(data_sgl, data_buf_len);
1688 : 588 : offset_in_block += data_buf_len;
1689 : : }
1690 : :
1691 [ + - ]: 279 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1692 : 279 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1693 : 279 : ctx->dif_pi_format);
1694 : : }
1695 : :
1696 : 279 : _dif_sgl_advance(md_sgl, ctx->md_size);
1697 : :
1698 : 279 : return _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
1699 : : }
1700 : :
1701 : : static int
1702 : 165 : dix_verify_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl,
1703 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1704 : : struct spdk_dif_error *err_blk)
1705 : : {
1706 : : uint32_t offset_blocks;
1707 : : int rc;
1708 : :
1709 [ + + ]: 324 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1710 : 279 : rc = _dix_verify_split(data_sgl, md_sgl, offset_blocks, ctx, err_blk);
1711 [ + + ]: 279 : if (rc != 0) {
1712 : 120 : return rc;
1713 : : }
1714 : : }
1715 : :
1716 : 45 : return 0;
1717 : : }
1718 : :
1719 : : int
1720 : 126741 : spdk_dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1721 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1722 : : struct spdk_dif_error *err_blk)
1723 : : {
1724 : 126644 : struct _dif_sgl data_sgl, md_sgl;
1725 : :
1726 [ - + ]: 126741 : if (md_iov->iov_base == NULL) {
1727 : 0 : SPDK_ERRLOG("Metadata buffer is NULL.\n");
1728 : 0 : return -EINVAL;
1729 : : }
1730 : :
1731 : 126741 : _dif_sgl_init(&data_sgl, iovs, iovcnt);
1732 : 126741 : _dif_sgl_init(&md_sgl, md_iov, 1);
1733 : :
1734 [ + - ]: 126741 : if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) ||
1735 [ - + ]: 126741 : !_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) {
1736 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
1737 : 0 : return -EINVAL;
1738 : : }
1739 : :
1740 [ + + ]: 126741 : if (_dif_is_disabled(ctx->dif_type)) {
1741 : 126256 : return 0;
1742 : : }
1743 : :
1744 [ + + ]: 485 : if (_dif_sgl_is_bytes_multiple(&data_sgl, ctx->block_size)) {
1745 : 320 : return dix_verify(&data_sgl, &md_sgl, num_blocks, ctx, err_blk);
1746 : : } else {
1747 : 165 : return dix_verify_split(&data_sgl, &md_sgl, num_blocks, ctx, err_blk);
1748 : : }
1749 : : }
1750 : :
1751 : : int
1752 : 240 : spdk_dix_inject_error(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1753 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1754 : : uint32_t inject_flags, uint32_t *inject_offset)
1755 : : {
1756 : 192 : struct _dif_sgl data_sgl, md_sgl;
1757 : : int rc;
1758 : :
1759 : 240 : _dif_sgl_init(&data_sgl, iovs, iovcnt);
1760 : 240 : _dif_sgl_init(&md_sgl, md_iov, 1);
1761 : :
1762 [ + - ]: 240 : if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) ||
1763 [ - + ]: 240 : !_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) {
1764 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
1765 : 0 : return -EINVAL;
1766 : : }
1767 : :
1768 [ + + ]: 240 : if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
1769 : 72 : rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks,
1770 : 60 : ctx->guard_interval + _dif_reftag_offset(ctx->dif_pi_format),
1771 : 60 : _dif_reftag_size(ctx->dif_pi_format),
1772 : : inject_offset);
1773 [ - + ]: 60 : if (rc != 0) {
1774 : 0 : SPDK_ERRLOG("Failed to inject error to Reference Tag.\n");
1775 : 0 : return rc;
1776 : : }
1777 : : }
1778 : :
1779 [ + + ]: 240 : if (inject_flags & SPDK_DIF_APPTAG_ERROR) {
1780 : 72 : rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks,
1781 : 60 : ctx->guard_interval + _dif_apptag_offset(ctx->dif_pi_format),
1782 : 60 : _dif_apptag_size(),
1783 : : inject_offset);
1784 [ - + ]: 60 : if (rc != 0) {
1785 : 0 : SPDK_ERRLOG("Failed to inject error to Application Tag.\n");
1786 : 0 : return rc;
1787 : : }
1788 : : }
1789 : :
1790 [ + + ]: 240 : if (inject_flags & SPDK_DIF_GUARD_ERROR) {
1791 : 60 : rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks,
1792 : 60 : ctx->guard_interval,
1793 : 60 : _dif_guard_size(ctx->dif_pi_format),
1794 : : inject_offset);
1795 [ - + ]: 60 : if (rc != 0) {
1796 : 0 : SPDK_ERRLOG("Failed to inject error to Guard.\n");
1797 : 0 : return rc;
1798 : : }
1799 : : }
1800 : :
1801 [ + + ]: 240 : if (inject_flags & SPDK_DIF_DATA_ERROR) {
1802 : : /* Note: Error injection to data block is expected to be detected
1803 : : * as guard error.
1804 : : */
1805 : 60 : rc = dif_inject_error(&data_sgl, ctx->block_size, num_blocks,
1806 : : 0,
1807 : 60 : ctx->block_size,
1808 : : inject_offset);
1809 [ - + ]: 60 : if (rc != 0) {
1810 : 0 : SPDK_ERRLOG("Failed to inject error to Guard.\n");
1811 : 0 : return rc;
1812 : : }
1813 : : }
1814 : :
1815 : 240 : return 0;
1816 : : }
1817 : :
1818 : : static uint32_t
1819 : 90491375 : _to_next_boundary(uint32_t offset, uint32_t boundary)
1820 : : {
1821 [ - + ]: 90491375 : return boundary - (offset % boundary);
1822 : : }
1823 : :
1824 : : static uint32_t
1825 : 8026217 : _to_size_with_md(uint32_t size, uint32_t data_block_size, uint32_t block_size)
1826 : : {
1827 [ - + - + ]: 8026217 : return (size / data_block_size) * block_size + (size % data_block_size);
1828 : : }
1829 : :
1830 : : int
1831 : 1646858 : spdk_dif_set_md_interleave_iovs(struct iovec *iovs, int iovcnt,
1832 : : struct iovec *buf_iovs, int buf_iovcnt,
1833 : : uint32_t data_offset, uint32_t data_len,
1834 : : uint32_t *_mapped_len,
1835 : : const struct spdk_dif_ctx *ctx)
1836 : : {
1837 : : uint32_t data_block_size, data_unalign, buf_len, buf_offset, len;
1838 : 152 : struct _dif_sgl dif_sgl;
1839 : 152 : struct _dif_sgl buf_sgl;
1840 : :
1841 [ + - + - : 1646858 : if (iovs == NULL || iovcnt == 0 || buf_iovs == NULL || buf_iovcnt == 0) {
+ - - + ]
1842 : 0 : return -EINVAL;
1843 : : }
1844 : :
1845 : 1646858 : data_block_size = ctx->block_size - ctx->md_size;
1846 : :
1847 [ - + ]: 1646858 : data_unalign = ctx->data_offset % data_block_size;
1848 : :
1849 : 1646858 : buf_len = _to_size_with_md(data_unalign + data_offset + data_len, data_block_size,
1850 : 1646858 : ctx->block_size);
1851 : 1646858 : buf_len -= data_unalign;
1852 : :
1853 : 1646858 : _dif_sgl_init(&dif_sgl, iovs, iovcnt);
1854 : 1646858 : _dif_sgl_init(&buf_sgl, buf_iovs, buf_iovcnt);
1855 : :
1856 [ + + ]: 1646858 : if (!_dif_sgl_is_valid(&buf_sgl, buf_len)) {
1857 : 5 : SPDK_ERRLOG("Buffer overflow will occur.\n");
1858 : 5 : return -ERANGE;
1859 : : }
1860 : :
1861 : 1646853 : buf_offset = _to_size_with_md(data_unalign + data_offset, data_block_size, ctx->block_size);
1862 : 1646853 : buf_offset -= data_unalign;
1863 : :
1864 : 1646853 : _dif_sgl_advance(&buf_sgl, buf_offset);
1865 : :
1866 [ + + ]: 28018611 : while (data_len != 0) {
1867 [ + + ]: 26711988 : len = spdk_min(data_len, _to_next_boundary(ctx->data_offset + data_offset, data_block_size));
1868 [ + + ]: 26711988 : if (!_dif_sgl_append_split(&dif_sgl, &buf_sgl, len)) {
1869 : 340230 : break;
1870 : : }
1871 : 26371758 : _dif_sgl_advance(&buf_sgl, ctx->md_size);
1872 : 26371758 : data_offset += len;
1873 : 26371758 : data_len -= len;
1874 : : }
1875 : :
1876 [ + - ]: 1646853 : if (_mapped_len != NULL) {
1877 : 1646853 : *_mapped_len = dif_sgl.total_size;
1878 : : }
1879 : :
1880 : 1646853 : return iovcnt - dif_sgl.iovcnt;
1881 : : }
1882 : :
1883 : : static int
1884 : 1005700 : _dif_sgl_setup_stream(struct _dif_sgl *sgl, uint32_t *_buf_offset, uint32_t *_buf_len,
1885 : : uint32_t data_offset, uint32_t data_len,
1886 : : const struct spdk_dif_ctx *ctx)
1887 : : {
1888 : : uint32_t data_block_size, data_unalign, buf_len, buf_offset;
1889 : :
1890 : 1005700 : data_block_size = ctx->block_size - ctx->md_size;
1891 : :
1892 [ - + ]: 1005700 : data_unalign = ctx->data_offset % data_block_size;
1893 : :
1894 : : /* If the last data block is complete, DIF of the data block is
1895 : : * inserted or verified in this turn.
1896 : : */
1897 : 1005700 : buf_len = _to_size_with_md(data_unalign + data_offset + data_len, data_block_size,
1898 : 1005700 : ctx->block_size);
1899 : 1005700 : buf_len -= data_unalign;
1900 : :
1901 [ + + ]: 1005700 : if (!_dif_sgl_is_valid(sgl, buf_len)) {
1902 : 15 : return -ERANGE;
1903 : : }
1904 : :
1905 : 1005685 : buf_offset = _to_size_with_md(data_unalign + data_offset, data_block_size, ctx->block_size);
1906 : 1005685 : buf_offset -= data_unalign;
1907 : :
1908 : 1005685 : _dif_sgl_advance(sgl, buf_offset);
1909 : 1005685 : buf_len -= buf_offset;
1910 : :
1911 : 1005685 : buf_offset += data_unalign;
1912 : :
1913 : 1005685 : *_buf_offset = buf_offset;
1914 : 1005685 : *_buf_len = buf_len;
1915 : :
1916 : 1005685 : return 0;
1917 : : }
1918 : :
1919 : : int
1920 : 245 : spdk_dif_generate_stream(struct iovec *iovs, int iovcnt,
1921 : : uint32_t data_offset, uint32_t data_len,
1922 : : struct spdk_dif_ctx *ctx)
1923 : : {
1924 : 245 : uint32_t buf_len = 0, buf_offset = 0;
1925 : : uint32_t len, offset_in_block, offset_blocks;
1926 : 245 : uint64_t guard = 0;
1927 : 196 : struct _dif_sgl sgl;
1928 : : int rc;
1929 : :
1930 [ + - - + ]: 245 : if (iovs == NULL || iovcnt == 0) {
1931 : 0 : return -EINVAL;
1932 : : }
1933 : :
1934 [ + - ]: 245 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1935 : 245 : guard = ctx->last_guard;
1936 : : }
1937 : :
1938 : 245 : _dif_sgl_init(&sgl, iovs, iovcnt);
1939 : :
1940 : 245 : rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx);
1941 [ + + ]: 245 : if (rc != 0) {
1942 : 15 : return rc;
1943 : : }
1944 : :
1945 [ + + ]: 610 : while (buf_len != 0) {
1946 [ + + ]: 380 : len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size));
1947 [ - + ]: 380 : offset_in_block = buf_offset % ctx->block_size;
1948 [ - + ]: 380 : offset_blocks = buf_offset / ctx->block_size;
1949 : :
1950 : 380 : guard = _dif_generate_split(&sgl, offset_in_block, len, guard, offset_blocks, ctx);
1951 : :
1952 : 380 : buf_len -= len;
1953 : 380 : buf_offset += len;
1954 : : }
1955 : :
1956 [ + - ]: 230 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1957 : 230 : ctx->last_guard = guard;
1958 : : }
1959 : :
1960 : 230 : return 0;
1961 : : }
1962 : :
1963 : : int
1964 : 823379 : spdk_dif_verify_stream(struct iovec *iovs, int iovcnt,
1965 : : uint32_t data_offset, uint32_t data_len,
1966 : : struct spdk_dif_ctx *ctx,
1967 : : struct spdk_dif_error *err_blk)
1968 : : {
1969 : 823379 : uint32_t buf_len = 0, buf_offset = 0;
1970 : : uint32_t len, offset_in_block, offset_blocks;
1971 : 823379 : uint64_t guard = 0;
1972 : 36 : struct _dif_sgl sgl;
1973 : 823379 : int rc = 0;
1974 : :
1975 [ + - - + ]: 823379 : if (iovs == NULL || iovcnt == 0) {
1976 : 0 : return -EINVAL;
1977 : : }
1978 : :
1979 [ + - ]: 823379 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1980 : 823379 : guard = ctx->last_guard;
1981 : : }
1982 : :
1983 : 823379 : _dif_sgl_init(&sgl, iovs, iovcnt);
1984 : :
1985 : 823379 : rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx);
1986 [ - + ]: 823379 : if (rc != 0) {
1987 : 0 : return rc;
1988 : : }
1989 : :
1990 [ + + ]: 14179203 : while (buf_len != 0) {
1991 [ + + ]: 13355824 : len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size));
1992 [ - + ]: 13355824 : offset_in_block = buf_offset % ctx->block_size;
1993 [ - + ]: 13355824 : offset_blocks = buf_offset / ctx->block_size;
1994 : :
1995 : 13355824 : rc = _dif_verify_split(&sgl, offset_in_block, len, &guard, offset_blocks,
1996 : : ctx, err_blk);
1997 [ - + ]: 13355824 : if (rc != 0) {
1998 : 0 : goto error;
1999 : : }
2000 : :
2001 : 13355824 : buf_len -= len;
2002 : 13355824 : buf_offset += len;
2003 : : }
2004 : :
2005 [ - + ]: 823379 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
2006 : 823379 : ctx->last_guard = guard;
2007 : : }
2008 : 36 : error:
2009 : 823379 : return rc;
2010 : : }
2011 : :
2012 : : int
2013 : 182076 : spdk_dif_update_crc32c_stream(struct iovec *iovs, int iovcnt,
2014 : : uint32_t data_offset, uint32_t data_len,
2015 : : uint32_t *_crc32c, const struct spdk_dif_ctx *ctx)
2016 : : {
2017 : 182076 : uint32_t buf_len = 0, buf_offset = 0, len, offset_in_block;
2018 : : uint32_t crc32c;
2019 : 36 : struct _dif_sgl sgl;
2020 : : int rc;
2021 : :
2022 [ + - - + ]: 182076 : if (iovs == NULL || iovcnt == 0) {
2023 : 0 : return -EINVAL;
2024 : : }
2025 : :
2026 : 182076 : crc32c = *_crc32c;
2027 : 182076 : _dif_sgl_init(&sgl, iovs, iovcnt);
2028 : :
2029 : 182076 : rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx);
2030 [ - + ]: 182076 : if (rc != 0) {
2031 : 0 : return rc;
2032 : : }
2033 : :
2034 [ + + ]: 5359729 : while (buf_len != 0) {
2035 [ + + ]: 5177653 : len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size));
2036 [ - + ]: 5177653 : offset_in_block = buf_offset % ctx->block_size;
2037 : :
2038 : 5177653 : crc32c = _dif_update_crc32c_split(&sgl, offset_in_block, len, crc32c, ctx);
2039 : :
2040 : 5177653 : buf_len -= len;
2041 : 5177653 : buf_offset += len;
2042 : : }
2043 : :
2044 : 182076 : *_crc32c = crc32c;
2045 : :
2046 : 182076 : return 0;
2047 : : }
2048 : :
2049 : : void
2050 : 1074348 : spdk_dif_get_range_with_md(uint32_t data_offset, uint32_t data_len,
2051 : : uint32_t *_buf_offset, uint32_t *_buf_len,
2052 : : const struct spdk_dif_ctx *ctx)
2053 : : {
2054 : : uint32_t data_block_size, data_unalign, buf_offset, buf_len;
2055 : :
2056 [ - + - + ]: 1074348 : if (!ctx->md_interleave) {
2057 : 0 : buf_offset = data_offset;
2058 : 0 : buf_len = data_len;
2059 : : } else {
2060 : 1074348 : data_block_size = ctx->block_size - ctx->md_size;
2061 : :
2062 [ - + ]: 1074348 : data_unalign = data_offset % data_block_size;
2063 : :
2064 : 1074348 : buf_offset = _to_size_with_md(data_offset, data_block_size, ctx->block_size);
2065 : 1074348 : buf_len = _to_size_with_md(data_unalign + data_len, data_block_size, ctx->block_size) -
2066 : : data_unalign;
2067 : : }
2068 : :
2069 [ + - ]: 1074348 : if (_buf_offset != NULL) {
2070 : 1074348 : *_buf_offset = buf_offset;
2071 : : }
2072 : :
2073 [ + - ]: 1074348 : if (_buf_len != NULL) {
2074 : 1074348 : *_buf_len = buf_len;
2075 : : }
2076 : 1074348 : }
2077 : :
2078 : : uint32_t
2079 : 572425 : spdk_dif_get_length_with_md(uint32_t data_len, const struct spdk_dif_ctx *ctx)
2080 : : {
2081 : : uint32_t data_block_size;
2082 : :
2083 [ - + - + ]: 572425 : if (!ctx->md_interleave) {
2084 : 0 : return data_len;
2085 : : } else {
2086 : 572425 : data_block_size = ctx->block_size - ctx->md_size;
2087 : :
2088 : 572425 : return _to_size_with_md(data_len, data_block_size, ctx->block_size);
2089 : : }
2090 : : }
2091 : :
2092 : : static int
2093 : 360 : _dif_remap_ref_tag(struct _dif_sgl *sgl, uint32_t offset_blocks,
2094 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk,
2095 : : bool check_ref_tag)
2096 : : {
2097 : 288 : uint32_t offset, buf_len;
2098 : 360 : uint64_t expected = 0, remapped;
2099 : 288 : uint8_t *buf;
2100 : 288 : struct _dif_sgl tmp_sgl;
2101 : 288 : struct spdk_dif dif;
2102 : :
2103 : : /* Fast forward to DIF field. */
2104 : 360 : _dif_sgl_advance(sgl, ctx->guard_interval);
2105 : 360 : _dif_sgl_copy(&tmp_sgl, sgl);
2106 : :
2107 : : /* Copy the split DIF field to the temporary DIF buffer */
2108 : 360 : offset = 0;
2109 [ + + ]: 810 : while (offset < _dif_size(ctx->dif_pi_format)) {
2110 : 450 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
2111 [ + + ]: 450 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset);
2112 : :
2113 [ - + - + ]: 450 : memcpy((uint8_t *)&dif + offset, buf, buf_len);
2114 : :
2115 : 450 : _dif_sgl_advance(sgl, buf_len);
2116 : 450 : offset += buf_len;
2117 : : }
2118 : :
2119 [ - + ]: 360 : if (_dif_ignore(&dif, ctx)) {
2120 : 0 : goto end;
2121 : : }
2122 : :
2123 : : /* For type 1 and 2, the Reference Tag is incremented for each
2124 : : * subsequent logical block. For type 3, the Reference Tag
2125 : : * remains the same as the initial Reference Tag.
2126 : : */
2127 [ + - ]: 360 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
2128 : 360 : expected = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
2129 : 360 : remapped = ctx->remapped_init_ref_tag + ctx->ref_tag_offset + offset_blocks;
2130 : : } else {
2131 : 0 : remapped = ctx->remapped_init_ref_tag;
2132 : : }
2133 : :
2134 : : /* Verify the stored Reference Tag. */
2135 [ + - - + ]: 360 : if (check_ref_tag && !_dif_reftag_check(&dif, ctx, expected, offset_blocks, err_blk)) {
2136 : 0 : return -1;
2137 : : }
2138 : :
2139 : : /* Update the stored Reference Tag to the remapped one. */
2140 : 360 : _dif_set_reftag(&dif, remapped, ctx->dif_pi_format);
2141 : :
2142 : 360 : offset = 0;
2143 [ + + ]: 810 : while (offset < _dif_size(ctx->dif_pi_format)) {
2144 : 450 : _dif_sgl_get_buf(&tmp_sgl, &buf, &buf_len);
2145 [ + + ]: 450 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset);
2146 : :
2147 [ - + - + ]: 450 : memcpy(buf, (uint8_t *)&dif + offset, buf_len);
2148 : :
2149 : 450 : _dif_sgl_advance(&tmp_sgl, buf_len);
2150 : 450 : offset += buf_len;
2151 : : }
2152 : :
2153 : 360 : end:
2154 : 360 : _dif_sgl_advance(sgl, ctx->block_size - ctx->guard_interval - _dif_size(ctx->dif_pi_format));
2155 : :
2156 : 360 : return 0;
2157 : : }
2158 : :
2159 : : int
2160 : 60 : spdk_dif_remap_ref_tag(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
2161 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk,
2162 : : bool check_ref_tag)
2163 : : {
2164 : 48 : struct _dif_sgl sgl;
2165 : : uint32_t offset_blocks;
2166 : : int rc;
2167 : :
2168 : 60 : _dif_sgl_init(&sgl, iovs, iovcnt);
2169 : :
2170 [ - + ]: 60 : if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) {
2171 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
2172 : 0 : return -EINVAL;
2173 : : }
2174 : :
2175 [ - + ]: 60 : if (_dif_is_disabled(ctx->dif_type)) {
2176 : 0 : return 0;
2177 : : }
2178 : :
2179 [ - + ]: 60 : if (!(ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK)) {
2180 : 0 : return 0;
2181 : : }
2182 : :
2183 [ + + ]: 420 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
2184 : 360 : rc = _dif_remap_ref_tag(&sgl, offset_blocks, ctx, err_blk, check_ref_tag);
2185 [ - + ]: 360 : if (rc != 0) {
2186 : 0 : return rc;
2187 : : }
2188 : : }
2189 : :
2190 : 60 : return 0;
2191 : : }
2192 : :
2193 : : static int
2194 : 1000 : _dix_remap_ref_tag(struct _dif_sgl *md_sgl, uint32_t offset_blocks,
2195 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk,
2196 : : bool check_ref_tag)
2197 : : {
2198 : 1000 : uint64_t expected = 0, remapped;
2199 : 800 : uint8_t *md_buf;
2200 : : struct spdk_dif *dif;
2201 : :
2202 : 1000 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
2203 : :
2204 : 1000 : dif = (struct spdk_dif *)(md_buf + ctx->guard_interval);
2205 : :
2206 [ - + ]: 1000 : if (_dif_ignore(dif, ctx)) {
2207 : 0 : goto end;
2208 : : }
2209 : :
2210 : : /* For type 1 and 2, the Reference Tag is incremented for each
2211 : : * subsequent logical block. For type 3, the Reference Tag
2212 : : * remains the same as the initialReference Tag.
2213 : : */
2214 [ + - ]: 1000 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
2215 : 1000 : expected = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
2216 : 1000 : remapped = ctx->remapped_init_ref_tag + ctx->ref_tag_offset + offset_blocks;
2217 : : } else {
2218 : 0 : remapped = ctx->remapped_init_ref_tag;
2219 : : }
2220 : :
2221 : : /* Verify the stored Reference Tag. */
2222 [ + + - + ]: 1000 : if (check_ref_tag && !_dif_reftag_check(dif, ctx, expected, offset_blocks, err_blk)) {
2223 : 0 : return -1;
2224 : : }
2225 : :
2226 : : /* Update the stored Reference Tag to the remapped one. */
2227 : 1000 : _dif_set_reftag(dif, remapped, ctx->dif_pi_format);
2228 : :
2229 : 1000 : end:
2230 : 1000 : _dif_sgl_advance(md_sgl, ctx->md_size);
2231 : :
2232 : 1000 : return 0;
2233 : : }
2234 : :
2235 : : int
2236 : 60 : spdk_dix_remap_ref_tag(struct iovec *md_iov, uint32_t num_blocks,
2237 : : const struct spdk_dif_ctx *ctx,
2238 : : struct spdk_dif_error *err_blk,
2239 : : bool check_ref_tag)
2240 : : {
2241 : 48 : struct _dif_sgl md_sgl;
2242 : : uint32_t offset_blocks;
2243 : : int rc;
2244 : :
2245 : 60 : _dif_sgl_init(&md_sgl, md_iov, 1);
2246 : :
2247 [ - + ]: 60 : if (!_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) {
2248 : 0 : SPDK_ERRLOG("Size of metadata iovec array is not valid.\n");
2249 : 0 : return -EINVAL;
2250 : : }
2251 : :
2252 [ - + ]: 60 : if (_dif_is_disabled(ctx->dif_type)) {
2253 : 0 : return 0;
2254 : : }
2255 : :
2256 [ - + ]: 60 : if (!(ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK)) {
2257 : 0 : return 0;
2258 : : }
2259 : :
2260 [ + + ]: 1060 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
2261 : 1000 : rc = _dix_remap_ref_tag(&md_sgl, offset_blocks, ctx, err_blk, check_ref_tag);
2262 [ - + ]: 1000 : if (rc != 0) {
2263 : 0 : return rc;
2264 : : }
2265 : : }
2266 : :
2267 : 60 : return 0;
2268 : : }
|