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