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 2429 : _dif_sgl_init(struct _dif_sgl *s, struct iovec *iovs, int iovcnt)
65 : {
66 2429 : s->iov = iovs;
67 2429 : s->iovcnt = iovcnt;
68 2429 : s->iov_offset = 0;
69 2429 : s->total_size = 0;
70 2429 : }
71 :
72 : static void
73 15041 : _dif_sgl_advance(struct _dif_sgl *s, uint32_t step)
74 : {
75 15041 : s->iov_offset += step;
76 20477 : while (s->iovcnt != 0) {
77 18671 : if (s->iov_offset < s->iov->iov_len) {
78 13235 : break;
79 : }
80 :
81 5436 : s->iov_offset -= s->iov->iov_len;
82 5436 : s->iov++;
83 5436 : s->iovcnt--;
84 : }
85 15041 : }
86 :
87 : static inline void
88 14901 : _dif_sgl_get_buf(struct _dif_sgl *s, uint8_t **_buf, uint32_t *_buf_len)
89 : {
90 14901 : if (_buf != NULL) {
91 14901 : *_buf = (uint8_t *)s->iov->iov_base + s->iov_offset;
92 : }
93 14901 : if (_buf_len != NULL) {
94 8082 : *_buf_len = s->iov->iov_len - s->iov_offset;
95 : }
96 14901 : }
97 :
98 : static inline bool
99 120 : _dif_sgl_append(struct _dif_sgl *s, uint8_t *data, uint32_t data_len)
100 : {
101 120 : assert(s->iovcnt > 0);
102 120 : s->iov->iov_base = data;
103 120 : s->iov->iov_len = data_len;
104 120 : s->total_size += data_len;
105 120 : s->iov++;
106 120 : s->iovcnt--;
107 :
108 120 : if (s->iovcnt > 0) {
109 100 : return true;
110 : } else {
111 20 : return false;
112 : }
113 : }
114 :
115 : static inline bool
116 104 : _dif_sgl_append_split(struct _dif_sgl *dst, struct _dif_sgl *src, uint32_t data_len)
117 : {
118 104 : uint8_t *buf;
119 104 : uint32_t buf_len;
120 :
121 204 : while (data_len != 0) {
122 120 : _dif_sgl_get_buf(src, &buf, &buf_len);
123 120 : buf_len = spdk_min(buf_len, data_len);
124 :
125 120 : if (!_dif_sgl_append(dst, buf, buf_len)) {
126 20 : return false;
127 : }
128 :
129 100 : _dif_sgl_advance(src, buf_len);
130 100 : data_len -= buf_len;
131 : }
132 :
133 84 : return true;
134 : }
135 :
136 : /* This function must be used before starting iteration. */
137 : static bool
138 849 : _dif_sgl_is_bytes_multiple(struct _dif_sgl *s, uint32_t bytes)
139 : {
140 : int i;
141 :
142 2119 : for (i = 0; i < s->iovcnt; i++) {
143 1704 : if (s->iov[i].iov_len % bytes) {
144 434 : return false;
145 : }
146 : }
147 :
148 415 : return true;
149 : }
150 :
151 : static bool
152 156 : _dif_sgl_is_valid_block_aligned(struct _dif_sgl *s, uint32_t num_blocks, uint32_t block_size)
153 : {
154 156 : uint32_t count = 0;
155 : int i;
156 :
157 312 : for (i = 0; i < s->iovcnt; i++) {
158 156 : if (s->iov[i].iov_len % block_size) {
159 0 : return false;
160 : }
161 156 : count += s->iov[i].iov_len / block_size;
162 : }
163 :
164 156 : return count >= num_blocks;
165 : }
166 :
167 : /* This function must be used before starting iteration. */
168 : static bool
169 2208 : _dif_sgl_is_valid(struct _dif_sgl *s, uint32_t bytes)
170 : {
171 2208 : uint64_t total = 0;
172 : int i;
173 :
174 8222 : for (i = 0; i < s->iovcnt; i++) {
175 6014 : total += s->iov[i].iov_len;
176 : }
177 :
178 2208 : return total >= bytes;
179 : }
180 :
181 : static void
182 72 : _dif_sgl_copy(struct _dif_sgl *to, struct _dif_sgl *from)
183 : {
184 72 : memcpy(to, from, sizeof(struct _dif_sgl));
185 72 : }
186 :
187 : static bool
188 860 : _dif_is_disabled(enum spdk_dif_type dif_type)
189 : {
190 860 : if (dif_type == SPDK_DIF_DISABLE) {
191 2 : return true;
192 : } else {
193 858 : return false;
194 : }
195 : }
196 :
197 : static inline size_t
198 3449 : _dif_size(enum spdk_dif_pi_format dif_pi_format)
199 : {
200 : uint8_t size;
201 :
202 3449 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
203 1273 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g16);
204 2176 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
205 1109 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g32);
206 : } else {
207 1067 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g64);
208 : }
209 :
210 3449 : return size;
211 : }
212 :
213 : static uint32_t
214 507 : _get_guard_interval(uint32_t block_size, uint32_t md_size, bool dif_loc, bool md_interleave,
215 : size_t dif_size)
216 : {
217 507 : 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 305 : if (md_interleave) {
224 227 : return block_size - dif_size;
225 : } else {
226 78 : 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 202 : if (md_interleave) {
234 166 : return block_size - md_size;
235 : } else {
236 36 : return 0;
237 : }
238 : }
239 : }
240 :
241 : static inline uint8_t
242 180 : _dif_guard_size(enum spdk_dif_pi_format dif_pi_format)
243 : {
244 : uint8_t size;
245 :
246 180 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
247 60 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g16.guard);
248 120 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
249 60 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g32.guard);
250 : } else {
251 60 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g64.guard);
252 : }
253 :
254 180 : return size;
255 : }
256 :
257 : static inline void
258 1801 : _dif_set_guard(struct spdk_dif *dif, uint64_t guard, enum spdk_dif_pi_format dif_pi_format)
259 : {
260 1801 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
261 757 : to_be16(&(dif->g16.guard), (uint16_t)guard);
262 1044 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
263 531 : to_be32(&(dif->g32.guard), (uint32_t)guard);
264 : } else {
265 513 : to_be64(&(dif->g64.guard), guard);
266 : }
267 1801 : }
268 :
269 : static inline uint64_t
270 1998 : _dif_get_guard(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
271 : {
272 : uint64_t guard;
273 :
274 1998 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
275 969 : guard = (uint64_t)from_be16(&(dif->g16.guard));
276 1029 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
277 514 : guard = (uint64_t)from_be32(&(dif->g32.guard));
278 : } else {
279 515 : guard = from_be64(&(dif->g64.guard));
280 : }
281 :
282 1998 : return guard;
283 : }
284 :
285 : static inline uint64_t
286 5920 : _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 5920 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
292 2891 : guard = (uint64_t)spdk_crc16_t10dif((uint16_t)guard_seed, buf, buf_len);
293 3029 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
294 1529 : guard = (uint64_t)spdk_crc32c_nvme(buf, buf_len, guard_seed);
295 : } else {
296 1500 : guard = spdk_crc64_nvme(buf, buf_len, guard_seed);
297 : }
298 :
299 5920 : return guard;
300 : }
301 :
302 : static inline uint64_t
303 918 : _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 918 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
309 306 : guard = (uint64_t)spdk_crc16_t10dif_copy((uint16_t)guard_seed, dst, src, buf_len);
310 612 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
311 306 : memcpy(dst, src, buf_len);
312 306 : guard = (uint64_t)spdk_crc32c_nvme(src, buf_len, guard_seed);
313 : } else {
314 306 : memcpy(dst, src, buf_len);
315 306 : guard = spdk_crc64_nvme(src, buf_len, guard_seed);
316 : }
317 :
318 918 : return guard;
319 : }
320 :
321 : static inline uint8_t
322 120 : _dif_apptag_offset(enum spdk_dif_pi_format dif_pi_format)
323 : {
324 120 : return _dif_guard_size(dif_pi_format);
325 : }
326 :
327 : static inline uint8_t
328 120 : _dif_apptag_size(void)
329 : {
330 120 : return SPDK_SIZEOF_MEMBER(struct spdk_dif, g16.app_tag);
331 : }
332 :
333 : static inline void
334 1793 : _dif_set_apptag(struct spdk_dif *dif, uint16_t app_tag, enum spdk_dif_pi_format dif_pi_format)
335 : {
336 1793 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
337 756 : to_be16(&(dif->g16.app_tag), app_tag);
338 1037 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
339 528 : to_be16(&(dif->g32.app_tag), app_tag);
340 : } else {
341 509 : to_be16(&(dif->g64.app_tag), app_tag);
342 : }
343 1793 : }
344 :
345 : static inline uint16_t
346 4468 : _dif_get_apptag(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
347 : {
348 : uint16_t app_tag;
349 :
350 4468 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
351 2187 : app_tag = from_be16(&(dif->g16.app_tag));
352 2281 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
353 1141 : app_tag = from_be16(&(dif->g32.app_tag));
354 : } else {
355 1140 : app_tag = from_be16(&(dif->g64.app_tag));
356 : }
357 :
358 4468 : return app_tag;
359 : }
360 :
361 : static inline bool
362 2602 : _dif_apptag_ignore(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
363 : {
364 2602 : return _dif_get_apptag(dif, dif_pi_format) == SPDK_DIF_APPTAG_IGNORE;
365 : }
366 :
367 : static inline uint8_t
368 60 : _dif_reftag_offset(enum spdk_dif_pi_format dif_pi_format)
369 : {
370 : uint8_t offset;
371 :
372 60 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
373 20 : offset = _dif_apptag_offset(dif_pi_format) + _dif_apptag_size();
374 40 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
375 20 : 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 20 : offset = _dif_apptag_offset(dif_pi_format) + _dif_apptag_size();
379 : }
380 :
381 60 : return offset;
382 : }
383 :
384 : static inline uint8_t
385 60 : _dif_reftag_size(enum spdk_dif_pi_format dif_pi_format)
386 : {
387 : uint8_t size;
388 :
389 60 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
390 20 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g16.stor_ref_space);
391 40 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
392 20 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g32.stor_ref_space_p2);
393 : } else {
394 20 : 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 60 : return size;
399 : }
400 :
401 : static inline void
402 2062 : _dif_set_reftag(struct spdk_dif *dif, uint64_t ref_tag, enum spdk_dif_pi_format dif_pi_format)
403 : {
404 2062 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
405 931 : to_be32(&(dif->g16.stor_ref_space), (uint32_t)ref_tag);
406 1131 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
407 574 : to_be64(&(dif->g32.stor_ref_space_p2), ref_tag);
408 : } else {
409 557 : to_be16(&(dif->g64.stor_ref_space_p1), (uint16_t)(ref_tag >> 32));
410 557 : to_be32(&(dif->g64.stor_ref_space_p2), (uint32_t)ref_tag);
411 : }
412 2062 : }
413 :
414 : static inline uint64_t
415 2012 : _dif_get_reftag(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
416 : {
417 : uint64_t ref_tag;
418 :
419 2012 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
420 978 : ref_tag = (uint64_t)from_be32(&(dif->g16.stor_ref_space));
421 1034 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
422 517 : ref_tag = from_be64(&(dif->g32.stor_ref_space_p2));
423 : } else {
424 517 : ref_tag = (uint64_t)from_be16(&(dif->g64.stor_ref_space_p1));
425 517 : ref_tag <<= 32;
426 517 : ref_tag |= (uint64_t)from_be32(&(dif->g64.stor_ref_space_p2));
427 : }
428 :
429 2012 : return ref_tag;
430 : }
431 :
432 : static inline bool
433 1944 : _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 1944 : _ref_tag = _dif_get_reftag(dif, dif_pi_format);
440 :
441 1944 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
442 954 : match = (_ref_tag == (ref_tag & REFTAG_MASK_16));
443 990 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
444 495 : match = (_ref_tag == ref_tag);
445 : } else {
446 495 : match = (_ref_tag == (ref_tag & REFTAG_MASK_64));
447 : }
448 :
449 1944 : return match;
450 : }
451 :
452 : static inline bool
453 7 : _dif_reftag_ignore(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
454 : {
455 7 : return _dif_reftag_match(dif, REFTAG_MASK_32, dif_pi_format);
456 : }
457 :
458 : static bool
459 2602 : _dif_ignore(struct spdk_dif *dif, const struct spdk_dif_ctx *ctx)
460 : {
461 2602 : switch (ctx->dif_type) {
462 2595 : 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 2595 : if (_dif_apptag_ignore(dif, ctx->dif_pi_format)) {
468 6 : return true;
469 : }
470 2589 : break;
471 7 : 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 14 : if (_dif_apptag_ignore(dif, ctx->dif_pi_format) &&
478 7 : _dif_reftag_ignore(dif, ctx->dif_pi_format)) {
479 4 : return true;
480 : }
481 3 : break;
482 0 : default:
483 0 : break;
484 : }
485 :
486 2592 : return false;
487 : }
488 :
489 : static bool
490 508 : _dif_pi_format_is_valid(enum spdk_dif_pi_format dif_pi_format)
491 : {
492 508 : switch (dif_pi_format) {
493 507 : case SPDK_DIF_PI_FORMAT_16:
494 : case SPDK_DIF_PI_FORMAT_32:
495 : case SPDK_DIF_PI_FORMAT_64:
496 507 : return true;
497 1 : default:
498 1 : return false;
499 : }
500 : }
501 :
502 : static bool
503 509 : _dif_type_is_valid(enum spdk_dif_type dif_type)
504 : {
505 509 : switch (dif_type) {
506 508 : case SPDK_DIF_DISABLE:
507 : case SPDK_DIF_TYPE1:
508 : case SPDK_DIF_TYPE2:
509 : case SPDK_DIF_TYPE3:
510 508 : return true;
511 1 : default:
512 1 : return false;
513 : }
514 : }
515 :
516 : int
517 504 : 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 504 : enum spdk_dif_pi_format dif_pi_format = SPDK_DIF_PI_FORMAT_16;
524 :
525 504 : if (opts != NULL) {
526 504 : 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 504 : dif_pi_format = opts->dif_pi_format;
532 : }
533 :
534 504 : 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 504 : if (md_size < _dif_size(dif_pi_format)) {
540 10 : SPDK_ERRLOG("Metadata size is smaller than DIF size.\n");
541 10 : return -EINVAL;
542 : }
543 :
544 494 : if (md_interleave) {
545 375 : if (block_size < md_size) {
546 0 : SPDK_ERRLOG("Block size is smaller than DIF size.\n");
547 0 : return -EINVAL;
548 : }
549 375 : data_block_size = block_size - md_size;
550 : } else {
551 119 : data_block_size = block_size;
552 : }
553 :
554 494 : if (data_block_size == 0) {
555 2 : SPDK_ERRLOG("Zero data block size is not allowed\n");
556 2 : return -EINVAL;
557 : }
558 :
559 492 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
560 188 : 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 304 : if ((data_block_size % 4096) != 0) {
566 6 : SPDK_ERRLOG("Data block size should be a multiple of 4kB\n");
567 6 : return -EINVAL;
568 : }
569 : }
570 :
571 486 : ctx->block_size = block_size;
572 486 : ctx->md_size = md_size;
573 486 : ctx->md_interleave = md_interleave;
574 486 : ctx->dif_pi_format = dif_pi_format;
575 486 : ctx->guard_interval = _get_guard_interval(block_size, md_size, dif_loc, md_interleave,
576 486 : _dif_size(ctx->dif_pi_format));
577 486 : ctx->dif_type = dif_type;
578 486 : ctx->dif_flags = dif_flags;
579 486 : ctx->init_ref_tag = init_ref_tag;
580 486 : ctx->apptag_mask = apptag_mask;
581 486 : ctx->app_tag = app_tag;
582 486 : ctx->data_offset = data_offset;
583 486 : ctx->ref_tag_offset = data_offset / data_block_size;
584 486 : ctx->last_guard = guard_seed;
585 486 : ctx->guard_seed = guard_seed;
586 486 : ctx->remapped_init_ref_tag = 0;
587 :
588 486 : return 0;
589 : }
590 :
591 : void
592 42 : spdk_dif_ctx_set_data_offset(struct spdk_dif_ctx *ctx, uint32_t data_offset)
593 : {
594 : uint32_t data_block_size;
595 :
596 42 : if (ctx->md_interleave) {
597 42 : data_block_size = ctx->block_size - ctx->md_size;
598 : } else {
599 0 : data_block_size = ctx->block_size;
600 : }
601 :
602 42 : ctx->data_offset = data_offset;
603 42 : ctx->ref_tag_offset = data_offset / data_block_size;
604 42 : }
605 :
606 : void
607 24 : spdk_dif_ctx_set_remapped_init_ref_tag(struct spdk_dif_ctx *ctx,
608 : uint32_t remapped_init_ref_tag)
609 : {
610 24 : ctx->remapped_init_ref_tag = remapped_init_ref_tag;
611 24 : }
612 :
613 : static void
614 2131 : _dif_generate(void *_dif, uint64_t guard, uint32_t offset_blocks,
615 : const struct spdk_dif_ctx *ctx)
616 : {
617 2131 : struct spdk_dif *dif = _dif;
618 : uint64_t ref_tag;
619 :
620 2131 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
621 1801 : _dif_set_guard(dif, guard, ctx->dif_pi_format);
622 : }
623 :
624 2131 : if (ctx->dif_flags & SPDK_DIF_FLAGS_APPTAG_CHECK) {
625 1793 : _dif_set_apptag(dif, ctx->app_tag, ctx->dif_pi_format);
626 : }
627 :
628 2131 : 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 1790 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
634 1783 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
635 : } else {
636 7 : 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 1790 : if (ctx->init_ref_tag == SPDK_DIF_REFTAG_IGNORE) {
641 2 : if (ctx->dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
642 2 : 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 1790 : _dif_set_reftag(dif, ref_tag, ctx->dif_pi_format);
651 : }
652 2131 : }
653 :
654 : static void
655 100 : dif_generate(struct _dif_sgl *sgl, uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
656 : {
657 100 : uint32_t offset_blocks = 0;
658 100 : uint8_t *buf;
659 100 : uint64_t guard = 0;
660 :
661 677 : while (offset_blocks < num_blocks) {
662 577 : _dif_sgl_get_buf(sgl, &buf, NULL);
663 :
664 577 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
665 475 : guard = _dif_generate_guard(ctx->guard_seed, buf, ctx->guard_interval, ctx->dif_pi_format);
666 : }
667 :
668 577 : _dif_generate(buf + ctx->guard_interval, guard, offset_blocks, ctx);
669 :
670 577 : _dif_sgl_advance(sgl, ctx->block_size);
671 577 : offset_blocks++;
672 : }
673 100 : }
674 :
675 : static uint64_t
676 262 : _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 262 : uint32_t offset_in_dif, buf_len;
680 262 : uint8_t *buf;
681 262 : struct spdk_dif dif = {};
682 :
683 262 : assert(offset_in_block < ctx->guard_interval);
684 262 : 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 704 : while (data_len != 0 && offset_in_block < ctx->guard_interval) {
689 442 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
690 442 : buf_len = spdk_min(buf_len, data_len);
691 442 : buf_len = spdk_min(buf_len, ctx->guard_interval - offset_in_block);
692 :
693 442 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
694 442 : guard = _dif_generate_guard(guard, buf, buf_len, ctx->dif_pi_format);
695 : }
696 :
697 442 : _dif_sgl_advance(sgl, buf_len);
698 442 : offset_in_block += buf_len;
699 442 : data_len -= buf_len;
700 : }
701 :
702 262 : if (offset_in_block < ctx->guard_interval) {
703 39 : 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 223 : _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 616 : while (offset_in_block < ctx->block_size) {
715 393 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
716 :
717 393 : if (offset_in_block < ctx->guard_interval + _dif_size(ctx->dif_pi_format)) {
718 309 : offset_in_dif = offset_in_block - ctx->guard_interval;
719 309 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset_in_dif);
720 :
721 309 : memcpy(buf, ((uint8_t *)&dif) + offset_in_dif, buf_len);
722 : } else {
723 84 : buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block);
724 : }
725 :
726 393 : _dif_sgl_advance(sgl, buf_len);
727 393 : offset_in_block += buf_len;
728 : }
729 :
730 223 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
731 223 : guard = ctx->guard_seed;
732 : }
733 :
734 223 : return guard;
735 : }
736 :
737 : static void
738 152 : 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 152 : uint64_t guard = 0;
743 :
744 152 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
745 152 : guard = ctx->guard_seed;
746 : }
747 :
748 329 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
749 177 : _dif_generate_split(sgl, 0, ctx->block_size, guard, offset_blocks, ctx);
750 : }
751 152 : }
752 :
753 : int
754 244 : spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
755 : const struct spdk_dif_ctx *ctx)
756 : {
757 244 : struct _dif_sgl sgl;
758 :
759 244 : _dif_sgl_init(&sgl, iovs, iovcnt);
760 :
761 244 : 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 244 : if (_dif_is_disabled(ctx->dif_type)) {
767 1 : return 0;
768 : }
769 :
770 243 : if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
771 91 : dif_generate(&sgl, num_blocks, ctx);
772 : } else {
773 152 : dif_generate_split(&sgl, num_blocks, ctx);
774 : }
775 :
776 243 : return 0;
777 : }
778 :
779 : static void
780 262 : _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 262 : if (err_blk) {
784 253 : err_blk->err_type = err_type;
785 253 : err_blk->expected = expected;
786 253 : err_blk->actual = actual;
787 253 : err_blk->err_offset = err_offset;
788 : }
789 262 : }
790 :
791 : static bool
792 2268 : _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 2268 : if (ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK) {
798 1937 : switch (ctx->dif_type) {
799 1937 : 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 1937 : if (!_dif_reftag_match(dif, expected_reftag, ctx->dif_pi_format)) {
808 66 : reftag = _dif_get_reftag(dif, ctx->dif_pi_format);
809 66 : _dif_error_set(err_blk, SPDK_DIF_REFTAG_ERROR, expected_reftag,
810 : reftag, offset_blocks);
811 66 : SPDK_ERRLOG("Failed to compare Ref Tag: LBA=%" PRIu64 "," \
812 : " Expected=%lx, Actual=%lx\n",
813 : expected_reftag, expected_reftag, reftag);
814 66 : return false;
815 : }
816 1871 : 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 2202 : return true;
828 : }
829 :
830 : static int
831 2330 : _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 2330 : struct spdk_dif *dif = _dif;
835 : uint64_t _guard;
836 : uint16_t _app_tag;
837 : uint64_t ref_tag;
838 :
839 2330 : if (_dif_ignore(dif, ctx)) {
840 10 : 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 2320 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
848 2317 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
849 : } else {
850 3 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset;
851 : }
852 :
853 2320 : 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 1988 : _guard = _dif_get_guard(dif, ctx->dif_pi_format);
858 1988 : if (_guard != guard) {
859 124 : _dif_error_set(err_blk, SPDK_DIF_GUARD_ERROR, _guard, guard,
860 : offset_blocks);
861 124 : SPDK_ERRLOG("Failed to compare Guard: LBA=%" PRIu64 "," \
862 : " Expected=%lx, Actual=%lx\n",
863 : ref_tag, _guard, guard);
864 124 : return -1;
865 : }
866 : }
867 :
868 2196 : 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 1864 : _app_tag = _dif_get_apptag(dif, ctx->dif_pi_format);
873 1864 : if ((_app_tag & ctx->apptag_mask) != (ctx->app_tag & ctx->apptag_mask)) {
874 72 : _dif_error_set(err_blk, SPDK_DIF_APPTAG_ERROR, ctx->app_tag,
875 72 : (_app_tag & ctx->apptag_mask), offset_blocks);
876 72 : 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 72 : return -1;
880 : }
881 : }
882 :
883 2124 : if (!_dif_reftag_check(dif, ctx, ref_tag, offset_blocks, err_blk)) {
884 66 : return -1;
885 : }
886 :
887 2058 : return 0;
888 : }
889 :
890 : static int
891 105 : 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 105 : uint32_t offset_blocks = 0;
895 : int rc;
896 105 : uint8_t *buf;
897 105 : uint64_t guard = 0;
898 :
899 662 : while (offset_blocks < num_blocks) {
900 594 : _dif_sgl_get_buf(sgl, &buf, NULL);
901 :
902 594 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
903 490 : guard = _dif_generate_guard(ctx->guard_seed, buf, ctx->guard_interval, ctx->dif_pi_format);
904 : }
905 :
906 594 : rc = _dif_verify(buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
907 594 : if (rc != 0) {
908 37 : return rc;
909 : }
910 :
911 557 : _dif_sgl_advance(sgl, ctx->block_size);
912 557 : offset_blocks++;
913 : }
914 :
915 68 : return 0;
916 : }
917 :
918 : static int
919 196 : _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 196 : uint32_t offset_in_dif, buf_len;
924 196 : uint8_t *buf;
925 : uint64_t guard;
926 196 : struct spdk_dif dif = {};
927 : int rc;
928 :
929 196 : assert(_guard != NULL);
930 196 : assert(offset_in_block < ctx->guard_interval);
931 196 : assert(offset_in_block + data_len < ctx->guard_interval ||
932 : offset_in_block + data_len == ctx->block_size);
933 :
934 196 : guard = *_guard;
935 :
936 : /* Compute CRC over split logical block data. */
937 557 : while (data_len != 0 && offset_in_block < ctx->guard_interval) {
938 361 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
939 361 : buf_len = spdk_min(buf_len, data_len);
940 361 : buf_len = spdk_min(buf_len, ctx->guard_interval - offset_in_block);
941 :
942 361 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
943 361 : guard = _dif_generate_guard(guard, buf, buf_len, ctx->dif_pi_format);
944 : }
945 :
946 361 : _dif_sgl_advance(sgl, buf_len);
947 361 : offset_in_block += buf_len;
948 361 : data_len -= buf_len;
949 : }
950 :
951 196 : if (offset_in_block < ctx->guard_interval) {
952 15 : *_guard = guard;
953 15 : 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 529 : while (offset_in_block < ctx->block_size) {
959 348 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
960 :
961 348 : if (offset_in_block < ctx->guard_interval + _dif_size(ctx->dif_pi_format)) {
962 264 : offset_in_dif = offset_in_block - ctx->guard_interval;
963 264 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset_in_dif);
964 :
965 264 : memcpy((uint8_t *)&dif + offset_in_dif, buf, buf_len);
966 : } else {
967 84 : buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block);
968 : }
969 348 : _dif_sgl_advance(sgl, buf_len);
970 348 : offset_in_block += buf_len;
971 : }
972 :
973 181 : rc = _dif_verify(&dif, guard, offset_blocks, ctx, err_blk);
974 181 : if (rc != 0) {
975 120 : return rc;
976 : }
977 :
978 61 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
979 61 : guard = ctx->guard_seed;
980 : }
981 :
982 61 : *_guard = guard;
983 61 : return 0;
984 : }
985 :
986 : static int
987 150 : 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 150 : uint64_t guard = 0;
992 : int rc;
993 :
994 150 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
995 150 : guard = ctx->guard_seed;
996 : }
997 :
998 199 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
999 169 : rc = _dif_verify_split(sgl, 0, ctx->block_size, &guard, offset_blocks,
1000 : ctx, err_blk);
1001 169 : if (rc != 0) {
1002 120 : return rc;
1003 : }
1004 : }
1005 :
1006 30 : return 0;
1007 : }
1008 :
1009 : int
1010 247 : 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 247 : struct _dif_sgl sgl;
1014 :
1015 247 : _dif_sgl_init(&sgl, iovs, iovcnt);
1016 :
1017 247 : 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 247 : if (_dif_is_disabled(ctx->dif_type)) {
1023 1 : return 0;
1024 : }
1025 :
1026 246 : if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
1027 96 : return dif_verify(&sgl, num_blocks, ctx, err_blk);
1028 : } else {
1029 150 : return dif_verify_split(&sgl, num_blocks, ctx, err_blk);
1030 : }
1031 : }
1032 :
1033 : static uint32_t
1034 9 : 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 9 : uint8_t *buf;
1039 :
1040 45 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1041 36 : _dif_sgl_get_buf(sgl, &buf, NULL);
1042 :
1043 36 : crc32c = spdk_crc32c_update(buf, ctx->block_size - ctx->md_size, crc32c);
1044 :
1045 36 : _dif_sgl_advance(sgl, ctx->block_size);
1046 : }
1047 :
1048 9 : return crc32c;
1049 : }
1050 :
1051 : static uint32_t
1052 51 : _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 51 : uint32_t data_block_size, buf_len;
1056 51 : uint8_t *buf;
1057 :
1058 51 : data_block_size = ctx->block_size - ctx->md_size;
1059 :
1060 51 : assert(offset_in_block + data_len <= ctx->block_size);
1061 :
1062 174 : while (data_len != 0) {
1063 123 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
1064 123 : buf_len = spdk_min(buf_len, data_len);
1065 :
1066 123 : if (offset_in_block < data_block_size) {
1067 69 : buf_len = spdk_min(buf_len, data_block_size - offset_in_block);
1068 69 : crc32c = spdk_crc32c_update(buf, buf_len, crc32c);
1069 : }
1070 :
1071 123 : _dif_sgl_advance(sgl, buf_len);
1072 123 : offset_in_block += buf_len;
1073 123 : data_len -= buf_len;
1074 : }
1075 :
1076 51 : return crc32c;
1077 : }
1078 :
1079 : static uint32_t
1080 6 : 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 30 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1086 24 : crc32c = _dif_update_crc32c_split(sgl, 0, ctx->block_size, crc32c, ctx);
1087 : }
1088 :
1089 6 : return crc32c;
1090 : }
1091 :
1092 : int
1093 15 : 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 15 : struct _dif_sgl sgl;
1097 :
1098 15 : if (_crc32c == NULL) {
1099 0 : return -EINVAL;
1100 : }
1101 :
1102 15 : _dif_sgl_init(&sgl, iovs, iovcnt);
1103 :
1104 15 : 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 15 : if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
1110 9 : *_crc32c = dif_update_crc32c(&sgl, num_blocks, *_crc32c, ctx);
1111 : } else {
1112 6 : *_crc32c = dif_update_crc32c_split(&sgl, num_blocks, *_crc32c, ctx);
1113 : }
1114 :
1115 15 : return 0;
1116 : }
1117 :
1118 : static void
1119 48 : 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 48 : uint32_t offset_blocks = 0, data_block_size;
1123 48 : uint8_t *src, *dst;
1124 : uint64_t guard;
1125 :
1126 48 : data_block_size = ctx->block_size - ctx->md_size;
1127 :
1128 492 : while (offset_blocks < num_blocks) {
1129 444 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1130 444 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1131 :
1132 444 : guard = 0;
1133 444 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1134 330 : guard = _dif_generate_guard_copy(ctx->guard_seed, dst, src, data_block_size,
1135 330 : ctx->dif_pi_format);
1136 330 : guard = _dif_generate_guard(guard, dst + data_block_size,
1137 330 : ctx->guard_interval - data_block_size, ctx->dif_pi_format);
1138 : } else {
1139 114 : memcpy(dst, src, data_block_size);
1140 : }
1141 :
1142 444 : _dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx);
1143 :
1144 444 : _dif_sgl_advance(src_sgl, data_block_size);
1145 444 : _dif_sgl_advance(dst_sgl, ctx->block_size);
1146 444 : offset_blocks++;
1147 : }
1148 48 : }
1149 :
1150 : static void
1151 63 : _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 63 : uint32_t offset_in_block, src_len, data_block_size;
1155 63 : uint8_t *src, *dst;
1156 63 : uint64_t guard = 0;
1157 :
1158 63 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1159 :
1160 63 : data_block_size = ctx->block_size - ctx->md_size;
1161 :
1162 63 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1163 63 : guard = ctx->guard_seed;
1164 : }
1165 63 : offset_in_block = 0;
1166 :
1167 192 : while (offset_in_block < data_block_size) {
1168 : /* Compute CRC over split logical block data and copy
1169 : * data to bounce buffer.
1170 : */
1171 129 : _dif_sgl_get_buf(src_sgl, &src, &src_len);
1172 129 : src_len = spdk_min(src_len, data_block_size - offset_in_block);
1173 :
1174 129 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1175 129 : guard = _dif_generate_guard_copy(guard, dst + offset_in_block,
1176 129 : src, src_len, ctx->dif_pi_format);
1177 : } else {
1178 0 : memcpy(dst + offset_in_block, src, src_len);
1179 : }
1180 :
1181 129 : _dif_sgl_advance(src_sgl, src_len);
1182 129 : offset_in_block += src_len;
1183 : }
1184 :
1185 63 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1186 63 : guard = _dif_generate_guard(guard, dst + data_block_size,
1187 63 : ctx->guard_interval - data_block_size, ctx->dif_pi_format);
1188 : }
1189 :
1190 63 : _dif_sgl_advance(dst_sgl, ctx->block_size);
1191 :
1192 63 : _dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx);
1193 63 : }
1194 :
1195 : static void
1196 30 : 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 93 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1202 63 : _dif_generate_copy_split(src_sgl, dst_sgl, offset_blocks, ctx);
1203 : }
1204 30 : }
1205 :
1206 : int
1207 78 : 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 78 : struct _dif_sgl src_sgl, dst_sgl;
1212 : uint32_t data_block_size;
1213 :
1214 78 : _dif_sgl_init(&src_sgl, iovs, iovcnt);
1215 78 : _dif_sgl_init(&dst_sgl, bounce_iovs, bounce_iovcnt);
1216 :
1217 78 : data_block_size = ctx->block_size - ctx->md_size;
1218 :
1219 78 : 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 78 : if (!_dif_sgl_is_valid_block_aligned(&dst_sgl, num_blocks, ctx->block_size)) {
1225 0 : SPDK_ERRLOG("Size of bounce_iovs arrays are not valid or misaligned with block_size.\n");
1226 0 : return -EINVAL;
1227 : }
1228 :
1229 78 : if (_dif_is_disabled(ctx->dif_type)) {
1230 0 : return 0;
1231 : }
1232 :
1233 78 : if (_dif_sgl_is_bytes_multiple(&src_sgl, data_block_size)) {
1234 48 : dif_generate_copy(&src_sgl, &dst_sgl, num_blocks, ctx);
1235 : } else {
1236 30 : dif_generate_copy_split(&src_sgl, &dst_sgl, num_blocks, ctx);
1237 : }
1238 :
1239 78 : return 0;
1240 : }
1241 :
1242 : static int
1243 48 : 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 48 : uint32_t offset_blocks = 0, data_block_size;
1248 48 : uint8_t *src, *dst;
1249 : int rc;
1250 : uint64_t guard;
1251 :
1252 48 : data_block_size = ctx->block_size - ctx->md_size;
1253 :
1254 468 : while (offset_blocks < num_blocks) {
1255 444 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1256 444 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1257 :
1258 444 : guard = 0;
1259 444 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1260 330 : guard = _dif_generate_guard_copy(ctx->guard_seed, dst, src, data_block_size,
1261 330 : ctx->dif_pi_format);
1262 330 : guard = _dif_generate_guard(guard, src + data_block_size,
1263 330 : ctx->guard_interval - data_block_size, ctx->dif_pi_format);
1264 : } else {
1265 114 : memcpy(dst, src, data_block_size);
1266 : }
1267 :
1268 444 : rc = _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
1269 444 : if (rc != 0) {
1270 24 : return rc;
1271 : }
1272 :
1273 420 : _dif_sgl_advance(src_sgl, ctx->block_size);
1274 420 : _dif_sgl_advance(dst_sgl, data_block_size);
1275 420 : offset_blocks++;
1276 : }
1277 :
1278 24 : return 0;
1279 : }
1280 :
1281 : static int
1282 63 : _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 63 : uint32_t offset_in_block, dst_len, data_block_size;
1287 63 : uint8_t *src, *dst;
1288 63 : uint64_t guard = 0;
1289 :
1290 63 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1291 :
1292 63 : data_block_size = ctx->block_size - ctx->md_size;
1293 :
1294 63 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1295 63 : guard = ctx->guard_seed;
1296 : }
1297 63 : offset_in_block = 0;
1298 :
1299 192 : while (offset_in_block < data_block_size) {
1300 : /* Compute CRC over split logical block data and copy
1301 : * data to bounce buffer.
1302 : */
1303 129 : _dif_sgl_get_buf(dst_sgl, &dst, &dst_len);
1304 129 : dst_len = spdk_min(dst_len, data_block_size - offset_in_block);
1305 :
1306 129 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1307 129 : guard = _dif_generate_guard_copy(guard, dst, src + offset_in_block,
1308 129 : dst_len, ctx->dif_pi_format);
1309 : } else {
1310 0 : memcpy(dst, src + offset_in_block, dst_len);
1311 : }
1312 :
1313 129 : _dif_sgl_advance(dst_sgl, dst_len);
1314 129 : offset_in_block += dst_len;
1315 : }
1316 :
1317 63 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1318 63 : guard = _dif_generate_guard(guard, src + data_block_size,
1319 63 : ctx->guard_interval - data_block_size, ctx->dif_pi_format);
1320 : }
1321 :
1322 63 : _dif_sgl_advance(src_sgl, ctx->block_size);
1323 :
1324 63 : return _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
1325 : }
1326 :
1327 : static int
1328 30 : 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 69 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1336 63 : rc = _dif_verify_copy_split(src_sgl, dst_sgl, offset_blocks, ctx, err_blk);
1337 63 : if (rc != 0) {
1338 24 : return rc;
1339 : }
1340 : }
1341 :
1342 6 : return 0;
1343 : }
1344 :
1345 : int
1346 78 : 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 78 : struct _dif_sgl src_sgl, dst_sgl;
1352 : uint32_t data_block_size;
1353 :
1354 78 : _dif_sgl_init(&src_sgl, bounce_iovs, bounce_iovcnt);
1355 78 : _dif_sgl_init(&dst_sgl, iovs, iovcnt);
1356 :
1357 78 : data_block_size = ctx->block_size - ctx->md_size;
1358 :
1359 78 : 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 78 : 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 78 : if (_dif_is_disabled(ctx->dif_type)) {
1370 0 : return 0;
1371 : }
1372 :
1373 78 : if (_dif_sgl_is_bytes_multiple(&dst_sgl, data_block_size)) {
1374 48 : return dif_verify_copy(&src_sgl, &dst_sgl, num_blocks, ctx, err_blk);
1375 : } else {
1376 30 : return dif_verify_copy_split(&src_sgl, &dst_sgl, num_blocks, ctx, err_blk);
1377 : }
1378 : }
1379 :
1380 : static void
1381 240 : _bit_flip(uint8_t *buf, uint32_t flip_bit)
1382 : {
1383 : uint8_t byte;
1384 :
1385 240 : byte = *buf;
1386 240 : byte ^= 1 << flip_bit;
1387 240 : *buf = byte;
1388 240 : }
1389 :
1390 : static int
1391 240 : _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 240 : uint32_t offset_in_block, buf_len;
1398 240 : uint8_t *buf;
1399 :
1400 240 : _dif_sgl_advance(sgl, block_size * inject_offset_blocks);
1401 :
1402 240 : offset_in_block = 0;
1403 :
1404 322 : while (offset_in_block < block_size) {
1405 322 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
1406 322 : buf_len = spdk_min(buf_len, block_size - offset_in_block);
1407 :
1408 322 : if (inject_offset_bytes >= offset_in_block &&
1409 322 : inject_offset_bytes < offset_in_block + buf_len) {
1410 240 : buf += inject_offset_bytes - offset_in_block;
1411 240 : _bit_flip(buf, inject_offset_bits);
1412 240 : return 0;
1413 : }
1414 :
1415 82 : _dif_sgl_advance(sgl, buf_len);
1416 82 : offset_in_block += buf_len;
1417 : }
1418 :
1419 0 : return -1;
1420 : }
1421 :
1422 : static int
1423 240 : 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 240 : srand(time(0));
1432 :
1433 240 : inject_offset_blocks = rand() % num_blocks;
1434 240 : inject_offset_bytes = start_inject_bytes + (rand() % inject_range_bytes);
1435 240 : inject_offset_bits = rand() % 8;
1436 :
1437 936 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1438 936 : if (offset_blocks == inject_offset_blocks) {
1439 240 : rc = _dif_inject_error(sgl, block_size, num_blocks,
1440 : inject_offset_blocks,
1441 : inject_offset_bytes,
1442 : inject_offset_bits);
1443 240 : if (rc == 0) {
1444 240 : *inject_offset = inject_offset_blocks;
1445 : }
1446 240 : return rc;
1447 : }
1448 : }
1449 :
1450 0 : return -1;
1451 : }
1452 :
1453 : int
1454 192 : 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 192 : struct _dif_sgl sgl;
1459 : int rc;
1460 :
1461 192 : _dif_sgl_init(&sgl, iovs, iovcnt);
1462 :
1463 192 : 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 192 : if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
1469 96 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1470 48 : ctx->guard_interval + _dif_reftag_offset(ctx->dif_pi_format),
1471 48 : _dif_reftag_size(ctx->dif_pi_format),
1472 : inject_offset);
1473 48 : if (rc != 0) {
1474 0 : SPDK_ERRLOG("Failed to inject error to Reference Tag.\n");
1475 0 : return rc;
1476 : }
1477 : }
1478 :
1479 192 : if (inject_flags & SPDK_DIF_APPTAG_ERROR) {
1480 96 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1481 48 : ctx->guard_interval + _dif_apptag_offset(ctx->dif_pi_format),
1482 48 : _dif_apptag_size(),
1483 : inject_offset);
1484 48 : if (rc != 0) {
1485 0 : SPDK_ERRLOG("Failed to inject error to Application Tag.\n");
1486 0 : return rc;
1487 : }
1488 : }
1489 192 : if (inject_flags & SPDK_DIF_GUARD_ERROR) {
1490 48 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1491 48 : ctx->guard_interval,
1492 48 : _dif_guard_size(ctx->dif_pi_format),
1493 : inject_offset);
1494 48 : if (rc != 0) {
1495 0 : SPDK_ERRLOG("Failed to inject error to Guard.\n");
1496 0 : return rc;
1497 : }
1498 : }
1499 :
1500 192 : 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 48 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1510 : 0,
1511 48 : ctx->block_size - ctx->md_size,
1512 : inject_offset);
1513 48 : if (rc != 0) {
1514 0 : SPDK_ERRLOG("Failed to inject error to data block.\n");
1515 0 : return rc;
1516 : }
1517 : }
1518 :
1519 192 : return 0;
1520 : }
1521 :
1522 : static void
1523 59 : 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 59 : uint32_t offset_blocks = 0;
1527 59 : uint8_t *data_buf, *md_buf;
1528 : uint64_t guard;
1529 :
1530 787 : while (offset_blocks < num_blocks) {
1531 728 : _dif_sgl_get_buf(data_sgl, &data_buf, NULL);
1532 728 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1533 :
1534 728 : guard = 0;
1535 728 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1536 614 : guard = _dif_generate_guard(ctx->guard_seed, data_buf, ctx->block_size,
1537 614 : ctx->dif_pi_format);
1538 614 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1539 614 : ctx->dif_pi_format);
1540 : }
1541 :
1542 728 : _dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx);
1543 :
1544 728 : _dif_sgl_advance(data_sgl, ctx->block_size);
1545 728 : _dif_sgl_advance(md_sgl, ctx->md_size);
1546 728 : offset_blocks++;
1547 : }
1548 59 : }
1549 :
1550 : static void
1551 75 : _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 75 : uint32_t offset_in_block, data_buf_len;
1555 75 : uint8_t *data_buf, *md_buf;
1556 75 : uint64_t guard = 0;
1557 :
1558 75 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1559 :
1560 75 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1561 75 : guard = ctx->guard_seed;
1562 : }
1563 75 : offset_in_block = 0;
1564 :
1565 231 : while (offset_in_block < ctx->block_size) {
1566 156 : _dif_sgl_get_buf(data_sgl, &data_buf, &data_buf_len);
1567 156 : data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block);
1568 :
1569 156 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1570 156 : guard = _dif_generate_guard(guard, data_buf, data_buf_len,
1571 156 : ctx->dif_pi_format);
1572 : }
1573 :
1574 156 : _dif_sgl_advance(data_sgl, data_buf_len);
1575 156 : offset_in_block += data_buf_len;
1576 : }
1577 :
1578 75 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1579 75 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1580 75 : ctx->dif_pi_format);
1581 : }
1582 :
1583 75 : _dif_sgl_advance(md_sgl, ctx->md_size);
1584 :
1585 75 : _dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx);
1586 75 : }
1587 :
1588 : static void
1589 33 : 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 108 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1595 75 : _dix_generate_split(data_sgl, md_sgl, offset_blocks, ctx);
1596 : }
1597 33 : }
1598 :
1599 : int
1600 92 : 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 92 : struct _dif_sgl data_sgl, md_sgl;
1604 :
1605 92 : _dif_sgl_init(&data_sgl, iovs, iovcnt);
1606 92 : _dif_sgl_init(&md_sgl, md_iov, 1);
1607 :
1608 92 : if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) ||
1609 92 : !_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 92 : if (_dif_is_disabled(ctx->dif_type)) {
1615 0 : return 0;
1616 : }
1617 :
1618 92 : if (_dif_sgl_is_bytes_multiple(&data_sgl, ctx->block_size)) {
1619 59 : dix_generate(&data_sgl, &md_sgl, num_blocks, ctx);
1620 : } else {
1621 33 : dix_generate_split(&data_sgl, &md_sgl, num_blocks, ctx);
1622 : }
1623 :
1624 92 : return 0;
1625 : }
1626 :
1627 : static int
1628 64 : 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 64 : uint32_t offset_blocks = 0;
1633 64 : uint8_t *data_buf, *md_buf;
1634 : uint64_t guard;
1635 : int rc;
1636 :
1637 992 : while (offset_blocks < num_blocks) {
1638 952 : _dif_sgl_get_buf(data_sgl, &data_buf, NULL);
1639 952 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1640 :
1641 952 : guard = 0;
1642 952 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1643 838 : guard = _dif_generate_guard(ctx->guard_seed, data_buf, ctx->block_size,
1644 838 : ctx->dif_pi_format);
1645 838 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1646 838 : ctx->dif_pi_format);
1647 : }
1648 :
1649 952 : rc = _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
1650 952 : if (rc != 0) {
1651 24 : return rc;
1652 : }
1653 :
1654 928 : _dif_sgl_advance(data_sgl, ctx->block_size);
1655 928 : _dif_sgl_advance(md_sgl, ctx->md_size);
1656 928 : offset_blocks++;
1657 : }
1658 :
1659 40 : return 0;
1660 : }
1661 :
1662 : static int
1663 75 : _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 75 : uint32_t offset_in_block, data_buf_len;
1668 75 : uint8_t *data_buf, *md_buf;
1669 75 : uint64_t guard = 0;
1670 :
1671 75 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1672 :
1673 75 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1674 75 : guard = ctx->guard_seed;
1675 : }
1676 75 : offset_in_block = 0;
1677 :
1678 231 : while (offset_in_block < ctx->block_size) {
1679 156 : _dif_sgl_get_buf(data_sgl, &data_buf, &data_buf_len);
1680 156 : data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block);
1681 :
1682 156 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1683 156 : guard = _dif_generate_guard(guard, data_buf, data_buf_len,
1684 156 : ctx->dif_pi_format);
1685 : }
1686 :
1687 156 : _dif_sgl_advance(data_sgl, data_buf_len);
1688 156 : offset_in_block += data_buf_len;
1689 : }
1690 :
1691 75 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1692 75 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1693 75 : ctx->dif_pi_format);
1694 : }
1695 :
1696 75 : _dif_sgl_advance(md_sgl, ctx->md_size);
1697 :
1698 75 : return _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
1699 : }
1700 :
1701 : static int
1702 33 : 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 84 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1710 75 : rc = _dix_verify_split(data_sgl, md_sgl, offset_blocks, ctx, err_blk);
1711 75 : if (rc != 0) {
1712 24 : return rc;
1713 : }
1714 : }
1715 :
1716 9 : return 0;
1717 : }
1718 :
1719 : int
1720 97 : 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 97 : struct _dif_sgl data_sgl, md_sgl;
1725 :
1726 97 : if (md_iov->iov_base == NULL) {
1727 0 : SPDK_ERRLOG("Metadata buffer is NULL.\n");
1728 0 : return -EINVAL;
1729 : }
1730 :
1731 97 : _dif_sgl_init(&data_sgl, iovs, iovcnt);
1732 97 : _dif_sgl_init(&md_sgl, md_iov, 1);
1733 :
1734 97 : if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) ||
1735 97 : !_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 97 : if (_dif_is_disabled(ctx->dif_type)) {
1741 0 : return 0;
1742 : }
1743 :
1744 97 : if (_dif_sgl_is_bytes_multiple(&data_sgl, ctx->block_size)) {
1745 64 : return dix_verify(&data_sgl, &md_sgl, num_blocks, ctx, err_blk);
1746 : } else {
1747 33 : return dix_verify_split(&data_sgl, &md_sgl, num_blocks, ctx, err_blk);
1748 : }
1749 : }
1750 :
1751 : int
1752 48 : 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 48 : struct _dif_sgl data_sgl, md_sgl;
1757 : int rc;
1758 :
1759 48 : _dif_sgl_init(&data_sgl, iovs, iovcnt);
1760 48 : _dif_sgl_init(&md_sgl, md_iov, 1);
1761 :
1762 48 : if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) ||
1763 48 : !_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 48 : if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
1769 24 : rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks,
1770 12 : ctx->guard_interval + _dif_reftag_offset(ctx->dif_pi_format),
1771 12 : _dif_reftag_size(ctx->dif_pi_format),
1772 : inject_offset);
1773 12 : if (rc != 0) {
1774 0 : SPDK_ERRLOG("Failed to inject error to Reference Tag.\n");
1775 0 : return rc;
1776 : }
1777 : }
1778 :
1779 48 : if (inject_flags & SPDK_DIF_APPTAG_ERROR) {
1780 24 : rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks,
1781 12 : ctx->guard_interval + _dif_apptag_offset(ctx->dif_pi_format),
1782 12 : _dif_apptag_size(),
1783 : inject_offset);
1784 12 : if (rc != 0) {
1785 0 : SPDK_ERRLOG("Failed to inject error to Application Tag.\n");
1786 0 : return rc;
1787 : }
1788 : }
1789 :
1790 48 : if (inject_flags & SPDK_DIF_GUARD_ERROR) {
1791 12 : rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks,
1792 12 : ctx->guard_interval,
1793 12 : _dif_guard_size(ctx->dif_pi_format),
1794 : inject_offset);
1795 12 : if (rc != 0) {
1796 0 : SPDK_ERRLOG("Failed to inject error to Guard.\n");
1797 0 : return rc;
1798 : }
1799 : }
1800 :
1801 48 : 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 12 : rc = dif_inject_error(&data_sgl, ctx->block_size, num_blocks,
1806 : 0,
1807 12 : ctx->block_size,
1808 : inject_offset);
1809 12 : if (rc != 0) {
1810 0 : SPDK_ERRLOG("Failed to inject error to Guard.\n");
1811 0 : return rc;
1812 : }
1813 : }
1814 :
1815 48 : return 0;
1816 : }
1817 :
1818 : static uint32_t
1819 369 : _to_next_boundary(uint32_t offset, uint32_t boundary)
1820 : {
1821 369 : return boundary - (offset % boundary);
1822 : }
1823 :
1824 : static uint32_t
1825 237 : _to_size_with_md(uint32_t size, uint32_t data_block_size, uint32_t block_size)
1826 : {
1827 237 : return (size / data_block_size) * block_size + (size % data_block_size);
1828 : }
1829 :
1830 : int
1831 38 : 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 38 : struct _dif_sgl dif_sgl;
1839 38 : struct _dif_sgl buf_sgl;
1840 :
1841 38 : if (iovs == NULL || iovcnt == 0 || buf_iovs == NULL || buf_iovcnt == 0) {
1842 0 : return -EINVAL;
1843 : }
1844 :
1845 38 : data_block_size = ctx->block_size - ctx->md_size;
1846 :
1847 38 : data_unalign = ctx->data_offset % data_block_size;
1848 :
1849 38 : buf_len = _to_size_with_md(data_unalign + data_offset + data_len, data_block_size,
1850 38 : ctx->block_size);
1851 38 : buf_len -= data_unalign;
1852 :
1853 38 : _dif_sgl_init(&dif_sgl, iovs, iovcnt);
1854 38 : _dif_sgl_init(&buf_sgl, buf_iovs, buf_iovcnt);
1855 :
1856 38 : if (!_dif_sgl_is_valid(&buf_sgl, buf_len)) {
1857 1 : SPDK_ERRLOG("Buffer overflow will occur.\n");
1858 1 : return -ERANGE;
1859 : }
1860 :
1861 37 : buf_offset = _to_size_with_md(data_unalign + data_offset, data_block_size, ctx->block_size);
1862 37 : buf_offset -= data_unalign;
1863 :
1864 37 : _dif_sgl_advance(&buf_sgl, buf_offset);
1865 :
1866 121 : while (data_len != 0) {
1867 104 : len = spdk_min(data_len, _to_next_boundary(ctx->data_offset + data_offset, data_block_size));
1868 104 : if (!_dif_sgl_append_split(&dif_sgl, &buf_sgl, len)) {
1869 20 : break;
1870 : }
1871 84 : _dif_sgl_advance(&buf_sgl, ctx->md_size);
1872 84 : data_offset += len;
1873 84 : data_len -= len;
1874 : }
1875 :
1876 37 : if (_mapped_len != NULL) {
1877 37 : *_mapped_len = dif_sgl.total_size;
1878 : }
1879 :
1880 37 : return iovcnt - dif_sgl.iovcnt;
1881 : }
1882 :
1883 : static int
1884 67 : _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 67 : data_block_size = ctx->block_size - ctx->md_size;
1891 :
1892 67 : 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 67 : buf_len = _to_size_with_md(data_unalign + data_offset + data_len, data_block_size,
1898 67 : ctx->block_size);
1899 67 : buf_len -= data_unalign;
1900 :
1901 67 : if (!_dif_sgl_is_valid(sgl, buf_len)) {
1902 3 : return -ERANGE;
1903 : }
1904 :
1905 64 : buf_offset = _to_size_with_md(data_unalign + data_offset, data_block_size, ctx->block_size);
1906 64 : buf_offset -= data_unalign;
1907 :
1908 64 : _dif_sgl_advance(sgl, buf_offset);
1909 64 : buf_len -= buf_offset;
1910 :
1911 64 : buf_offset += data_unalign;
1912 :
1913 64 : *_buf_offset = buf_offset;
1914 64 : *_buf_len = buf_len;
1915 :
1916 64 : return 0;
1917 : }
1918 :
1919 : int
1920 49 : 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 49 : uint32_t buf_len = 0, buf_offset = 0;
1925 : uint32_t len, offset_in_block, offset_blocks;
1926 49 : uint64_t guard = 0;
1927 49 : struct _dif_sgl sgl;
1928 : int rc;
1929 :
1930 49 : if (iovs == NULL || iovcnt == 0) {
1931 0 : return -EINVAL;
1932 : }
1933 :
1934 49 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1935 49 : guard = ctx->last_guard;
1936 : }
1937 :
1938 49 : _dif_sgl_init(&sgl, iovs, iovcnt);
1939 :
1940 49 : rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx);
1941 49 : if (rc != 0) {
1942 3 : return rc;
1943 : }
1944 :
1945 122 : while (buf_len != 0) {
1946 76 : len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size));
1947 76 : offset_in_block = buf_offset % ctx->block_size;
1948 76 : offset_blocks = buf_offset / ctx->block_size;
1949 :
1950 76 : guard = _dif_generate_split(&sgl, offset_in_block, len, guard, offset_blocks, ctx);
1951 :
1952 76 : buf_len -= len;
1953 76 : buf_offset += len;
1954 : }
1955 :
1956 46 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1957 46 : ctx->last_guard = guard;
1958 : }
1959 :
1960 46 : return 0;
1961 : }
1962 :
1963 : int
1964 9 : 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 9 : uint32_t buf_len = 0, buf_offset = 0;
1970 : uint32_t len, offset_in_block, offset_blocks;
1971 9 : uint64_t guard = 0;
1972 9 : struct _dif_sgl sgl;
1973 9 : int rc = 0;
1974 :
1975 9 : if (iovs == NULL || iovcnt == 0) {
1976 0 : return -EINVAL;
1977 : }
1978 :
1979 9 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
1980 9 : guard = ctx->last_guard;
1981 : }
1982 :
1983 9 : _dif_sgl_init(&sgl, iovs, iovcnt);
1984 :
1985 9 : rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx);
1986 9 : if (rc != 0) {
1987 0 : return rc;
1988 : }
1989 :
1990 27 : while (buf_len != 0) {
1991 18 : len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size));
1992 18 : offset_in_block = buf_offset % ctx->block_size;
1993 18 : offset_blocks = buf_offset / ctx->block_size;
1994 :
1995 18 : rc = _dif_verify_split(&sgl, offset_in_block, len, &guard, offset_blocks,
1996 : ctx, err_blk);
1997 18 : if (rc != 0) {
1998 0 : goto error;
1999 : }
2000 :
2001 18 : buf_len -= len;
2002 18 : buf_offset += len;
2003 : }
2004 :
2005 9 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
2006 9 : ctx->last_guard = guard;
2007 : }
2008 9 : error:
2009 9 : return rc;
2010 : }
2011 :
2012 : int
2013 9 : 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 9 : uint32_t buf_len = 0, buf_offset = 0, len, offset_in_block;
2018 : uint32_t crc32c;
2019 9 : struct _dif_sgl sgl;
2020 : int rc;
2021 :
2022 9 : if (iovs == NULL || iovcnt == 0) {
2023 0 : return -EINVAL;
2024 : }
2025 :
2026 9 : crc32c = *_crc32c;
2027 9 : _dif_sgl_init(&sgl, iovs, iovcnt);
2028 :
2029 9 : rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx);
2030 9 : if (rc != 0) {
2031 0 : return rc;
2032 : }
2033 :
2034 27 : while (buf_len != 0) {
2035 18 : len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size));
2036 18 : offset_in_block = buf_offset % ctx->block_size;
2037 :
2038 18 : crc32c = _dif_update_crc32c_split(&sgl, offset_in_block, len, crc32c, ctx);
2039 :
2040 18 : buf_len -= len;
2041 18 : buf_offset += len;
2042 : }
2043 :
2044 9 : *_crc32c = crc32c;
2045 :
2046 9 : return 0;
2047 : }
2048 :
2049 : void
2050 10 : 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 10 : if (!ctx->md_interleave) {
2057 0 : buf_offset = data_offset;
2058 0 : buf_len = data_len;
2059 : } else {
2060 10 : data_block_size = ctx->block_size - ctx->md_size;
2061 :
2062 10 : data_unalign = data_offset % data_block_size;
2063 :
2064 10 : buf_offset = _to_size_with_md(data_offset, data_block_size, ctx->block_size);
2065 10 : buf_len = _to_size_with_md(data_unalign + data_len, data_block_size, ctx->block_size) -
2066 : data_unalign;
2067 : }
2068 :
2069 10 : if (_buf_offset != NULL) {
2070 10 : *_buf_offset = buf_offset;
2071 : }
2072 :
2073 10 : if (_buf_len != NULL) {
2074 10 : *_buf_len = buf_len;
2075 : }
2076 10 : }
2077 :
2078 : uint32_t
2079 11 : 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 11 : if (!ctx->md_interleave) {
2084 0 : return data_len;
2085 : } else {
2086 11 : data_block_size = ctx->block_size - ctx->md_size;
2087 :
2088 11 : return _to_size_with_md(data_len, data_block_size, ctx->block_size);
2089 : }
2090 : }
2091 :
2092 : static int
2093 72 : _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 72 : uint32_t offset, buf_len;
2098 72 : uint64_t expected = 0, remapped;
2099 72 : uint8_t *buf;
2100 72 : struct _dif_sgl tmp_sgl;
2101 72 : struct spdk_dif dif;
2102 :
2103 : /* Fast forward to DIF field. */
2104 72 : _dif_sgl_advance(sgl, ctx->guard_interval);
2105 72 : _dif_sgl_copy(&tmp_sgl, sgl);
2106 :
2107 : /* Copy the split DIF field to the temporary DIF buffer */
2108 72 : offset = 0;
2109 162 : while (offset < _dif_size(ctx->dif_pi_format)) {
2110 90 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
2111 90 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset);
2112 :
2113 90 : memcpy((uint8_t *)&dif + offset, buf, buf_len);
2114 :
2115 90 : _dif_sgl_advance(sgl, buf_len);
2116 90 : offset += buf_len;
2117 : }
2118 :
2119 72 : 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 72 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
2128 72 : expected = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
2129 72 : 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 72 : 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 72 : _dif_set_reftag(&dif, remapped, ctx->dif_pi_format);
2141 :
2142 72 : offset = 0;
2143 162 : while (offset < _dif_size(ctx->dif_pi_format)) {
2144 90 : _dif_sgl_get_buf(&tmp_sgl, &buf, &buf_len);
2145 90 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset);
2146 :
2147 90 : memcpy(buf, (uint8_t *)&dif + offset, buf_len);
2148 :
2149 90 : _dif_sgl_advance(&tmp_sgl, buf_len);
2150 90 : offset += buf_len;
2151 : }
2152 :
2153 72 : end:
2154 72 : _dif_sgl_advance(sgl, ctx->block_size - ctx->guard_interval - _dif_size(ctx->dif_pi_format));
2155 :
2156 72 : return 0;
2157 : }
2158 :
2159 : int
2160 12 : 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 12 : struct _dif_sgl sgl;
2165 : uint32_t offset_blocks;
2166 : int rc;
2167 :
2168 12 : _dif_sgl_init(&sgl, iovs, iovcnt);
2169 :
2170 12 : 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 12 : if (_dif_is_disabled(ctx->dif_type)) {
2176 0 : return 0;
2177 : }
2178 :
2179 12 : if (!(ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK)) {
2180 0 : return 0;
2181 : }
2182 :
2183 84 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
2184 72 : rc = _dif_remap_ref_tag(&sgl, offset_blocks, ctx, err_blk, check_ref_tag);
2185 72 : if (rc != 0) {
2186 0 : return rc;
2187 : }
2188 : }
2189 :
2190 12 : return 0;
2191 : }
2192 :
2193 : static int
2194 200 : _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 200 : uint64_t expected = 0, remapped;
2199 200 : uint8_t *md_buf;
2200 : struct spdk_dif *dif;
2201 :
2202 200 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
2203 :
2204 200 : dif = (struct spdk_dif *)(md_buf + ctx->guard_interval);
2205 :
2206 200 : 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 200 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
2215 200 : expected = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
2216 200 : 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 200 : 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 200 : _dif_set_reftag(dif, remapped, ctx->dif_pi_format);
2228 :
2229 200 : end:
2230 200 : _dif_sgl_advance(md_sgl, ctx->md_size);
2231 :
2232 200 : return 0;
2233 : }
2234 :
2235 : int
2236 12 : 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 12 : struct _dif_sgl md_sgl;
2242 : uint32_t offset_blocks;
2243 : int rc;
2244 :
2245 12 : _dif_sgl_init(&md_sgl, md_iov, 1);
2246 :
2247 12 : 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 12 : if (_dif_is_disabled(ctx->dif_type)) {
2253 0 : return 0;
2254 : }
2255 :
2256 12 : if (!(ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK)) {
2257 0 : return 0;
2258 : }
2259 :
2260 212 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
2261 200 : rc = _dix_remap_ref_tag(&md_sgl, offset_blocks, ctx, err_blk, check_ref_tag);
2262 200 : if (rc != 0) {
2263 0 : return rc;
2264 : }
2265 : }
2266 :
2267 12 : return 0;
2268 : }
|