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