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 : 13494873 : _dif_sgl_init(struct _dif_sgl *s, struct iovec *iovs, int iovcnt)
65 : : {
66 [ # # # # ]: 13494873 : s->iov = iovs;
67 [ # # # # ]: 13494873 : s->iovcnt = iovcnt;
68 [ # # # # ]: 13494873 : s->iov_offset = 0;
69 [ # # # # ]: 13494873 : s->total_size = 0;
70 : 13494873 : }
71 : :
72 : : static void
73 : 180608580 : _dif_sgl_advance(struct _dif_sgl *s, uint32_t step)
74 : : {
75 [ # # # # ]: 180608580 : s->iov_offset += step;
76 [ + + # # : 191804263 : while (s->iovcnt != 0) {
# # ]
77 [ + + # # : 181740121 : if (s->iov_offset < s->iov->iov_len) {
# # # # #
# # # #
# ]
78 : 170544438 : break;
79 : : }
80 : :
81 [ # # # # : 11195683 : s->iov_offset -= s->iov->iov_len;
# # # # #
# # # ]
82 [ # # # # ]: 11195683 : s->iov++;
83 [ # # # # ]: 11195683 : s->iovcnt--;
84 : : }
85 : 180608580 : }
86 : :
87 : : static inline void
88 : 150199700 : _dif_sgl_get_buf(struct _dif_sgl *s, uint8_t **_buf, uint32_t *_buf_len)
89 : : {
90 [ + + ]: 150199700 : if (_buf != NULL) {
91 [ # # # # : 150232163 : *_buf = (uint8_t *)s->iov->iov_base + s->iov_offset;
# # # # #
# # # # #
# # ]
92 : 11899725 : }
93 [ + + ]: 150264626 : if (_buf_len != NULL) {
94 [ # # # # : 84754785 : *_buf_len = s->iov->iov_len - s->iov_offset;
# # # # #
# # # #
# ]
95 : 10143 : }
96 : 150264626 : }
97 : :
98 : : static inline bool
99 : 28346134 : _dif_sgl_append(struct _dif_sgl *s, uint8_t *data, uint32_t data_len)
100 : : {
101 [ + + # # : 28346134 : assert(s->iovcnt > 0);
# # # # ]
102 [ # # # # : 28346134 : s->iov->iov_base = data;
# # # # ]
103 [ # # # # : 28346134 : s->iov->iov_len = data_len;
# # # # ]
104 [ # # # # ]: 28346134 : s->total_size += data_len;
105 [ # # # # ]: 28346134 : s->iov++;
106 [ # # # # ]: 28346134 : s->iovcnt--;
107 : :
108 [ + + # # : 28346134 : if (s->iovcnt > 0) {
# # ]
109 : 27983852 : return true;
110 : : } else {
111 : 362282 : return false;
112 : : }
113 : 120 : }
114 : :
115 : : static inline bool
116 : 28279436 : _dif_sgl_append_split(struct _dif_sgl *dst, struct _dif_sgl *src, uint32_t data_len)
117 : : {
118 : 312 : uint8_t *buf;
119 : 312 : uint32_t buf_len;
120 : :
121 [ + + ]: 56263288 : while (data_len != 0) {
122 : 28346134 : _dif_sgl_get_buf(src, &buf, &buf_len);
123 [ + + ]: 28346134 : buf_len = spdk_min(buf_len, data_len);
124 : :
125 [ + + ]: 28346134 : if (!_dif_sgl_append(dst, buf, buf_len)) {
126 : 362282 : return false;
127 : : }
128 : :
129 : 27983852 : _dif_sgl_advance(src, buf_len);
130 : 27983852 : data_len -= buf_len;
131 : : }
132 : :
133 : 27917154 : return true;
134 : 104 : }
135 : :
136 : : /* This function must be used before starting iteration. */
137 : : static bool
138 : 8350489 : _dif_sgl_is_bytes_multiple(struct _dif_sgl *s, uint32_t bytes)
139 : : {
140 : : int i;
141 : :
142 [ + + # # : 16663776 : for (i = 0; i < s->iovcnt; i++) {
# # # # ]
143 [ + + + + : 8348367 : if (s->iov[i].iov_len % bytes) {
# # # # #
# # # #
# ]
144 : 35080 : return false;
145 : : }
146 : 1993393 : }
147 : :
148 : 8315409 : return true;
149 : 1999156 : }
150 : :
151 : : /* This function must be used before starting iteration. */
152 : : static bool
153 : 11746219 : _dif_sgl_is_valid(struct _dif_sgl *s, uint32_t bytes)
154 : : {
155 : 11746219 : uint64_t total = 0;
156 : : int i;
157 : :
158 [ + + # # : 23943505 : for (i = 0; i < s->iovcnt; i++) {
# # # # ]
159 [ # # # # : 12197286 : total += s->iov[i].iov_len;
# # # # #
# ]
160 : 2005510 : }
161 : :
162 : 11746219 : return total >= bytes;
163 : : }
164 : :
165 : : static void
166 : 288 : _dif_sgl_copy(struct _dif_sgl *to, struct _dif_sgl *from)
167 : : {
168 [ - + - + ]: 288 : memcpy(to, from, sizeof(struct _dif_sgl));
169 : 288 : }
170 : :
171 : : static bool
172 : 6328836 : _dif_is_disabled(enum spdk_dif_type dif_type)
173 : : {
174 [ + + ]: 6328836 : if (dif_type == SPDK_DIF_DISABLE) {
175 : 179536 : return true;
176 : : } else {
177 : 6149300 : return false;
178 : : }
179 : 1344485 : }
180 : :
181 : : static inline size_t
182 : 78561809 : _dif_size(enum spdk_dif_pi_format dif_pi_format)
183 : : {
184 : : uint8_t size;
185 : :
186 [ + + ]: 78561809 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
187 : 78551405 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g16);
188 [ + + ]: 2705348 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
189 : 5292 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g32);
190 : 1330 : } else {
191 : 5112 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g64);
192 : : }
193 : :
194 : 78561809 : return size;
195 : : }
196 : :
197 : : uint32_t
198 : 0 : spdk_dif_pi_format_get_size(enum spdk_dif_pi_format dif_pi_format)
199 : : {
200 : 0 : return _dif_size(dif_pi_format);
201 : : }
202 : :
203 : : static uint32_t
204 : 5297459 : _get_guard_interval(uint32_t block_size, uint32_t md_size, bool dif_loc, bool md_interleave,
205 : : size_t dif_size)
206 : : {
207 [ + + # # ]: 5297459 : if (!dif_loc) {
208 : : /* For metadata formats with more than 8/16 bytes (depending on
209 : : * the PI format), if the DIF is contained in the last 8/16 bytes
210 : : * of metadata, then the CRC covers all metadata up to but excluding
211 : : * these last 8/16 bytes.
212 : : */
213 [ + + # # ]: 3987079 : if (md_interleave) {
214 : 3807263 : return block_size - dif_size;
215 : : } else {
216 : 179816 : return md_size - dif_size;
217 : : }
218 : : } else {
219 : : /* For metadata formats with more than 8/16 bytes (depending on
220 : : * the PI format), if the DIF is contained in the first 8/16 bytes
221 : : * of metadata, then the CRC does not cover any metadata.
222 : : */
223 [ + + # # ]: 1310380 : if (md_interleave) {
224 : 1310018 : return block_size - md_size;
225 : : } else {
226 : 362 : return 0;
227 : : }
228 : : }
229 : 1372851 : }
230 : :
231 : : static inline uint8_t
232 : 720 : _dif_guard_size(enum spdk_dif_pi_format dif_pi_format)
233 : : {
234 : : uint8_t size;
235 : :
236 [ + + ]: 720 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
237 : 240 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g16.guard);
238 [ + + ]: 540 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
239 : 240 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g32.guard);
240 : 60 : } else {
241 : 240 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g64.guard);
242 : : }
243 : :
244 : 720 : return size;
245 : : }
246 : :
247 : : static inline void
248 : 30671448 : _dif_set_guard(struct spdk_dif *dif, uint64_t guard, enum spdk_dif_pi_format dif_pi_format)
249 : : {
250 [ + + ]: 30671448 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
251 [ # # # # : 30665792 : to_be16(&(dif->g16.guard), (uint16_t)guard);
# # ]
252 [ + + ]: 2713127 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
253 [ # # # # : 2872 : to_be32(&(dif->g32.guard), (uint32_t)guard);
# # ]
254 : 718 : } else {
255 [ # # # # : 2784 : to_be64(&(dif->g64.guard), guard);
# # ]
256 : : }
257 : 30671448 : }
258 : :
259 : : static inline uint64_t
260 : 40745014 : _dif_get_guard(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
261 : : {
262 : : uint64_t guard;
263 : :
264 [ + + ]: 40745014 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
265 [ # # # # : 40741178 : guard = (uint64_t)from_be16(&(dif->g16.guard));
# # ]
266 [ + + ]: 6842228 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
267 [ # # # # : 1916 : guard = (uint64_t)from_be32(&(dif->g32.guard));
# # ]
268 : 537 : } else {
269 [ # # # # : 1920 : guard = from_be64(&(dif->g64.guard));
# # ]
270 : : }
271 : :
272 : 40745014 : return guard;
273 : : }
274 : :
275 : : static inline uint64_t
276 : 72874121 : _dif_generate_guard(uint64_t guard_seed, void *buf, size_t buf_len,
277 : : enum spdk_dif_pi_format dif_pi_format)
278 : : {
279 : : uint64_t guard;
280 : :
281 [ + + ]: 72874121 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
282 : 72862733 : guard = (uint64_t)spdk_crc16_t10dif((uint16_t)guard_seed, buf, buf_len);
283 [ + + ]: 8933904 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
284 : 5752 : guard = (uint64_t)spdk_crc32c_nvme(buf, buf_len, guard_seed);
285 : 1517 : } else {
286 : 5636 : guard = spdk_crc64_nvme(buf, buf_len, guard_seed);
287 : : }
288 : :
289 : 72874121 : return guard;
290 : : }
291 : :
292 : : static uint64_t
293 : 22671051 : dif_generate_guard_split(uint64_t guard_seed, struct _dif_sgl *sgl, uint32_t start,
294 : : uint32_t len, const struct spdk_dif_ctx *ctx)
295 : : {
296 : 22671051 : uint64_t guard = guard_seed;
297 : 1752 : uint32_t offset, end, buf_len;
298 : 1752 : uint8_t *buf;
299 : :
300 : 22671051 : offset = start;
301 [ + + # # : 22671051 : end = start + spdk_min(len, ctx->guard_interval - start);
# # # # #
# ]
302 : :
303 [ + + ]: 45409803 : while (offset < end) {
304 : 22738752 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
305 [ + + ]: 22738752 : buf_len = spdk_min(buf_len, end - offset);
306 : :
307 [ + + # # : 22738752 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
308 [ # # # # ]: 22738752 : guard = _dif_generate_guard(guard, buf, buf_len, ctx->dif_pi_format);
309 : 855 : }
310 : :
311 : 22738752 : _dif_sgl_advance(sgl, buf_len);
312 : 22738752 : offset += buf_len;
313 : : }
314 : :
315 : 22671051 : return guard;
316 : : }
317 : :
318 : : static inline uint64_t
319 : 17224778 : _dif_generate_guard_copy(uint64_t guard_seed, void *dst, void *src, size_t buf_len,
320 : : enum spdk_dif_pi_format dif_pi_format)
321 : : {
322 : : uint64_t guard;
323 : :
324 [ + + ]: 17224778 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
325 : 17222138 : guard = (uint64_t)spdk_crc16_t10dif_copy((uint16_t)guard_seed, dst, src, buf_len);
326 [ + + ]: 4855225 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
327 [ - + - + ]: 1320 : memcpy(dst, src, buf_len);
328 : 1320 : guard = (uint64_t)spdk_crc32c_nvme(src, buf_len, guard_seed);
329 : 352 : } else {
330 [ - + - + ]: 1320 : memcpy(dst, src, buf_len);
331 : 1320 : guard = spdk_crc64_nvme(src, buf_len, guard_seed);
332 : : }
333 : :
334 : 17224778 : return guard;
335 : : }
336 : :
337 : : static uint64_t
338 : 576 : _dif_generate_guard_copy_split(uint64_t guard, struct _dif_sgl *dst_sgl,
339 : : struct _dif_sgl *src_sgl, uint32_t data_len,
340 : : enum spdk_dif_pi_format dif_pi_format)
341 : : {
342 : 576 : uint32_t offset = 0, src_len, dst_len, buf_len;
343 : 426 : uint8_t *src, *dst;
344 : :
345 [ + + ]: 1736 : while (offset < data_len) {
346 : 1160 : _dif_sgl_get_buf(src_sgl, &src, &src_len);
347 : 1160 : _dif_sgl_get_buf(dst_sgl, &dst, &dst_len);
348 [ + + ]: 1160 : buf_len = spdk_min(src_len, dst_len);
349 [ + + ]: 1160 : buf_len = spdk_min(buf_len, data_len - offset);
350 : :
351 : 1160 : guard = _dif_generate_guard_copy(guard, dst, src, buf_len, dif_pi_format);
352 : :
353 : 1160 : _dif_sgl_advance(src_sgl, buf_len);
354 : 1160 : _dif_sgl_advance(dst_sgl, buf_len);
355 : 1160 : offset += buf_len;
356 : : }
357 : :
358 : 576 : return guard;
359 : : }
360 : :
361 : : static void
362 : 0 : _data_copy_split(struct _dif_sgl *dst_sgl, struct _dif_sgl *src_sgl, uint32_t data_len)
363 : : {
364 : 0 : uint32_t offset = 0, src_len, dst_len, buf_len;
365 : 0 : uint8_t *src, *dst;
366 : :
367 [ # # ]: 0 : while (offset < data_len) {
368 : 0 : _dif_sgl_get_buf(src_sgl, &src, &src_len);
369 : 0 : _dif_sgl_get_buf(dst_sgl, &dst, &dst_len);
370 [ # # ]: 0 : buf_len = spdk_min(src_len, dst_len);
371 [ # # ]: 0 : buf_len = spdk_min(buf_len, data_len - offset);
372 : :
373 [ # # # # ]: 0 : memcpy(dst, src, buf_len);
374 : :
375 : 0 : _dif_sgl_advance(src_sgl, buf_len);
376 : 0 : _dif_sgl_advance(dst_sgl, buf_len);
377 : 0 : offset += buf_len;
378 : : }
379 : 0 : }
380 : :
381 : : static inline uint8_t
382 : 480 : _dif_apptag_offset(enum spdk_dif_pi_format dif_pi_format)
383 : : {
384 : 480 : return _dif_guard_size(dif_pi_format);
385 : : }
386 : :
387 : : static inline uint8_t
388 : 480 : _dif_apptag_size(void)
389 : : {
390 : 480 : return SPDK_SIZEOF_MEMBER(struct spdk_dif, g16.app_tag);
391 : : }
392 : :
393 : : static inline void
394 : 30586184 : _dif_set_apptag(struct spdk_dif *dif, uint16_t app_tag, enum spdk_dif_pi_format dif_pi_format)
395 : : {
396 [ + + ]: 30586184 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
397 [ # # # # : 30580528 : to_be16(&(dif->g16.app_tag), app_tag);
# # ]
398 [ + + ]: 2627863 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
399 [ # # # # : 2872 : to_be16(&(dif->g32.app_tag), app_tag);
# # ]
400 : 718 : } else {
401 [ # # # # : 2784 : to_be16(&(dif->g64.app_tag), app_tag);
# # ]
402 : : }
403 : 30586184 : }
404 : :
405 : : static inline uint16_t
406 : 45610102 : _dif_get_apptag(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
407 : : {
408 : : uint16_t app_tag;
409 : :
410 [ + + ]: 45610102 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
411 [ # # # # : 45601122 : app_tag = from_be16(&(dif->g16.app_tag));
# # ]
412 [ + + ]: 7078258 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
413 [ # # # # : 4492 : app_tag = from_be16(&(dif->g32.app_tag));
# # ]
414 : 1239 : } else {
415 [ # # # # : 4488 : app_tag = from_be16(&(dif->g64.app_tag));
# # ]
416 : : }
417 : :
418 : 45610102 : return app_tag;
419 : : }
420 : :
421 : : static inline bool
422 : 40826251 : _dif_apptag_ignore(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
423 : : {
424 : 40826251 : return _dif_get_apptag(dif, dif_pi_format) == SPDK_DIF_APPTAG_IGNORE;
425 : : }
426 : :
427 : : static inline uint8_t
428 : 240 : _dif_reftag_offset(enum spdk_dif_pi_format dif_pi_format)
429 : : {
430 : : uint8_t offset;
431 : :
432 [ + + ]: 240 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
433 : 80 : offset = _dif_apptag_offset(dif_pi_format) + _dif_apptag_size();
434 [ + + ]: 180 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
435 : 100 : offset = _dif_apptag_offset(dif_pi_format) + _dif_apptag_size()
436 : 20 : + SPDK_SIZEOF_MEMBER(struct spdk_dif, g32.stor_ref_space_p1);
437 : 20 : } else {
438 : 80 : offset = _dif_apptag_offset(dif_pi_format) + _dif_apptag_size();
439 : : }
440 : :
441 : 240 : return offset;
442 : : }
443 : :
444 : : static inline uint8_t
445 : 240 : _dif_reftag_size(enum spdk_dif_pi_format dif_pi_format)
446 : : {
447 : : uint8_t size;
448 : :
449 [ + + ]: 240 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
450 : 80 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g16.stor_ref_space);
451 [ + + ]: 180 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
452 : 80 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g32.stor_ref_space_p2);
453 : 20 : } else {
454 : 80 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g64.stor_ref_space_p1) +
455 : : SPDK_SIZEOF_MEMBER(struct spdk_dif, g64.stor_ref_space_p2);
456 : : }
457 : :
458 : 240 : return size;
459 : : }
460 : :
461 : : static inline void
462 : 30546984 : _dif_set_reftag(struct spdk_dif *dif, uint64_t ref_tag, enum spdk_dif_pi_format dif_pi_format)
463 : : {
464 [ + + ]: 30546984 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
465 [ # # # # : 30540944 : to_be32(&(dif->g16.stor_ref_space), (uint32_t)ref_tag);
# # ]
466 [ + + ]: 2588135 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
467 [ # # # # : 3064 : to_be64(&(dif->g32.stor_ref_space_p2), ref_tag);
# # ]
468 : 766 : } else {
469 [ # # # # : 2976 : to_be16(&(dif->g64.stor_ref_space_p1), (uint16_t)(ref_tag >> 32));
# # # # ]
470 [ # # # # : 2976 : to_be32(&(dif->g64.stor_ref_space_p2), (uint32_t)ref_tag);
# # ]
471 : : }
472 : 30546984 : }
473 : :
474 : : static inline uint64_t
475 : 31656354 : _dif_get_reftag(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
476 : : {
477 : : uint64_t ref_tag;
478 : :
479 [ + + ]: 31656354 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
480 [ # # # # : 31652506 : ref_tag = (uint64_t)from_be32(&(dif->g16.stor_ref_space));
# # ]
481 [ + + ]: 6283020 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
482 [ # # # # : 1924 : ref_tag = from_be64(&(dif->g32.stor_ref_space_p2));
# # ]
483 : 539 : } else {
484 [ # # # # : 1924 : ref_tag = (uint64_t)from_be16(&(dif->g64.stor_ref_space_p1));
# # ]
485 [ # # ]: 1924 : ref_tag <<= 32;
486 [ # # # # : 1924 : ref_tag |= (uint64_t)from_be32(&(dif->g64.stor_ref_space_p2));
# # ]
487 : : }
488 : :
489 : 31656354 : return ref_tag;
490 : : }
491 : :
492 : : static inline bool
493 : 31866950 : _dif_reftag_match(struct spdk_dif *dif, uint64_t ref_tag,
494 : : enum spdk_dif_pi_format dif_pi_format)
495 : : {
496 : : uint64_t _ref_tag;
497 : : bool match;
498 : :
499 : 31866950 : _ref_tag = _dif_get_reftag(dif, dif_pi_format);
500 : :
501 [ + + ]: 31866950 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
502 : 31863278 : match = (_ref_tag == (ref_tag & REFTAG_MASK_16));
503 [ + + ]: 6493706 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
504 : 1836 : match = (_ref_tag == ref_tag);
505 : 517 : } else {
506 : 1836 : match = (_ref_tag == (ref_tag & REFTAG_MASK_64));
507 : : }
508 : :
509 [ # # ]: 31866950 : return match;
510 : : }
511 : :
512 : : static inline bool
513 : 28 : _dif_reftag_ignore(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
514 : : {
515 : 28 : return _dif_reftag_match(dif, REFTAG_MASK_32, dif_pi_format);
516 : : }
517 : :
518 : : static bool
519 : 40754425 : _dif_ignore(struct spdk_dif *dif, const struct spdk_dif_ctx *ctx)
520 : : {
521 [ + + + # : 40754425 : switch (ctx->dif_type) {
# # # ]
522 : 25428077 : case SPDK_DIF_TYPE1:
523 : : case SPDK_DIF_TYPE2:
524 : : /* If Type 1 or 2 is used, then all DIF checks are disabled when
525 : : * the Application Tag is 0xFFFF.
526 : : */
527 [ + + # # : 32224807 : if (_dif_apptag_ignore(dif, ctx->dif_pi_format)) {
# # ]
528 : 59699 : return true;
529 : : }
530 : 32165108 : break;
531 : 8529611 : case SPDK_DIF_TYPE3:
532 : : /* If Type 3 is used, then all DIF checks are disabled when the
533 : : * Application Tag is 0xFFFF and the Reference Tag is 0xFFFFFFFF
534 : : * or 0xFFFFFFFFFFFFFFFF depending on the PI format.
535 : : */
536 : :
537 [ + + + + : 8529639 : if (_dif_apptag_ignore(dif, ctx->dif_pi_format) &&
# # # # ]
538 [ # # # # ]: 28 : _dif_reftag_ignore(dif, ctx->dif_pi_format)) {
539 : 16 : return true;
540 : : }
541 : 8529602 : break;
542 : 0 : default:
543 : 0 : break;
544 : : }
545 : :
546 : 40694710 : return false;
547 : 6796737 : }
548 : :
549 : : static bool
550 : 5283659 : _dif_pi_format_is_valid(enum spdk_dif_pi_format dif_pi_format)
551 : : {
552 [ + + ]: 5283659 : switch (dif_pi_format) {
553 : 3924611 : case SPDK_DIF_PI_FORMAT_16:
554 : : case SPDK_DIF_PI_FORMAT_32:
555 : : case SPDK_DIF_PI_FORMAT_64:
556 : 5283655 : return true;
557 : 3 : default:
558 : 4 : return false;
559 : : }
560 : 1359045 : }
561 : :
562 : : static bool
563 : 5282614 : _dif_type_is_valid(enum spdk_dif_type dif_type)
564 : : {
565 [ + + ]: 5282614 : switch (dif_type) {
566 : 3924614 : case SPDK_DIF_DISABLE:
567 : : case SPDK_DIF_TYPE1:
568 : : case SPDK_DIF_TYPE2:
569 : : case SPDK_DIF_TYPE3:
570 : 5282610 : return true;
571 : 3 : default:
572 : 4 : return false;
573 : : }
574 : 1357997 : }
575 : :
576 : : int
577 : 5283449 : spdk_dif_ctx_init(struct spdk_dif_ctx *ctx, uint32_t block_size, uint32_t md_size,
578 : : bool md_interleave, bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
579 : : uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag,
580 : : uint32_t data_offset, uint64_t guard_seed, struct spdk_dif_ctx_init_ext_opts *opts)
581 : : {
582 : : uint32_t data_block_size;
583 : 5283449 : enum spdk_dif_pi_format dif_pi_format = SPDK_DIF_PI_FORMAT_16;
584 : :
585 [ + + ]: 5283449 : if (opts != NULL) {
586 [ + + # # : 5282395 : if (!_dif_pi_format_is_valid(opts->dif_pi_format)) {
# # ]
587 : 0 : SPDK_ERRLOG("No valid DIF PI format provided.\n");
588 : 0 : return -EINVAL;
589 : : }
590 : :
591 [ # # # # ]: 5282395 : dif_pi_format = opts->dif_pi_format;
592 : 1357793 : }
593 : :
594 [ + + ]: 5283449 : if (!_dif_type_is_valid(dif_type)) {
595 : 0 : SPDK_ERRLOG("No valid DIF type was provided.\n");
596 : 0 : return -EINVAL;
597 : : }
598 : :
599 [ + + ]: 5281341 : if (md_size < _dif_size(dif_pi_format)) {
600 : 44 : SPDK_ERRLOG("Metadata size is smaller than DIF size.\n");
601 : 44 : return -EINVAL;
602 : : }
603 : :
604 [ + + # # ]: 5281297 : if (md_interleave) {
605 [ - + ]: 5100981 : if (block_size < md_size) {
606 : 0 : SPDK_ERRLOG("Block size is smaller than DIF size.\n");
607 : 0 : return -EINVAL;
608 : : }
609 : 5100981 : data_block_size = block_size - md_size;
610 : 1356489 : } else {
611 : 180316 : data_block_size = block_size;
612 : : }
613 : :
614 [ + + ]: 5281297 : if (data_block_size == 0) {
615 : 8 : SPDK_ERRLOG("Zero data block size is not allowed\n");
616 : 8 : return -EINVAL;
617 : : }
618 : :
619 [ + + ]: 5281013 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
620 [ + + # # ]: 5279689 : if ((data_block_size % 512) != 0) {
621 : 0 : SPDK_ERRLOG("Data block size should be a multiple of 512B\n");
622 : 0 : return -EINVAL;
623 : : }
624 : 1356119 : } else {
625 [ + + # # ]: 1324 : if ((data_block_size % 4096) != 0) {
626 : 24 : SPDK_ERRLOG("Data block size should be a multiple of 4kB\n");
627 : 24 : return -EINVAL;
628 : : }
629 : : }
630 : :
631 [ # # # # ]: 5280989 : ctx->block_size = block_size;
632 [ # # # # ]: 5280989 : ctx->md_size = md_size;
633 [ # # # # : 5280989 : ctx->md_interleave = md_interleave;
# # ]
634 [ # # # # ]: 5280989 : ctx->dif_pi_format = dif_pi_format;
635 [ # # # # : 6637433 : ctx->guard_interval = _get_guard_interval(block_size, md_size, dif_loc, md_interleave,
# # # # ]
636 [ # # # # ]: 5280989 : _dif_size(ctx->dif_pi_format));
637 [ # # # # ]: 5280989 : ctx->dif_type = dif_type;
638 [ # # # # ]: 5280989 : ctx->dif_flags = dif_flags;
639 [ # # # # ]: 5280989 : ctx->init_ref_tag = init_ref_tag;
640 [ # # # # ]: 5280989 : ctx->apptag_mask = apptag_mask;
641 [ # # # # ]: 5280989 : ctx->app_tag = app_tag;
642 [ # # # # ]: 5280989 : ctx->data_offset = data_offset;
643 [ - + # # : 5280989 : ctx->ref_tag_offset = data_offset / data_block_size;
# # ]
644 [ # # # # ]: 5280989 : ctx->last_guard = guard_seed;
645 [ # # # # ]: 5280989 : ctx->guard_seed = guard_seed;
646 [ # # # # ]: 5280989 : ctx->remapped_init_ref_tag = 0;
647 : :
648 : 5280989 : return 0;
649 : 1356463 : }
650 : :
651 : : void
652 : 1135170 : spdk_dif_ctx_set_data_offset(struct spdk_dif_ctx *ctx, uint32_t data_offset)
653 : : {
654 : : uint32_t data_block_size;
655 : :
656 [ + + + - : 1135170 : if (ctx->md_interleave) {
# # # # ]
657 [ # # # # : 1135170 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
658 : 42 : } else {
659 [ # # # # ]: 0 : data_block_size = ctx->block_size;
660 : : }
661 : :
662 [ # # # # ]: 1135170 : ctx->data_offset = data_offset;
663 [ - + # # : 1135170 : ctx->ref_tag_offset = data_offset / data_block_size;
# # ]
664 : 1135170 : }
665 : :
666 : : void
667 : 96 : spdk_dif_ctx_set_remapped_init_ref_tag(struct spdk_dif_ctx *ctx,
668 : : uint32_t remapped_init_ref_tag)
669 : : {
670 [ # # # # ]: 96 : ctx->remapped_init_ref_tag = remapped_init_ref_tag;
671 : 96 : }
672 : :
673 : : static void
674 : 30651655 : _dif_generate(void *_dif, uint64_t guard, uint32_t offset_blocks,
675 : : const struct spdk_dif_ctx *ctx)
676 : : {
677 : 30651655 : struct spdk_dif *dif = _dif;
678 : : uint64_t ref_tag;
679 : :
680 [ + + # # : 30651655 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
681 [ # # # # ]: 30649471 : _dif_set_guard(dif, guard, ctx->dif_pi_format);
682 : 2688654 : } else {
683 [ # # # # ]: 2184 : _dif_set_guard(dif, 0, ctx->dif_pi_format);
684 : : }
685 : :
686 [ + + # # : 30651655 : if (ctx->dif_flags & SPDK_DIF_FLAGS_APPTAG_CHECK) {
# # # # ]
687 [ # # # # : 8792820 : _dif_set_apptag(dif, ctx->app_tag, ctx->dif_pi_format);
# # # # ]
688 : 49729 : } else {
689 [ # # # # ]: 21858835 : _dif_set_apptag(dif, 0, ctx->dif_pi_format);
690 : : }
691 : :
692 [ + + # # : 30651655 : if (ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK) {
# # # # ]
693 : : /* For type 1 and 2, the reference tag is incremented for each
694 : : * subsequent logical block. For type 3, the reference tag
695 : : * remains the same as the initial reference tag.
696 : : */
697 [ + + # # : 22023805 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
# # ]
698 [ # # # # : 22023777 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
# # # # ]
699 : 2592412 : } else {
700 [ # # # # : 28 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset;
# # # # ]
701 : : }
702 : :
703 : : /* Overwrite reference tag if initialization reference tag is SPDK_DIF_REFTAG_IGNORE */
704 [ + + # # : 22023805 : if (ctx->init_ref_tag == SPDK_DIF_REFTAG_IGNORE) {
# # ]
705 [ + + # # : 30728 : if (ctx->dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
# # ]
706 : 30728 : ref_tag = REFTAG_MASK_16;
707 [ # # # # : 6146 : } else if (ctx->dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
# # ]
708 : 0 : ref_tag = REFTAG_MASK_32;
709 : 0 : } else {
710 : 0 : ref_tag = REFTAG_MASK_64;
711 : : }
712 : 6146 : }
713 : :
714 [ # # # # ]: 22023805 : _dif_set_reftag(dif, ref_tag, ctx->dif_pi_format);
715 : 2592419 : } else {
716 [ # # # # ]: 8531626 : _dif_set_reftag(dif, 0, ctx->dif_pi_format);
717 : : }
718 : 30555431 : }
719 : :
720 : : static void
721 : 1381337 : dif_generate(struct _dif_sgl *sgl, uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
722 : : {
723 : : uint32_t offset_blocks;
724 : 275844 : uint8_t *buf;
725 : 1381337 : uint64_t guard = 0;
726 : :
727 [ + + ]: 13524203 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
728 : 12142866 : _dif_sgl_get_buf(sgl, &buf, NULL);
729 : :
730 [ + + # # : 12142866 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
731 [ # # # # : 12142314 : guard = _dif_generate_guard(ctx->guard_seed, buf, ctx->guard_interval, ctx->dif_pi_format);
# # # # #
# # # ]
732 : 6619 : }
733 : :
734 [ # # # # : 12142866 : _dif_generate(buf + ctx->guard_interval, guard, offset_blocks, ctx);
# # ]
735 : :
736 [ # # # # ]: 12142866 : _dif_sgl_advance(sgl, ctx->block_size);
737 : 6721 : }
738 : 1381337 : }
739 : :
740 : : static void
741 : 8530344 : dif_store_split(struct _dif_sgl *sgl, struct spdk_dif *dif,
742 : : const struct spdk_dif_ctx *ctx)
743 : : {
744 : 8530344 : uint32_t offset = 0, rest_md_len, buf_len;
745 : 894 : uint8_t *buf;
746 : :
747 [ # # # # : 8530344 : rest_md_len = ctx->block_size - ctx->guard_interval;
# # # # ]
748 : :
749 [ + + ]: 17061504 : while (offset < rest_md_len) {
750 : 8531160 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
751 : :
752 [ + + # # : 8531160 : if (offset < _dif_size(ctx->dif_pi_format)) {
# # ]
753 [ + + # # : 8530696 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset);
# # # # #
# ]
754 [ - + - + : 8530696 : memcpy(buf, (uint8_t *)dif + offset, buf_len);
# # ]
755 : 386 : } else {
756 [ + + ]: 464 : buf_len = spdk_min(buf_len, rest_md_len - offset);
757 : : }
758 : :
759 : 8531160 : _dif_sgl_advance(sgl, buf_len);
760 : 8531160 : offset += buf_len;
761 : : }
762 : 8530344 : }
763 : :
764 : : static uint64_t
765 : 8530200 : _dif_generate_split(struct _dif_sgl *sgl, uint32_t offset_in_block, uint32_t data_len,
766 : : uint64_t guard, uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
767 : : {
768 : 8530200 : struct spdk_dif dif = {};
769 : :
770 [ + + # # : 8530200 : assert(offset_in_block < ctx->guard_interval);
# # # # ]
771 [ + + - + : 8530200 : assert(offset_in_block + data_len < ctx->guard_interval ||
# # # # #
# # # #
# ]
772 : : offset_in_block + data_len == ctx->block_size);
773 : :
774 : : /* Compute CRC over split logical block data. */
775 : 8530200 : guard = dif_generate_guard_split(guard, sgl, offset_in_block, data_len, ctx);
776 : :
777 [ + + # # : 8530200 : if (offset_in_block + data_len < ctx->guard_interval) {
# # ]
778 : 156 : return guard;
779 : : }
780 : :
781 : : /* If a whole logical block data is parsed, generate DIF
782 : : * and save it to the temporary DIF area.
783 : : */
784 : 8530044 : _dif_generate(&dif, guard, offset_blocks, ctx);
785 : :
786 : : /* Copy generated DIF field to the split DIF field, and then
787 : : * skip metadata field after DIF field (if any).
788 : : */
789 : 8530044 : dif_store_split(sgl, &dif, ctx);
790 : :
791 [ + + # # : 8530044 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
792 [ # # # # ]: 8530044 : guard = ctx->guard_seed;
793 : 223 : }
794 : :
795 : 8530044 : return guard;
796 : 262 : }
797 : :
798 : : static void
799 : 33925 : dif_generate_split(struct _dif_sgl *sgl, uint32_t num_blocks,
800 : : const struct spdk_dif_ctx *ctx)
801 : : {
802 : : uint32_t offset_blocks;
803 : 33925 : uint64_t guard = 0;
804 : :
805 [ + + # # : 33925 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
806 [ # # # # ]: 33925 : guard = ctx->guard_seed;
807 : 152 : }
808 : :
809 [ + + ]: 8563785 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
810 [ # # # # ]: 8529860 : _dif_generate_split(sgl, 0, ctx->block_size, guard, offset_blocks, ctx);
811 : 177 : }
812 : 33925 : }
813 : :
814 : : int
815 : 1415230 : spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
816 : : const struct spdk_dif_ctx *ctx)
817 : : {
818 : 276276 : struct _dif_sgl sgl;
819 : :
820 : 1415230 : _dif_sgl_init(&sgl, iovs, iovcnt);
821 : :
822 [ - + # # : 1415230 : if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) {
# # ]
823 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
824 : 0 : return -EINVAL;
825 : : }
826 : :
827 [ + + # # : 1415230 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
828 : 4 : return 0;
829 : : }
830 : :
831 [ + + # # : 1415226 : if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
# # ]
832 : 1381301 : dif_generate(&sgl, num_blocks, ctx);
833 : 94 : } else {
834 : 33925 : dif_generate_split(&sgl, num_blocks, ctx);
835 : : }
836 : :
837 : 1415226 : return 0;
838 : 247 : }
839 : :
840 : : static void
841 : 1099 : _dif_error_set(struct spdk_dif_error *err_blk, uint8_t err_type,
842 : : uint64_t expected, uint64_t actual, uint32_t err_offset)
843 : : {
844 [ + + ]: 1099 : if (err_blk) {
845 [ # # # # ]: 1063 : err_blk->err_type = err_type;
846 [ # # # # ]: 1063 : err_blk->expected = expected;
847 [ # # # # ]: 1063 : err_blk->actual = actual;
848 [ # # # # ]: 1063 : err_blk->err_offset = err_offset;
849 : 253 : }
850 : 1099 : }
851 : :
852 : : static bool
853 : 40407674 : _dif_reftag_check(struct spdk_dif *dif, const struct spdk_dif_ctx *ctx,
854 : : uint64_t expected_reftag, uint32_t offset_blocks, struct spdk_dif_error *err_blk)
855 : : {
856 : : uint64_t reftag;
857 : :
858 [ + + # # : 40407674 : if (ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK) {
# # # # ]
859 [ + - - # : 31863128 : switch (ctx->dif_type) {
# # # ]
860 : 25375861 : case SPDK_DIF_TYPE1:
861 : : case SPDK_DIF_TYPE2:
862 : : /* Compare the DIF Reference Tag field to the passed Reference Tag.
863 : : * The passed Reference Tag will be the least significant 4 bytes
864 : : * or 8 bytes (depending on the PI format)
865 : : * of the LBA when Type 1 is used, and application specific value
866 : : * if Type 2 is used.
867 : : */
868 [ + + # # : 31863128 : if (!_dif_reftag_match(dif, expected_reftag, ctx->dif_pi_format)) {
# # ]
869 [ # # # # ]: 282 : reftag = _dif_get_reftag(dif, ctx->dif_pi_format);
870 : 348 : _dif_error_set(err_blk, SPDK_DIF_REFTAG_ERROR, expected_reftag,
871 : 66 : reftag, offset_blocks);
872 : 282 : SPDK_ERRLOG("Failed to compare Ref Tag: LBA=%" PRIu64 "," \
873 : : " Expected=%lx, Actual=%lx\n",
874 : : expected_reftag, expected_reftag, reftag);
875 : 282 : return false;
876 : : }
877 : 31862846 : break;
878 : 0 : case SPDK_DIF_TYPE3:
879 : : /* For Type 3, computed Reference Tag remains unchanged.
880 : : * Hence ignore the Reference Tag field.
881 : : */
882 : 0 : break;
883 : 0 : default:
884 : 0 : break;
885 : : }
886 : 6487201 : }
887 : :
888 : 40407392 : return true;
889 : 6500420 : }
890 : :
891 : : static int
892 : 40340216 : _dif_verify(void *_dif, uint64_t guard, uint32_t offset_blocks,
893 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
894 : : {
895 : 40340216 : struct spdk_dif *dif = _dif;
896 : : uint64_t _guard;
897 : : uint16_t _app_tag;
898 : : uint64_t ref_tag;
899 : :
900 [ + + ]: 40340216 : if (_dif_ignore(dif, ctx)) {
901 : 59641 : return 0;
902 : : }
903 : :
904 : : /* For type 1 and 2, the reference tag is incremented for each
905 : : * subsequent logical block. For type 3, the reference tag
906 : : * remains the same as the initial reference tag.
907 : : */
908 [ + + # # : 40280575 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
# # ]
909 [ # # # # : 31750973 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
# # # # ]
910 : 6373129 : } else {
911 [ # # # # : 8529602 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset;
# # # # ]
912 : : }
913 : :
914 [ + + # # : 40280575 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
915 : : /* Compare the DIF Guard field to the CRC computed over the logical
916 : : * block data.
917 : : */
918 [ # # # # ]: 40275360 : _guard = _dif_get_guard(dif, ctx->dif_pi_format);
919 [ + + ]: 40275360 : if (_guard != guard) {
920 : 635 : _dif_error_set(err_blk, SPDK_DIF_GUARD_ERROR, _guard, guard,
921 : 124 : offset_blocks);
922 : 511 : SPDK_ERRLOG("Failed to compare Guard: LBA=%" PRIu64 "," \
923 : : " Expected=%lx, Actual=%lx\n",
924 : : ref_tag, _guard, guard);
925 : 511 : return -1;
926 : : }
927 : 6369719 : }
928 : :
929 [ + + # # : 40280064 : if (ctx->dif_flags & SPDK_DIF_FLAGS_APPTAG_CHECK) {
# # # # ]
930 : : /* Compare unmasked bits in the DIF Application Tag field to the
931 : : * passed Application Tag.
932 : : */
933 [ # # # # ]: 4582589 : _app_tag = _dif_get_apptag(dif, ctx->dif_pi_format);
934 [ + + # # : 4582589 : if ((_app_tag & ctx->apptag_mask) != (ctx->app_tag & ctx->apptag_mask)) {
# # # # #
# # # #
# ]
935 [ # # # # ]: 378 : _dif_error_set(err_blk, SPDK_DIF_APPTAG_ERROR, ctx->app_tag,
936 [ # # # # ]: 306 : (_app_tag & ctx->apptag_mask), offset_blocks);
937 [ # # # # : 306 : SPDK_ERRLOG("Failed to compare App Tag: LBA=%" PRIu64 "," \
# # # # ]
938 : : " Expected=%x, Actual=%x\n",
939 : : ref_tag, ctx->app_tag, (_app_tag & ctx->apptag_mask));
940 : 306 : return -1;
941 : : }
942 : 1864 : }
943 : :
944 [ + + ]: 40279758 : if (!_dif_reftag_check(dif, ctx, ref_tag, offset_blocks, err_blk)) {
945 : 282 : return -1;
946 : : }
947 : :
948 : 40279476 : return 0;
949 : 6383344 : }
950 : :
951 : : static int
952 : 2276253 : dif_verify(struct _dif_sgl *sgl, uint32_t num_blocks,
953 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
954 : : {
955 : : uint32_t offset_blocks;
956 : : int rc;
957 : 1065869 : uint8_t *buf;
958 : 2276253 : uint64_t guard = 0;
959 : :
960 [ + + ]: 19609477 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
961 : 17333387 : _dif_sgl_get_buf(sgl, &buf, NULL);
962 : :
963 [ + + # # : 17333387 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
964 [ # # # # : 17316054 : guard = _dif_generate_guard(ctx->guard_seed, buf, ctx->guard_interval, ctx->dif_pi_format);
# # # # #
# # # ]
965 : 4542373 : }
966 : :
967 [ # # # # : 17333387 : rc = _dif_verify(buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
# # ]
968 [ + + ]: 17333387 : if (rc != 0) {
969 : 163 : return rc;
970 : : }
971 : :
972 [ # # # # ]: 17333224 : _dif_sgl_advance(sgl, ctx->block_size);
973 : 4559081 : }
974 : :
975 : 2276090 : return 0;
976 : 679340 : }
977 : :
978 : : static void
979 : 14140555 : dif_load_split(struct _dif_sgl *sgl, struct spdk_dif *dif,
980 : : const struct spdk_dif_ctx *ctx)
981 : : {
982 : 14140555 : uint32_t offset = 0, rest_md_len, buf_len;
983 : 744 : uint8_t *buf;
984 : :
985 [ # # # # : 14140555 : rest_md_len = ctx->block_size - ctx->guard_interval;
# # # # ]
986 : :
987 [ + + ]: 28281917 : while (offset < rest_md_len) {
988 : 14141362 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
989 : :
990 [ + + # # : 14141362 : if (offset < _dif_size(ctx->dif_pi_format)) {
# # ]
991 [ + + # # : 14140895 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset);
# # # # #
# ]
992 [ - + - + : 14140895 : memcpy((uint8_t *)dif + offset, buf, buf_len);
# # ]
993 : 341 : } else {
994 [ + + ]: 467 : buf_len = spdk_min(buf_len, rest_md_len - offset);
995 : : }
996 : :
997 : 14141362 : _dif_sgl_advance(sgl, buf_len);
998 : 14141362 : offset += buf_len;
999 : : }
1000 : 14140555 : }
1001 : :
1002 : : static int
1003 : 14140339 : _dif_verify_split(struct _dif_sgl *sgl, uint32_t offset_in_block, uint32_t data_len,
1004 : : uint64_t *_guard, uint32_t offset_blocks,
1005 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
1006 : : {
1007 [ # # ]: 14140339 : uint64_t guard = *_guard;
1008 : 14140339 : struct spdk_dif dif = {};
1009 : : int rc;
1010 : :
1011 [ + + # # ]: 14140339 : assert(_guard != NULL);
1012 [ + + # # : 14140339 : assert(offset_in_block < ctx->guard_interval);
# # # # ]
1013 [ + + - + : 14140339 : assert(offset_in_block + data_len < ctx->guard_interval ||
# # # # #
# # # #
# ]
1014 : : offset_in_block + data_len == ctx->block_size);
1015 : :
1016 : 14140339 : guard = dif_generate_guard_split(guard, sgl, offset_in_block, data_len, ctx);
1017 : :
1018 [ + + # # : 14140339 : if (offset_in_block + data_len < ctx->guard_interval) {
# # ]
1019 [ # # ]: 60 : *_guard = guard;
1020 : 60 : return 0;
1021 : : }
1022 : :
1023 : 14140279 : dif_load_split(sgl, &dif, ctx);
1024 : :
1025 : 14140279 : rc = _dif_verify(&dif, guard, offset_blocks, ctx, err_blk);
1026 [ + + ]: 14140279 : if (rc != 0) {
1027 : 480 : return rc;
1028 : : }
1029 : :
1030 [ + + # # : 14139799 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1031 [ # # # # ]: 14139799 : guard = ctx->guard_seed;
1032 : 61 : }
1033 : :
1034 [ # # ]: 14139799 : *_guard = guard;
1035 : 14139799 : return 0;
1036 : 196 : }
1037 : :
1038 : : static int
1039 : 603 : dif_verify_split(struct _dif_sgl *sgl, uint32_t num_blocks,
1040 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
1041 : : {
1042 : : uint32_t offset_blocks;
1043 : 603 : uint64_t guard = 0;
1044 : : int rc;
1045 : :
1046 [ + + # # : 603 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1047 [ # # # # ]: 603 : guard = ctx->guard_seed;
1048 : 150 : }
1049 : :
1050 [ + + ]: 844 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1051 [ # # # # ]: 890 : rc = _dif_verify_split(sgl, 0, ctx->block_size, &guard, offset_blocks,
1052 : 169 : ctx, err_blk);
1053 [ + + ]: 721 : if (rc != 0) {
1054 : 480 : return rc;
1055 : : }
1056 : 49 : }
1057 : :
1058 : 123 : return 0;
1059 : 150 : }
1060 : :
1061 : : int
1062 : 2287601 : spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
1063 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
1064 : : {
1065 : 1066295 : struct _dif_sgl sgl;
1066 : :
1067 : 2287601 : _dif_sgl_init(&sgl, iovs, iovcnt);
1068 : :
1069 [ - + # # : 2287601 : if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) {
# # ]
1070 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
1071 : 0 : return -EINVAL;
1072 : : }
1073 : :
1074 [ + + # # : 2287601 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
1075 : 4 : return 0;
1076 : : }
1077 : :
1078 [ + + # # : 2287597 : if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
# # ]
1079 : 2286994 : return dif_verify(&sgl, num_blocks, ctx, err_blk);
1080 : : } else {
1081 : 603 : return dif_verify_split(&sgl, num_blocks, ctx, err_blk);
1082 : : }
1083 : 690259 : }
1084 : :
1085 : : static uint32_t
1086 : 36 : dif_update_crc32c(struct _dif_sgl *sgl, uint32_t num_blocks,
1087 : : uint32_t crc32c, const struct spdk_dif_ctx *ctx)
1088 : : {
1089 : : uint32_t offset_blocks;
1090 : 27 : uint8_t *buf;
1091 : :
1092 [ + + ]: 180 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1093 : 144 : _dif_sgl_get_buf(sgl, &buf, NULL);
1094 : :
1095 [ # # # # : 144 : crc32c = spdk_crc32c_update(buf, ctx->block_size - ctx->md_size, crc32c);
# # # # ]
1096 : :
1097 [ # # # # ]: 144 : _dif_sgl_advance(sgl, ctx->block_size);
1098 : 36 : }
1099 : :
1100 : 36 : return crc32c;
1101 : : }
1102 : :
1103 : : static uint32_t
1104 : 5471911 : _dif_update_crc32c_split(struct _dif_sgl *sgl, uint32_t offset_in_block, uint32_t data_len,
1105 : : uint32_t crc32c, const struct spdk_dif_ctx *ctx)
1106 : : {
1107 : 153 : uint32_t data_block_size, buf_len;
1108 : 153 : uint8_t *buf;
1109 : :
1110 [ # # # # : 5471911 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1111 : :
1112 [ + + # # : 5471911 : assert(offset_in_block + data_len <= ctx->block_size);
# # # # ]
1113 : :
1114 [ + + ]: 16437190 : while (data_len != 0) {
1115 : 10965279 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
1116 [ + + ]: 10965279 : buf_len = spdk_min(buf_len, data_len);
1117 : :
1118 [ + + ]: 10965279 : if (offset_in_block < data_block_size) {
1119 [ + + ]: 5493356 : buf_len = spdk_min(buf_len, data_block_size - offset_in_block);
1120 : 5493356 : crc32c = spdk_crc32c_update(buf, buf_len, crc32c);
1121 : 69 : }
1122 : :
1123 : 10965279 : _dif_sgl_advance(sgl, buf_len);
1124 : 10965279 : offset_in_block += buf_len;
1125 : 10965279 : data_len -= buf_len;
1126 : : }
1127 : :
1128 : 5471911 : return crc32c;
1129 : : }
1130 : :
1131 : : static uint32_t
1132 : 24 : dif_update_crc32c_split(struct _dif_sgl *sgl, uint32_t num_blocks,
1133 : : uint32_t crc32c, const struct spdk_dif_ctx *ctx)
1134 : : {
1135 : : uint32_t offset_blocks;
1136 : :
1137 [ + + ]: 120 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1138 [ # # # # ]: 96 : crc32c = _dif_update_crc32c_split(sgl, 0, ctx->block_size, crc32c, ctx);
1139 : 24 : }
1140 : :
1141 : 24 : return crc32c;
1142 : : }
1143 : :
1144 : : int
1145 : 60 : spdk_dif_update_crc32c(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
1146 : : uint32_t *_crc32c, const struct spdk_dif_ctx *ctx)
1147 : : {
1148 : 45 : struct _dif_sgl sgl;
1149 : :
1150 [ + + ]: 60 : if (_crc32c == NULL) {
1151 : 0 : return -EINVAL;
1152 : : }
1153 : :
1154 : 60 : _dif_sgl_init(&sgl, iovs, iovcnt);
1155 : :
1156 [ + + # # : 60 : if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) {
# # ]
1157 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
1158 : 0 : return -EINVAL;
1159 : : }
1160 : :
1161 [ + + # # : 60 : if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
# # ]
1162 [ # # # # ]: 36 : *_crc32c = dif_update_crc32c(&sgl, num_blocks, *_crc32c, ctx);
1163 : 9 : } else {
1164 [ # # # # ]: 24 : *_crc32c = dif_update_crc32c_split(&sgl, num_blocks, *_crc32c, ctx);
1165 : : }
1166 : :
1167 : 60 : return 0;
1168 : 15 : }
1169 : :
1170 : : static void
1171 : 9869147 : _dif_insert_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1172 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
1173 : : {
1174 : : uint32_t data_block_size;
1175 : 4453244 : uint8_t *src, *dst;
1176 : 9869147 : uint64_t guard = 0;
1177 : :
1178 [ # # # # : 9869147 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1179 : :
1180 : 9869147 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1181 : 9869147 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1182 : :
1183 [ + + # # : 9869147 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1184 [ # # # # ]: 12445420 : guard = _dif_generate_guard_copy(ctx->guard_seed, dst, src, data_block_size,
1185 [ # # # # ]: 9868523 : ctx->dif_pi_format);
1186 [ # # ]: 12445420 : guard = _dif_generate_guard(guard, dst + data_block_size,
1187 [ # # # # : 9868523 : ctx->guard_interval - data_block_size, ctx->dif_pi_format);
# # # # ]
1188 : 2576897 : } else {
1189 [ - + - + ]: 624 : memcpy(dst, src, data_block_size);
1190 : : }
1191 : :
1192 [ # # # # : 9869147 : _dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx);
# # ]
1193 : :
1194 : 9869147 : _dif_sgl_advance(src_sgl, data_block_size);
1195 [ # # # # ]: 9869147 : _dif_sgl_advance(dst_sgl, ctx->block_size);
1196 : 9869147 : }
1197 : :
1198 : : static void
1199 : 1247856 : dif_insert_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1200 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1201 : : {
1202 : : uint32_t offset_blocks;
1203 : :
1204 [ + + ]: 11112748 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1205 : 9864892 : _dif_insert_copy(src_sgl, dst_sgl, offset_blocks, ctx);
1206 : 2572792 : }
1207 : 1247856 : }
1208 : :
1209 : : static void
1210 : 268 : _dif_insert_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1211 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
1212 : : {
1213 : : uint32_t data_block_size;
1214 : 268 : uint64_t guard = 0;
1215 : 268 : struct spdk_dif dif = {};
1216 : :
1217 [ # # # # : 268 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1218 : :
1219 [ + - # # : 268 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1220 [ # # # # ]: 335 : guard = _dif_generate_guard_copy_split(ctx->guard_seed, dst_sgl, src_sgl,
1221 [ # # # # ]: 268 : data_block_size, ctx->dif_pi_format);
1222 : 335 : guard = dif_generate_guard_split(guard, dst_sgl, data_block_size,
1223 [ # # # # ]: 268 : ctx->guard_interval - data_block_size, ctx);
1224 : 67 : } else {
1225 : 0 : _data_copy_split(dst_sgl, src_sgl, data_block_size);
1226 [ # # # # ]: 0 : _dif_sgl_advance(dst_sgl, ctx->guard_interval - data_block_size);
1227 : : }
1228 : :
1229 : 268 : _dif_generate(&dif, guard, offset_blocks, ctx);
1230 : :
1231 : 268 : dif_store_split(dst_sgl, &dif, ctx);
1232 : 268 : }
1233 : :
1234 : : static void
1235 : 124 : dif_insert_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1236 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1237 : : {
1238 : : uint32_t offset_blocks;
1239 : :
1240 [ + + ]: 392 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1241 : 268 : _dif_insert_copy_split(src_sgl, dst_sgl, offset_blocks, ctx);
1242 : 67 : }
1243 : 124 : }
1244 : :
1245 : : static void
1246 : 48 : _dif_disable_insert_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1247 : : const struct spdk_dif_ctx *ctx)
1248 : : {
1249 : 48 : uint32_t offset = 0, src_len, dst_len, buf_len, data_block_size;
1250 : 36 : uint8_t *src, *dst;
1251 : :
1252 [ # # # # : 48 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1253 : :
1254 [ + + ]: 128 : while (offset < data_block_size) {
1255 : 80 : _dif_sgl_get_buf(src_sgl, &src, &src_len);
1256 : 80 : _dif_sgl_get_buf(dst_sgl, &dst, &dst_len);
1257 [ + + ]: 80 : buf_len = spdk_min(src_len, dst_len);
1258 [ + + ]: 80 : buf_len = spdk_min(buf_len, data_block_size - offset);
1259 : :
1260 [ - + - + ]: 80 : memcpy(dst, src, buf_len);
1261 : :
1262 : 80 : _dif_sgl_advance(src_sgl, buf_len);
1263 : 80 : _dif_sgl_advance(dst_sgl, buf_len);
1264 : 80 : offset += buf_len;
1265 : : }
1266 : :
1267 [ # # # # ]: 48 : _dif_sgl_advance(dst_sgl, ctx->md_size);
1268 : 48 : }
1269 : :
1270 : : static void
1271 : 12 : dif_disable_insert_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1272 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1273 : : {
1274 : : uint32_t offset_blocks;
1275 : :
1276 [ + + ]: 60 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1277 : 48 : _dif_disable_insert_copy(src_sgl, dst_sgl, ctx);
1278 : 12 : }
1279 : 12 : }
1280 : :
1281 : : static int
1282 : 1253470 : _spdk_dif_insert_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1283 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1284 : : {
1285 : : uint32_t data_block_size;
1286 : :
1287 [ # # # # : 1253470 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1288 : :
1289 [ + + + + ]: 1253470 : if (!_dif_sgl_is_valid(src_sgl, data_block_size * num_blocks) ||
1290 [ + + # # ]: 1252056 : !_dif_sgl_is_valid(dst_sgl, ctx->block_size * num_blocks)) {
1291 : 2831 : SPDK_ERRLOG("Size of iovec arrays are not valid.\n");
1292 : 2831 : return -EINVAL;
1293 : : }
1294 : :
1295 [ + + # # : 1253467 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
1296 : 12 : dif_disable_insert_copy(src_sgl, dst_sgl, num_blocks, ctx);
1297 : 12 : return 0;
1298 : : }
1299 : :
1300 [ + + + + ]: 2164951 : if (_dif_sgl_is_bytes_multiple(src_sgl, data_block_size) &&
1301 [ # # # # ]: 1250779 : _dif_sgl_is_bytes_multiple(dst_sgl, ctx->block_size)) {
1302 : 1248227 : dif_insert_copy(src_sgl, dst_sgl, num_blocks, ctx);
1303 : 336731 : } else {
1304 : 5228 : dif_insert_copy_split(src_sgl, dst_sgl, num_blocks, ctx);
1305 : : }
1306 : :
1307 : 1248351 : return 0;
1308 : 336765 : }
1309 : :
1310 : : static void
1311 : 384 : _dif_overwrite_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1312 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
1313 : : {
1314 : 288 : uint8_t *src, *dst;
1315 : 384 : uint64_t guard = 0;
1316 : :
1317 : 384 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1318 : 384 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1319 : :
1320 [ + + # # : 384 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1321 [ # # # # : 120 : guard = _dif_generate_guard_copy(ctx->guard_seed, dst, src, ctx->guard_interval,
# # # # ]
1322 [ # # # # ]: 96 : ctx->dif_pi_format);
1323 : 24 : } else {
1324 [ - + - + : 288 : memcpy(dst, src, ctx->guard_interval);
# # # # ]
1325 : : }
1326 : :
1327 [ # # # # : 384 : _dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx);
# # ]
1328 : :
1329 [ # # # # ]: 384 : _dif_sgl_advance(src_sgl, ctx->block_size);
1330 [ # # # # ]: 384 : _dif_sgl_advance(dst_sgl, ctx->block_size);
1331 : 384 : }
1332 : :
1333 : : static void
1334 : 64 : dif_overwrite_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1335 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1336 : : {
1337 : : uint32_t offset_blocks;
1338 : :
1339 [ + + ]: 448 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1340 : 384 : _dif_overwrite_copy(src_sgl, dst_sgl, offset_blocks, ctx);
1341 : 96 : }
1342 : 64 : }
1343 : :
1344 : : static void
1345 : 32 : _dif_overwrite_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1346 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
1347 : : {
1348 : 32 : uint64_t guard = 0;
1349 : 32 : struct spdk_dif dif = {};
1350 : :
1351 [ + - # # : 32 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1352 [ # # # # ]: 40 : guard = _dif_generate_guard_copy_split(ctx->guard_seed, dst_sgl, src_sgl,
1353 [ # # # # : 32 : ctx->guard_interval, ctx->dif_pi_format);
# # # # ]
1354 : 8 : } else {
1355 [ # # # # ]: 0 : _data_copy_split(dst_sgl, src_sgl, ctx->guard_interval);
1356 : : }
1357 : :
1358 [ # # # # : 32 : _dif_sgl_advance(src_sgl, ctx->block_size - ctx->guard_interval);
# # # # ]
1359 : :
1360 : 32 : _dif_generate(&dif, guard, offset_blocks, ctx);
1361 : 32 : dif_store_split(dst_sgl, &dif, ctx);
1362 : 32 : }
1363 : :
1364 : : static void
1365 : 8 : dif_overwrite_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1366 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1367 : : {
1368 : : uint32_t offset_blocks;
1369 : :
1370 [ + + ]: 40 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1371 : 32 : _dif_overwrite_copy_split(src_sgl, dst_sgl, offset_blocks, ctx);
1372 : 8 : }
1373 : 8 : }
1374 : :
1375 : : static void
1376 : 0 : dif_disable_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1377 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1378 : : {
1379 [ # # # # ]: 0 : _data_copy_split(dst_sgl, src_sgl, ctx->block_size * num_blocks);
1380 : 0 : }
1381 : :
1382 : : static int
1383 : 72 : _spdk_dif_overwrite_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1384 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1385 : : {
1386 [ + - - + : 72 : if (!_dif_sgl_is_valid(src_sgl, ctx->block_size * num_blocks) ||
# # # # ]
1387 [ - + # # ]: 72 : !_dif_sgl_is_valid(dst_sgl, ctx->block_size * num_blocks)) {
1388 : 0 : SPDK_ERRLOG("Size of iovec arrays are not valid.\n");
1389 : 0 : return -EINVAL;
1390 : : }
1391 : :
1392 [ - + # # : 72 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
1393 : 0 : dif_disable_copy(src_sgl, dst_sgl, num_blocks, ctx);
1394 : 0 : return 0;
1395 : : }
1396 : :
1397 [ + + + - : 120 : if (_dif_sgl_is_bytes_multiple(src_sgl, ctx->block_size) &&
# # # # ]
1398 [ # # # # ]: 64 : _dif_sgl_is_bytes_multiple(dst_sgl, ctx->block_size)) {
1399 : 64 : dif_overwrite_copy(src_sgl, dst_sgl, num_blocks, ctx);
1400 : 16 : } else {
1401 : 8 : dif_overwrite_copy_split(src_sgl, dst_sgl, num_blocks, ctx);
1402 : : }
1403 : :
1404 : 72 : return 0;
1405 : 18 : }
1406 : :
1407 : : int
1408 : 1251389 : spdk_dif_generate_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iovs,
1409 : : int bounce_iovcnt, uint32_t num_blocks,
1410 : : const struct spdk_dif_ctx *ctx)
1411 : : {
1412 : 556796 : struct _dif_sgl src_sgl, dst_sgl;
1413 : :
1414 : 1251389 : _dif_sgl_init(&src_sgl, iovs, iovcnt);
1415 : 1251389 : _dif_sgl_init(&dst_sgl, bounce_iovs, bounce_iovcnt);
1416 : :
1417 [ + + - + : 1251443 : if (!(ctx->dif_flags & SPDK_DIF_FLAGS_NVME_PRACT) ||
# # # # #
# ]
1418 [ # # # # : 72 : ctx->md_size == _dif_size(ctx->dif_pi_format)) {
# # # # ]
1419 : 1251317 : return _spdk_dif_insert_copy(&src_sgl, &dst_sgl, num_blocks, ctx);
1420 : : } else {
1421 : 72 : return _spdk_dif_overwrite_copy(&src_sgl, &dst_sgl, num_blocks, ctx);
1422 : : }
1423 : 339734 : }
1424 : :
1425 : : static int
1426 : 7585092 : _dif_strip_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1427 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx,
1428 : : struct spdk_dif_error *err_blk)
1429 : : {
1430 : : uint32_t data_block_size;
1431 : 3814327 : uint8_t *src, *dst;
1432 : : int rc;
1433 : 7585092 : uint64_t guard = 0;
1434 : :
1435 [ # # # # : 7585092 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1436 : :
1437 : 7585092 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1438 : 7585092 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1439 : :
1440 [ + + # # : 7585092 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1441 [ # # # # ]: 10089919 : guard = _dif_generate_guard_copy(ctx->guard_seed, dst, src, data_block_size,
1442 [ # # # # ]: 7584390 : ctx->dif_pi_format);
1443 [ # # ]: 10089919 : guard = _dif_generate_guard(guard, src + data_block_size,
1444 [ # # # # : 7584390 : ctx->guard_interval - data_block_size, ctx->dif_pi_format);
# # # # ]
1445 : 2505529 : } else {
1446 [ - + - + ]: 702 : memcpy(dst, src, data_block_size);
1447 : : }
1448 : :
1449 [ # # # # : 7585092 : rc = _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
# # ]
1450 [ + + ]: 7585092 : if (rc != 0) {
1451 : 41378 : return rc;
1452 : : }
1453 : :
1454 [ # # # # ]: 7543714 : _dif_sgl_advance(src_sgl, ctx->block_size);
1455 : 7543714 : _dif_sgl_advance(dst_sgl, data_block_size);
1456 : :
1457 : 7543714 : return 0;
1458 : 2505679 : }
1459 : :
1460 : : static int
1461 : 976730 : dif_strip_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1462 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1463 : : struct spdk_dif_error *err_blk)
1464 : : {
1465 : : uint32_t offset_blocks;
1466 : : int rc;
1467 : :
1468 [ + + ]: 8509673 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1469 : 7533048 : rc = _dif_strip_copy(src_sgl, dst_sgl, offset_blocks, ctx, err_blk);
1470 [ + + ]: 7533048 : if (rc != 0) {
1471 : 105 : return rc;
1472 : : }
1473 : 2453611 : }
1474 : :
1475 : 976625 : return 0;
1476 : 341785 : }
1477 : :
1478 : : static int
1479 : 244 : _dif_strip_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1480 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx,
1481 : : struct spdk_dif_error *err_blk)
1482 : : {
1483 : : uint32_t data_block_size;
1484 : 244 : uint64_t guard = 0;
1485 : 244 : struct spdk_dif dif = {};
1486 : :
1487 [ # # # # : 244 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1488 : :
1489 [ + - # # : 244 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1490 [ # # # # ]: 311 : guard = _dif_generate_guard_copy_split(ctx->guard_seed, dst_sgl, src_sgl,
1491 [ # # # # ]: 244 : data_block_size, ctx->dif_pi_format);
1492 : 311 : guard = dif_generate_guard_split(guard, src_sgl, data_block_size,
1493 [ # # # # ]: 244 : ctx->guard_interval - data_block_size, ctx);
1494 : 67 : } else {
1495 : 0 : _data_copy_split(dst_sgl, src_sgl, data_block_size);
1496 [ # # # # ]: 0 : _dif_sgl_advance(src_sgl, ctx->guard_interval - data_block_size);
1497 : : }
1498 : :
1499 : 244 : dif_load_split(src_sgl, &dif, ctx);
1500 : :
1501 : 244 : return _dif_verify(&dif, guard, offset_blocks, ctx, err_blk);
1502 : : }
1503 : :
1504 : : static int
1505 : 124 : dif_strip_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1506 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1507 : : struct spdk_dif_error *err_blk)
1508 : : {
1509 : : uint32_t offset_blocks;
1510 : : int rc;
1511 : :
1512 [ + + ]: 272 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1513 : 244 : rc = _dif_strip_copy_split(src_sgl, dst_sgl, offset_blocks, ctx, err_blk);
1514 [ + + ]: 244 : if (rc != 0) {
1515 : 96 : return rc;
1516 : : }
1517 : 43 : }
1518 : :
1519 : 28 : return 0;
1520 : 31 : }
1521 : :
1522 : : static void
1523 : 48 : _dif_disable_strip_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1524 : : const struct spdk_dif_ctx *ctx)
1525 : : {
1526 : 48 : uint32_t offset = 0, src_len, dst_len, buf_len, data_block_size;
1527 : 36 : uint8_t *src, *dst;
1528 : :
1529 [ # # # # : 48 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1530 : :
1531 [ + + ]: 128 : while (offset < data_block_size) {
1532 : 80 : _dif_sgl_get_buf(src_sgl, &src, &src_len);
1533 : 80 : _dif_sgl_get_buf(dst_sgl, &dst, &dst_len);
1534 [ + + ]: 80 : buf_len = spdk_min(src_len, dst_len);
1535 [ + + ]: 80 : buf_len = spdk_min(buf_len, data_block_size - offset);
1536 : :
1537 [ - + - + ]: 80 : memcpy(dst, src, buf_len);
1538 : :
1539 : 80 : _dif_sgl_advance(src_sgl, buf_len);
1540 : 80 : _dif_sgl_advance(dst_sgl, buf_len);
1541 : 80 : offset += buf_len;
1542 : : }
1543 : :
1544 [ # # # # ]: 48 : _dif_sgl_advance(src_sgl, ctx->md_size);
1545 : 48 : }
1546 : :
1547 : : static void
1548 : 12 : dif_disable_strip_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1549 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1550 : : {
1551 : : uint32_t offset_blocks;
1552 : :
1553 [ + + ]: 60 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1554 : 48 : _dif_disable_strip_copy(src_sgl, dst_sgl, ctx);
1555 : 12 : }
1556 : 12 : }
1557 : :
1558 : : static int
1559 : 981435 : _spdk_dif_strip_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1560 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1561 : : struct spdk_dif_error *err_blk)
1562 : : {
1563 : : uint32_t data_block_size;
1564 : :
1565 [ # # # # : 981435 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1566 : :
1567 [ + + + + ]: 981435 : if (!_dif_sgl_is_valid(dst_sgl, data_block_size * num_blocks) ||
1568 [ - + # # ]: 979104 : !_dif_sgl_is_valid(src_sgl, ctx->block_size * num_blocks)) {
1569 : 4662 : SPDK_ERRLOG("Size of iovec arrays are not valid\n");
1570 : 4662 : return -EINVAL;
1571 : : }
1572 : :
1573 [ + + # # : 981435 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
1574 : 12 : dif_disable_strip_copy(src_sgl, dst_sgl, num_blocks, ctx);
1575 : 12 : return 0;
1576 : : }
1577 : :
1578 [ + + + + ]: 1616368 : if (_dif_sgl_is_bytes_multiple(dst_sgl, data_block_size) &&
1579 [ # # # # ]: 978281 : _dif_sgl_is_bytes_multiple(src_sgl, ctx->block_size)) {
1580 : 975263 : return dif_strip_copy(src_sgl, dst_sgl, num_blocks, ctx, err_blk);
1581 : : } else {
1582 : 6160 : return dif_strip_copy_split(src_sgl, dst_sgl, num_blocks, ctx, err_blk);
1583 : : }
1584 : 340352 : }
1585 : :
1586 : : static int
1587 : 384 : _dif_verify_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1588 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx,
1589 : : struct spdk_dif_error *err_blk)
1590 : : {
1591 : 288 : uint8_t *src, *dst;
1592 : : int rc;
1593 : 384 : uint64_t guard = 0;
1594 : :
1595 : 384 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1596 : 384 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1597 : :
1598 [ + + # # : 384 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1599 [ # # # # : 120 : guard = _dif_generate_guard_copy(ctx->guard_seed, dst, src, ctx->guard_interval,
# # # # ]
1600 [ # # # # ]: 96 : ctx->dif_pi_format);
1601 : 24 : } else {
1602 [ - + - + : 288 : memcpy(dst, src, ctx->guard_interval);
# # # # ]
1603 : : }
1604 : :
1605 [ # # # # : 384 : rc = _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
# # ]
1606 [ + + ]: 384 : if (rc != 0) {
1607 : 0 : return rc;
1608 : : }
1609 : :
1610 [ # # # # ]: 384 : _dif_sgl_advance(src_sgl, ctx->block_size);
1611 [ # # # # ]: 384 : _dif_sgl_advance(dst_sgl, ctx->block_size);
1612 : :
1613 : 384 : return 0;
1614 : 96 : }
1615 : :
1616 : : static int
1617 : 64 : dif_verify_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1618 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1619 : : struct spdk_dif_error *err_blk)
1620 : : {
1621 : : uint32_t offset_blocks;
1622 : : int rc;
1623 : :
1624 [ + + ]: 448 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1625 : 384 : rc = _dif_verify_copy(src_sgl, dst_sgl, offset_blocks, ctx, err_blk);
1626 [ - + ]: 384 : if (rc != 0) {
1627 : 0 : return rc;
1628 : : }
1629 : 96 : }
1630 : :
1631 : 64 : return 0;
1632 : 16 : }
1633 : :
1634 : : static int
1635 : 32 : _dif_verify_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1636 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx,
1637 : : struct spdk_dif_error *err_blk)
1638 : : {
1639 : 32 : uint64_t guard = 0;
1640 : 32 : struct spdk_dif dif = {};
1641 : :
1642 [ + - # # : 32 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1643 [ # # # # ]: 40 : guard = _dif_generate_guard_copy_split(ctx->guard_seed, dst_sgl, src_sgl,
1644 [ # # # # : 32 : ctx->guard_interval, ctx->dif_pi_format);
# # # # ]
1645 : 8 : } else {
1646 [ # # # # ]: 0 : _data_copy_split(dst_sgl, src_sgl, ctx->guard_interval);
1647 : : }
1648 : :
1649 : 32 : dif_load_split(src_sgl, &dif, ctx);
1650 [ # # # # : 32 : _dif_sgl_advance(dst_sgl, ctx->block_size - ctx->guard_interval);
# # # # ]
1651 : :
1652 : 32 : return _dif_verify(&dif, guard, offset_blocks, ctx, err_blk);
1653 : : }
1654 : :
1655 : : static int
1656 : 8 : dif_verify_copy_split(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1657 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1658 : : struct spdk_dif_error *err_blk)
1659 : : {
1660 : : uint32_t offset_blocks;
1661 : : int rc;
1662 : :
1663 [ + + ]: 40 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1664 : 32 : rc = _dif_verify_copy_split(src_sgl, dst_sgl, offset_blocks, ctx, err_blk);
1665 [ - + ]: 32 : if (rc != 0) {
1666 : 0 : return rc;
1667 : : }
1668 : 8 : }
1669 : :
1670 : 8 : return 0;
1671 : 2 : }
1672 : :
1673 : : static int
1674 : 72 : _spdk_dif_verify_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1675 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1676 : : struct spdk_dif_error *err_blk)
1677 : : {
1678 [ + - - + : 72 : if (!_dif_sgl_is_valid(dst_sgl, ctx->block_size * num_blocks) ||
# # # # ]
1679 [ - + # # ]: 72 : !_dif_sgl_is_valid(src_sgl, ctx->block_size * num_blocks)) {
1680 : 0 : SPDK_ERRLOG("Size of iovec arrays are not valid\n");
1681 : 0 : return -EINVAL;
1682 : : }
1683 : :
1684 [ - + # # : 72 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
1685 : 0 : dif_disable_copy(src_sgl, dst_sgl, num_blocks, ctx);
1686 : 0 : return 0;
1687 : : }
1688 : :
1689 [ + + + - : 120 : if (_dif_sgl_is_bytes_multiple(dst_sgl, ctx->block_size) &&
# # # # ]
1690 [ # # # # ]: 64 : _dif_sgl_is_bytes_multiple(src_sgl, ctx->block_size)) {
1691 : 64 : return dif_verify_copy(src_sgl, dst_sgl, num_blocks, ctx, err_blk);
1692 : : } else {
1693 : 8 : return dif_verify_copy_split(src_sgl, dst_sgl, num_blocks, ctx, err_blk);
1694 : : }
1695 : 18 : }
1696 : :
1697 : : int
1698 : 979226 : spdk_dif_verify_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iovs,
1699 : : int bounce_iovcnt, uint32_t num_blocks,
1700 : : const struct spdk_dif_ctx *ctx,
1701 : : struct spdk_dif_error *err_blk)
1702 : : {
1703 : 476960 : struct _dif_sgl src_sgl, dst_sgl;
1704 : :
1705 : 979226 : _dif_sgl_init(&src_sgl, bounce_iovs, bounce_iovcnt);
1706 : 979226 : _dif_sgl_init(&dst_sgl, iovs, iovcnt);
1707 : :
1708 [ + + - + : 979280 : if (!(ctx->dif_flags & SPDK_DIF_FLAGS_NVME_PRACT) ||
# # # # #
# ]
1709 [ # # # # : 72 : ctx->md_size == _dif_size(ctx->dif_pi_format)) {
# # # # ]
1710 : 979154 : return _spdk_dif_strip_copy(&src_sgl, &dst_sgl, num_blocks, ctx, err_blk);
1711 : : } else {
1712 : 72 : return _spdk_dif_verify_copy(&src_sgl, &dst_sgl, num_blocks, ctx, err_blk);
1713 : : }
1714 : 344125 : }
1715 : :
1716 : : static void
1717 : 960 : _bit_flip(uint8_t *buf, uint32_t flip_bit)
1718 : : {
1719 : : uint8_t byte;
1720 : :
1721 [ # # ]: 960 : byte = *buf;
1722 [ - + # # ]: 960 : byte ^= 1 << flip_bit;
1723 [ # # ]: 960 : *buf = byte;
1724 : 960 : }
1725 : :
1726 : : static int
1727 : 960 : _dif_inject_error(struct _dif_sgl *sgl,
1728 : : uint32_t block_size, uint32_t num_blocks,
1729 : : uint32_t inject_offset_blocks,
1730 : : uint32_t inject_offset_bytes,
1731 : : uint32_t inject_offset_bits)
1732 : : {
1733 : 720 : uint32_t offset_in_block, buf_len;
1734 : 720 : uint8_t *buf;
1735 : :
1736 : 960 : _dif_sgl_advance(sgl, block_size * inject_offset_blocks);
1737 : :
1738 : 960 : offset_in_block = 0;
1739 : :
1740 [ + - ]: 1308 : while (offset_in_block < block_size) {
1741 : 1308 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
1742 [ + + ]: 1308 : buf_len = spdk_min(buf_len, block_size - offset_in_block);
1743 : :
1744 [ + - + + ]: 1308 : if (inject_offset_bytes >= offset_in_block &&
1745 [ + + ]: 1308 : inject_offset_bytes < offset_in_block + buf_len) {
1746 [ # # ]: 960 : buf += inject_offset_bytes - offset_in_block;
1747 : 960 : _bit_flip(buf, inject_offset_bits);
1748 : 960 : return 0;
1749 : : }
1750 : :
1751 : 348 : _dif_sgl_advance(sgl, buf_len);
1752 : 348 : offset_in_block += buf_len;
1753 : : }
1754 : :
1755 : 0 : return -1;
1756 : 240 : }
1757 : :
1758 : : static int
1759 : 960 : dif_inject_error(struct _dif_sgl *sgl, uint32_t block_size, uint32_t num_blocks,
1760 : : uint32_t start_inject_bytes, uint32_t inject_range_bytes,
1761 : : uint32_t *inject_offset)
1762 : : {
1763 : : uint32_t inject_offset_blocks, inject_offset_bytes, inject_offset_bits;
1764 : : uint32_t offset_blocks;
1765 : : int rc;
1766 : :
1767 : 960 : srand(time(0));
1768 : :
1769 [ - + ]: 960 : inject_offset_blocks = rand() % num_blocks;
1770 [ - + ]: 960 : inject_offset_bytes = start_inject_bytes + (rand() % inject_range_bytes);
1771 [ # # ]: 960 : inject_offset_bits = rand() % 8;
1772 : :
1773 [ + - ]: 3048 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1774 [ + + ]: 3048 : if (offset_blocks == inject_offset_blocks) {
1775 : 1200 : rc = _dif_inject_error(sgl, block_size, num_blocks,
1776 : 240 : inject_offset_blocks,
1777 : 240 : inject_offset_bytes,
1778 : 240 : inject_offset_bits);
1779 [ + + ]: 960 : if (rc == 0) {
1780 [ # # ]: 960 : *inject_offset = inject_offset_blocks;
1781 : 240 : }
1782 : 960 : return rc;
1783 : : }
1784 : 696 : }
1785 : :
1786 : 0 : return -1;
1787 : 240 : }
1788 : :
1789 : : int
1790 : 768 : spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
1791 : : const struct spdk_dif_ctx *ctx, uint32_t inject_flags,
1792 : : uint32_t *inject_offset)
1793 : : {
1794 : 576 : struct _dif_sgl sgl;
1795 : : int rc;
1796 : :
1797 : 768 : _dif_sgl_init(&sgl, iovs, iovcnt);
1798 : :
1799 [ - + # # : 768 : if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) {
# # ]
1800 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
1801 : 0 : return -EINVAL;
1802 : : }
1803 : :
1804 [ + + ]: 768 : if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
1805 [ # # # # ]: 288 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1806 [ # # # # : 192 : ctx->guard_interval + _dif_reftag_offset(ctx->dif_pi_format),
# # # # ]
1807 [ # # # # ]: 192 : _dif_reftag_size(ctx->dif_pi_format),
1808 : 48 : inject_offset);
1809 [ - + ]: 192 : if (rc != 0) {
1810 : 0 : SPDK_ERRLOG("Failed to inject error to Reference Tag.\n");
1811 : 0 : return rc;
1812 : : }
1813 : 48 : }
1814 : :
1815 [ + + ]: 768 : if (inject_flags & SPDK_DIF_APPTAG_ERROR) {
1816 [ # # # # ]: 288 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1817 [ # # # # : 192 : ctx->guard_interval + _dif_apptag_offset(ctx->dif_pi_format),
# # # # ]
1818 : 192 : _dif_apptag_size(),
1819 : 48 : inject_offset);
1820 [ - + ]: 192 : if (rc != 0) {
1821 : 0 : SPDK_ERRLOG("Failed to inject error to Application Tag.\n");
1822 : 0 : return rc;
1823 : : }
1824 : 48 : }
1825 [ + + ]: 768 : if (inject_flags & SPDK_DIF_GUARD_ERROR) {
1826 [ # # # # ]: 240 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1827 [ # # # # ]: 192 : ctx->guard_interval,
1828 [ # # # # ]: 192 : _dif_guard_size(ctx->dif_pi_format),
1829 : 48 : inject_offset);
1830 [ - + ]: 192 : if (rc != 0) {
1831 : 0 : SPDK_ERRLOG("Failed to inject error to Guard.\n");
1832 : 0 : return rc;
1833 : : }
1834 : 48 : }
1835 : :
1836 [ + + ]: 768 : if (inject_flags & SPDK_DIF_DATA_ERROR) {
1837 : : /* If the DIF information is contained within the last 8/16 bytes of
1838 : : * metadata (depending on the PI format), then the CRC covers all metadata
1839 : : * bytes up to but excluding the last 8/16 bytes. But error injection does not
1840 : : * cover these metadata because classification is not determined yet.
1841 : : *
1842 : : * Note: Error injection to data block is expected to be detected as
1843 : : * guard error.
1844 : : */
1845 [ # # # # ]: 240 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1846 : : 0,
1847 [ # # # # : 192 : ctx->block_size - ctx->md_size,
# # # # ]
1848 : 48 : inject_offset);
1849 [ + + ]: 192 : if (rc != 0) {
1850 : 0 : SPDK_ERRLOG("Failed to inject error to data block.\n");
1851 : 0 : return rc;
1852 : : }
1853 : 48 : }
1854 : :
1855 : 768 : return 0;
1856 : 192 : }
1857 : :
1858 : : static void
1859 : 404 : dix_generate(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl,
1860 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1861 : : {
1862 : 404 : uint32_t offset_blocks = 0;
1863 : 238 : uint8_t *data_buf, *md_buf;
1864 : : uint64_t guard;
1865 : :
1866 [ + + ]: 4852 : while (offset_blocks < num_blocks) {
1867 : 4448 : _dif_sgl_get_buf(data_sgl, &data_buf, NULL);
1868 : 4448 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1869 : :
1870 : 4448 : guard = 0;
1871 [ + + # # : 4448 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1872 [ # # # # : 4366 : guard = _dif_generate_guard(ctx->guard_seed, data_buf, ctx->block_size,
# # # # ]
1873 [ # # # # ]: 3728 : ctx->dif_pi_format);
1874 [ # # # # ]: 4366 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1875 [ # # # # ]: 3728 : ctx->dif_pi_format);
1876 : 638 : }
1877 : :
1878 [ # # # # : 4448 : _dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx);
# # ]
1879 : :
1880 [ # # # # ]: 4448 : _dif_sgl_advance(data_sgl, ctx->block_size);
1881 [ # # # # ]: 4448 : _dif_sgl_advance(md_sgl, ctx->md_size);
1882 : 4448 : offset_blocks++;
1883 : : }
1884 : 404 : }
1885 : :
1886 : : static void
1887 : 300 : _dix_generate_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl,
1888 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
1889 : : {
1890 : 225 : uint32_t offset_in_block, data_buf_len;
1891 : 225 : uint8_t *data_buf, *md_buf;
1892 : 300 : uint64_t guard = 0;
1893 : :
1894 : 300 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1895 : :
1896 [ + + # # : 300 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1897 [ # # # # ]: 300 : guard = ctx->guard_seed;
1898 : 75 : }
1899 : 300 : offset_in_block = 0;
1900 : :
1901 [ + + # # : 924 : while (offset_in_block < ctx->block_size) {
# # ]
1902 : 624 : _dif_sgl_get_buf(data_sgl, &data_buf, &data_buf_len);
1903 [ + + # # : 624 : data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block);
# # # # #
# ]
1904 : :
1905 [ + + # # : 624 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1906 : 780 : guard = _dif_generate_guard(guard, data_buf, data_buf_len,
1907 [ # # # # ]: 624 : ctx->dif_pi_format);
1908 : 156 : }
1909 : :
1910 : 624 : _dif_sgl_advance(data_sgl, data_buf_len);
1911 : 624 : offset_in_block += data_buf_len;
1912 : : }
1913 : :
1914 [ + + # # : 300 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1915 [ # # # # ]: 375 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1916 [ # # # # ]: 300 : ctx->dif_pi_format);
1917 : 75 : }
1918 : :
1919 [ # # # # ]: 300 : _dif_sgl_advance(md_sgl, ctx->md_size);
1920 : :
1921 [ # # # # : 300 : _dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx);
# # ]
1922 : 300 : }
1923 : :
1924 : : static void
1925 : 132 : dix_generate_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl,
1926 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1927 : : {
1928 : : uint32_t offset_blocks;
1929 : :
1930 [ + + ]: 432 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1931 : 300 : _dix_generate_split(data_sgl, md_sgl, offset_blocks, ctx);
1932 : 75 : }
1933 : 132 : }
1934 : :
1935 : : int
1936 : 11800 : spdk_dix_generate(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1937 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1938 : : {
1939 : 11601 : struct _dif_sgl data_sgl, md_sgl;
1940 : :
1941 : 11800 : _dif_sgl_init(&data_sgl, iovs, iovcnt);
1942 : 11800 : _dif_sgl_init(&md_sgl, md_iov, 1);
1943 : :
1944 [ + - - + : 11800 : if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) ||
# # # # ]
1945 [ - + # # ]: 11800 : !_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) {
1946 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
1947 : 0 : return -EINVAL;
1948 : : }
1949 : :
1950 [ + + # # : 11800 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
1951 : 11264 : return 0;
1952 : : }
1953 : :
1954 [ + + # # : 536 : if (_dif_sgl_is_bytes_multiple(&data_sgl, ctx->block_size)) {
# # ]
1955 : 404 : dix_generate(&data_sgl, &md_sgl, num_blocks, ctx);
1956 : 62 : } else {
1957 : 132 : dix_generate_split(&data_sgl, &md_sgl, num_blocks, ctx);
1958 : : }
1959 : :
1960 : 536 : return 0;
1961 : 95 : }
1962 : :
1963 : : static int
1964 : 245224 : dix_verify(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl,
1965 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1966 : : struct spdk_dif_error *err_blk)
1967 : : {
1968 : 245224 : uint32_t offset_blocks = 0;
1969 : 74493 : uint8_t *data_buf, *md_buf;
1970 : : uint64_t guard;
1971 : : int rc;
1972 : :
1973 [ + + ]: 2208416 : while (offset_blocks < num_blocks) {
1974 : 1963315 : _dif_sgl_get_buf(data_sgl, &data_buf, NULL);
1975 : 1963315 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1976 : :
1977 : 1963315 : guard = 0;
1978 [ + + # # : 1963315 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1979 [ # # # # : 1963397 : guard = _dif_generate_guard(ctx->guard_seed, data_buf, ctx->block_size,
# # # # ]
1980 [ # # # # ]: 1962535 : ctx->dif_pi_format);
1981 [ # # # # ]: 1963397 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1982 [ # # # # ]: 1962535 : ctx->dif_pi_format);
1983 : 862 : }
1984 : :
1985 [ # # # # : 1963315 : rc = _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
# # ]
1986 [ + + ]: 1963315 : if (rc != 0) {
1987 : 123 : return rc;
1988 : : }
1989 : :
1990 [ # # # # ]: 1963192 : _dif_sgl_advance(data_sgl, ctx->block_size);
1991 [ # # # # ]: 1963192 : _dif_sgl_advance(md_sgl, ctx->md_size);
1992 : 1963192 : offset_blocks++;
1993 : : }
1994 : :
1995 : 245101 : return 0;
1996 : 67 : }
1997 : :
1998 : : static int
1999 : 276 : _dix_verify_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl,
2000 : : uint32_t offset_blocks, const struct spdk_dif_ctx *ctx,
2001 : : struct spdk_dif_error *err_blk)
2002 : : {
2003 : 201 : uint32_t offset_in_block, data_buf_len;
2004 : 201 : uint8_t *data_buf, *md_buf;
2005 : 276 : uint64_t guard = 0;
2006 : :
2007 : 276 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
2008 : :
2009 [ + + # # : 276 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2010 [ # # # # ]: 276 : guard = ctx->guard_seed;
2011 : 75 : }
2012 : 276 : offset_in_block = 0;
2013 : :
2014 [ + + # # : 852 : while (offset_in_block < ctx->block_size) {
# # ]
2015 : 576 : _dif_sgl_get_buf(data_sgl, &data_buf, &data_buf_len);
2016 [ + + # # : 576 : data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block);
# # # # #
# ]
2017 : :
2018 [ + + # # : 576 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2019 : 732 : guard = _dif_generate_guard(guard, data_buf, data_buf_len,
2020 [ # # # # ]: 576 : ctx->dif_pi_format);
2021 : 156 : }
2022 : :
2023 : 576 : _dif_sgl_advance(data_sgl, data_buf_len);
2024 : 576 : offset_in_block += data_buf_len;
2025 : : }
2026 : :
2027 [ + + # # : 276 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2028 [ # # # # ]: 351 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
2029 [ # # # # ]: 276 : ctx->dif_pi_format);
2030 : 75 : }
2031 : :
2032 [ # # # # ]: 276 : _dif_sgl_advance(md_sgl, ctx->md_size);
2033 : :
2034 [ # # # # : 276 : return _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
# # ]
2035 : : }
2036 : :
2037 : : static int
2038 : 132 : dix_verify_split(struct _dif_sgl *data_sgl, struct _dif_sgl *md_sgl,
2039 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
2040 : : struct spdk_dif_error *err_blk)
2041 : : {
2042 : : uint32_t offset_blocks;
2043 : : int rc;
2044 : :
2045 [ + + ]: 312 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
2046 : 276 : rc = _dix_verify_split(data_sgl, md_sgl, offset_blocks, ctx, err_blk);
2047 [ + + ]: 276 : if (rc != 0) {
2048 : 96 : return rc;
2049 : : }
2050 : 51 : }
2051 : :
2052 : 36 : return 0;
2053 : 33 : }
2054 : :
2055 : : int
2056 : 413596 : spdk_dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
2057 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
2058 : : struct spdk_dif_error *err_blk)
2059 : : {
2060 : 242832 : struct _dif_sgl data_sgl, md_sgl;
2061 : :
2062 [ + + # # : 413596 : if (md_iov->iov_base == NULL) {
# # ]
2063 : 0 : SPDK_ERRLOG("Metadata buffer is NULL.\n");
2064 : 0 : return -EINVAL;
2065 : : }
2066 : :
2067 : 413596 : _dif_sgl_init(&data_sgl, iovs, iovcnt);
2068 : 413596 : _dif_sgl_init(&md_sgl, md_iov, 1);
2069 : :
2070 [ + - - + : 413596 : if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) ||
# # # # ]
2071 [ - + # # ]: 413596 : !_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) {
2072 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
2073 : 0 : return -EINVAL;
2074 : : }
2075 : :
2076 [ + + # # : 413596 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
2077 : 168240 : return 0;
2078 : : }
2079 : :
2080 [ + + # # : 245356 : if (_dif_sgl_is_bytes_multiple(&data_sgl, ctx->block_size)) {
# # ]
2081 : 245224 : return dix_verify(&data_sgl, &md_sgl, num_blocks, ctx, err_blk);
2082 : : } else {
2083 : 132 : return dix_verify_split(&data_sgl, &md_sgl, num_blocks, ctx, err_blk);
2084 : : }
2085 : 100 : }
2086 : :
2087 : : int
2088 : 192 : spdk_dix_inject_error(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
2089 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
2090 : : uint32_t inject_flags, uint32_t *inject_offset)
2091 : : {
2092 : 144 : struct _dif_sgl data_sgl, md_sgl;
2093 : : int rc;
2094 : :
2095 : 192 : _dif_sgl_init(&data_sgl, iovs, iovcnt);
2096 : 192 : _dif_sgl_init(&md_sgl, md_iov, 1);
2097 : :
2098 [ + - - + : 192 : if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) ||
# # # # ]
2099 [ - + # # ]: 192 : !_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) {
2100 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
2101 : 0 : return -EINVAL;
2102 : : }
2103 : :
2104 [ + + ]: 192 : if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
2105 [ # # # # ]: 72 : rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks,
2106 [ # # # # : 48 : ctx->guard_interval + _dif_reftag_offset(ctx->dif_pi_format),
# # # # ]
2107 [ # # # # ]: 48 : _dif_reftag_size(ctx->dif_pi_format),
2108 : 12 : inject_offset);
2109 [ - + ]: 48 : if (rc != 0) {
2110 : 0 : SPDK_ERRLOG("Failed to inject error to Reference Tag.\n");
2111 : 0 : return rc;
2112 : : }
2113 : 12 : }
2114 : :
2115 [ + + ]: 192 : if (inject_flags & SPDK_DIF_APPTAG_ERROR) {
2116 [ # # # # ]: 72 : rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks,
2117 [ # # # # : 48 : ctx->guard_interval + _dif_apptag_offset(ctx->dif_pi_format),
# # # # ]
2118 : 48 : _dif_apptag_size(),
2119 : 12 : inject_offset);
2120 [ - + ]: 48 : if (rc != 0) {
2121 : 0 : SPDK_ERRLOG("Failed to inject error to Application Tag.\n");
2122 : 0 : return rc;
2123 : : }
2124 : 12 : }
2125 : :
2126 [ + + ]: 192 : if (inject_flags & SPDK_DIF_GUARD_ERROR) {
2127 [ # # # # ]: 60 : rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks,
2128 [ # # # # ]: 48 : ctx->guard_interval,
2129 [ # # # # ]: 48 : _dif_guard_size(ctx->dif_pi_format),
2130 : 12 : inject_offset);
2131 [ - + ]: 48 : if (rc != 0) {
2132 : 0 : SPDK_ERRLOG("Failed to inject error to Guard.\n");
2133 : 0 : return rc;
2134 : : }
2135 : 12 : }
2136 : :
2137 [ + + ]: 192 : if (inject_flags & SPDK_DIF_DATA_ERROR) {
2138 : : /* Note: Error injection to data block is expected to be detected
2139 : : * as guard error.
2140 : : */
2141 [ # # # # ]: 60 : rc = dif_inject_error(&data_sgl, ctx->block_size, num_blocks,
2142 : : 0,
2143 [ # # # # ]: 48 : ctx->block_size,
2144 : 12 : inject_offset);
2145 [ + + ]: 48 : if (rc != 0) {
2146 : 0 : SPDK_ERRLOG("Failed to inject error to Guard.\n");
2147 : 0 : return rc;
2148 : : }
2149 : 12 : }
2150 : :
2151 : 192 : return 0;
2152 : 48 : }
2153 : :
2154 : : static uint32_t
2155 : 95781950 : _to_next_boundary(uint32_t offset, uint32_t boundary)
2156 : : {
2157 [ - + ]: 95781950 : return boundary - (offset % boundary);
2158 : : }
2159 : :
2160 : : static uint32_t
2161 : 8467942 : _to_size_with_md(uint32_t size, uint32_t data_block_size, uint32_t block_size)
2162 : : {
2163 [ - + - + ]: 8467942 : return (size / data_block_size) * block_size + (size % data_block_size);
2164 : : }
2165 : :
2166 : : int
2167 : 1736964 : spdk_dif_set_md_interleave_iovs(struct iovec *iovs, int iovcnt,
2168 : : struct iovec *buf_iovs, int buf_iovcnt,
2169 : : uint32_t data_offset, uint32_t data_len,
2170 : : uint32_t *_mapped_len,
2171 : : const struct spdk_dif_ctx *ctx)
2172 : : {
2173 : : uint32_t data_block_size, data_unalign, buf_len, buf_offset, len;
2174 : 114 : struct _dif_sgl dif_sgl;
2175 : 114 : struct _dif_sgl buf_sgl;
2176 : :
2177 [ + - + - : 1736964 : if (iovs == NULL || iovcnt == 0 || buf_iovs == NULL || buf_iovcnt == 0) {
+ - - + ]
2178 : 0 : return -EINVAL;
2179 : : }
2180 : :
2181 [ # # # # : 1736964 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
2182 : :
2183 [ - + # # : 1736964 : data_unalign = ctx->data_offset % data_block_size;
# # ]
2184 : :
2185 : 1737002 : buf_len = _to_size_with_md(data_unalign + data_offset + data_len, data_block_size,
2186 [ # # # # ]: 1736964 : ctx->block_size);
2187 : 1736964 : buf_len -= data_unalign;
2188 : :
2189 : 1736964 : _dif_sgl_init(&dif_sgl, iovs, iovcnt);
2190 : 1736964 : _dif_sgl_init(&buf_sgl, buf_iovs, buf_iovcnt);
2191 : :
2192 [ + + ]: 1736964 : if (!_dif_sgl_is_valid(&buf_sgl, buf_len)) {
2193 : 4 : SPDK_ERRLOG("Buffer overflow will occur.\n");
2194 : 4 : return -ERANGE;
2195 : : }
2196 : :
2197 [ # # # # ]: 1736960 : buf_offset = _to_size_with_md(data_unalign + data_offset, data_block_size, ctx->block_size);
2198 : 1736960 : buf_offset -= data_unalign;
2199 : :
2200 : 1736960 : _dif_sgl_advance(&buf_sgl, buf_offset);
2201 : :
2202 [ + + ]: 29654114 : while (data_len != 0) {
2203 [ + + # # : 28279436 : len = spdk_min(data_len, _to_next_boundary(ctx->data_offset + data_offset, data_block_size));
# # # # #
# ]
2204 [ + + ]: 28279436 : if (!_dif_sgl_append_split(&dif_sgl, &buf_sgl, len)) {
2205 : 362282 : break;
2206 : : }
2207 [ # # # # ]: 27917154 : _dif_sgl_advance(&buf_sgl, ctx->md_size);
2208 : 27917154 : data_offset += len;
2209 : 27917154 : data_len -= len;
2210 : : }
2211 : :
2212 [ + + ]: 1736960 : if (_mapped_len != NULL) {
2213 [ # # # # ]: 1736960 : *_mapped_len = dif_sgl.total_size;
2214 : 37 : }
2215 : :
2216 [ # # # # ]: 1736960 : return iovcnt - dif_sgl.iovcnt;
2217 : 38 : }
2218 : :
2219 : : static int
2220 : 1061046 : _dif_sgl_setup_stream(struct _dif_sgl *sgl, uint32_t *_buf_offset, uint32_t *_buf_len,
2221 : : uint32_t data_offset, uint32_t data_len,
2222 : : const struct spdk_dif_ctx *ctx)
2223 : : {
2224 : : uint32_t data_block_size, data_unalign, buf_len, buf_offset;
2225 : :
2226 [ # # # # : 1061046 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
2227 : :
2228 [ - + # # : 1061046 : data_unalign = ctx->data_offset % data_block_size;
# # ]
2229 : :
2230 : : /* If the last data block is complete, DIF of the data block is
2231 : : * inserted or verified in this turn.
2232 : : */
2233 : 1061113 : buf_len = _to_size_with_md(data_unalign + data_offset + data_len, data_block_size,
2234 [ # # # # ]: 1061046 : ctx->block_size);
2235 : 1061046 : buf_len -= data_unalign;
2236 : :
2237 [ + + ]: 1061046 : if (!_dif_sgl_is_valid(sgl, buf_len)) {
2238 : 12 : return -ERANGE;
2239 : : }
2240 : :
2241 [ # # # # ]: 1061034 : buf_offset = _to_size_with_md(data_unalign + data_offset, data_block_size, ctx->block_size);
2242 : 1061034 : buf_offset -= data_unalign;
2243 : :
2244 : 1061034 : _dif_sgl_advance(sgl, buf_offset);
2245 : 1061034 : buf_len -= buf_offset;
2246 : :
2247 : 1061034 : buf_offset += data_unalign;
2248 : :
2249 [ # # ]: 1061034 : *_buf_offset = buf_offset;
2250 [ # # ]: 1061034 : *_buf_len = buf_len;
2251 : :
2252 : 1061034 : return 0;
2253 : 67 : }
2254 : :
2255 : : int
2256 : 196 : spdk_dif_generate_stream(struct iovec *iovs, int iovcnt,
2257 : : uint32_t data_offset, uint32_t data_len,
2258 : : struct spdk_dif_ctx *ctx)
2259 : : {
2260 : 196 : uint32_t buf_len = 0, buf_offset = 0;
2261 : : uint32_t len, offset_in_block, offset_blocks;
2262 : 196 : uint64_t guard = 0;
2263 : 147 : struct _dif_sgl sgl;
2264 : : int rc;
2265 : :
2266 [ + - - + ]: 196 : if (iovs == NULL || iovcnt == 0) {
2267 : 0 : return -EINVAL;
2268 : : }
2269 : :
2270 [ + + # # : 196 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2271 [ # # # # ]: 196 : guard = ctx->last_guard;
2272 : 49 : }
2273 : :
2274 : 196 : _dif_sgl_init(&sgl, iovs, iovcnt);
2275 : :
2276 : 196 : rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx);
2277 [ + + ]: 196 : if (rc != 0) {
2278 : 12 : return rc;
2279 : : }
2280 : :
2281 [ + + ]: 488 : while (buf_len != 0) {
2282 [ + + # # : 304 : len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size));
# # # # #
# ]
2283 [ - + # # : 304 : offset_in_block = buf_offset % ctx->block_size;
# # ]
2284 [ - + # # : 304 : offset_blocks = buf_offset / ctx->block_size;
# # ]
2285 : :
2286 : 304 : guard = _dif_generate_split(&sgl, offset_in_block, len, guard, offset_blocks, ctx);
2287 : :
2288 : 304 : buf_len -= len;
2289 : 304 : buf_offset += len;
2290 : : }
2291 : :
2292 [ + + # # : 184 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2293 [ # # # # ]: 184 : ctx->last_guard = guard;
2294 : 46 : }
2295 : :
2296 : 184 : return 0;
2297 : 49 : }
2298 : :
2299 : : int
2300 : 868442 : spdk_dif_verify_stream(struct iovec *iovs, int iovcnt,
2301 : : uint32_t data_offset, uint32_t data_len,
2302 : : struct spdk_dif_ctx *ctx,
2303 : : struct spdk_dif_error *err_blk)
2304 : : {
2305 : 868442 : uint32_t buf_len = 0, buf_offset = 0;
2306 : : uint32_t len, offset_in_block, offset_blocks;
2307 : 868442 : uint64_t guard = 0;
2308 : 27 : struct _dif_sgl sgl;
2309 : 868442 : int rc = 0;
2310 : :
2311 [ + - - + ]: 868442 : if (iovs == NULL || iovcnt == 0) {
2312 : 0 : return -EINVAL;
2313 : : }
2314 : :
2315 [ + + # # : 868442 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2316 [ # # # # ]: 868442 : guard = ctx->last_guard;
2317 : 9 : }
2318 : :
2319 : 868442 : _dif_sgl_init(&sgl, iovs, iovcnt);
2320 : :
2321 : 868442 : rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx);
2322 [ - + ]: 868442 : if (rc != 0) {
2323 : 0 : return rc;
2324 : : }
2325 : :
2326 [ + + ]: 15008024 : while (buf_len != 0) {
2327 [ + + # # : 14139582 : len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size));
# # # # #
# ]
2328 [ - + # # : 14139582 : offset_in_block = buf_offset % ctx->block_size;
# # ]
2329 [ - + # # : 14139582 : offset_blocks = buf_offset / ctx->block_size;
# # ]
2330 : :
2331 : 14139600 : rc = _dif_verify_split(&sgl, offset_in_block, len, &guard, offset_blocks,
2332 : 18 : ctx, err_blk);
2333 [ + + ]: 14139582 : if (rc != 0) {
2334 : 0 : goto error;
2335 : : }
2336 : :
2337 : 14139582 : buf_len -= len;
2338 : 14139582 : buf_offset += len;
2339 : : }
2340 : :
2341 [ - + # # : 868451 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2342 [ # # # # ]: 868442 : ctx->last_guard = guard;
2343 : 9 : }
2344 : 27 : error:
2345 : 868442 : return rc;
2346 : 9 : }
2347 : :
2348 : : int
2349 : 192408 : spdk_dif_update_crc32c_stream(struct iovec *iovs, int iovcnt,
2350 : : uint32_t data_offset, uint32_t data_len,
2351 : : uint32_t *_crc32c, const struct spdk_dif_ctx *ctx)
2352 : : {
2353 : 192408 : uint32_t buf_len = 0, buf_offset = 0, len, offset_in_block;
2354 : : uint32_t crc32c;
2355 : 27 : struct _dif_sgl sgl;
2356 : : int rc;
2357 : :
2358 [ + - - + ]: 192408 : if (iovs == NULL || iovcnt == 0) {
2359 : 0 : return -EINVAL;
2360 : : }
2361 : :
2362 [ # # ]: 192408 : crc32c = *_crc32c;
2363 : 192408 : _dif_sgl_init(&sgl, iovs, iovcnt);
2364 : :
2365 : 192408 : rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx);
2366 [ + + ]: 192408 : if (rc != 0) {
2367 : 0 : return rc;
2368 : : }
2369 : :
2370 [ + + ]: 5664187 : while (buf_len != 0) {
2371 [ + + # # : 5471779 : len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size));
# # # # #
# ]
2372 [ - + # # : 5471779 : offset_in_block = buf_offset % ctx->block_size;
# # ]
2373 : :
2374 : 5471779 : crc32c = _dif_update_crc32c_split(&sgl, offset_in_block, len, crc32c, ctx);
2375 : :
2376 : 5471779 : buf_len -= len;
2377 : 5471779 : buf_offset += len;
2378 : : }
2379 : :
2380 [ # # ]: 192408 : *_crc32c = crc32c;
2381 : :
2382 : 192408 : return 0;
2383 : 9 : }
2384 : :
2385 : : void
2386 : 1135042 : spdk_dif_get_range_with_md(uint32_t data_offset, uint32_t data_len,
2387 : : uint32_t *_buf_offset, uint32_t *_buf_len,
2388 : : const struct spdk_dif_ctx *ctx)
2389 : : {
2390 : : uint32_t data_block_size, data_unalign, buf_offset, buf_len;
2391 : :
2392 [ + + - + : 1135042 : if (!ctx->md_interleave) {
# # # # ]
2393 : 0 : buf_offset = data_offset;
2394 : 0 : buf_len = data_len;
2395 : 0 : } else {
2396 [ # # # # : 1135042 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
2397 : :
2398 [ - + ]: 1135042 : data_unalign = data_offset % data_block_size;
2399 : :
2400 [ # # # # ]: 1135042 : buf_offset = _to_size_with_md(data_offset, data_block_size, ctx->block_size);
2401 [ # # # # ]: 1135052 : buf_len = _to_size_with_md(data_unalign + data_len, data_block_size, ctx->block_size) -
2402 : 10 : data_unalign;
2403 : : }
2404 : :
2405 [ + + ]: 1135042 : if (_buf_offset != NULL) {
2406 [ # # ]: 1135042 : *_buf_offset = buf_offset;
2407 : 10 : }
2408 : :
2409 [ + + ]: 1135042 : if (_buf_len != NULL) {
2410 [ # # ]: 1135042 : *_buf_len = buf_len;
2411 : 10 : }
2412 : 1135042 : }
2413 : :
2414 : : uint32_t
2415 : 601854 : spdk_dif_get_length_with_md(uint32_t data_len, const struct spdk_dif_ctx *ctx)
2416 : : {
2417 : : uint32_t data_block_size;
2418 : :
2419 [ - + - + : 601854 : if (!ctx->md_interleave) {
# # # # ]
2420 : 0 : return data_len;
2421 : : } else {
2422 [ # # # # : 601854 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
2423 : :
2424 [ # # # # ]: 601854 : return _to_size_with_md(data_len, data_block_size, ctx->block_size);
2425 : : }
2426 : 11 : }
2427 : :
2428 : : static int
2429 : 288 : _dif_remap_ref_tag(struct _dif_sgl *sgl, uint32_t offset_blocks,
2430 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk,
2431 : : bool check_ref_tag)
2432 : : {
2433 : 216 : uint32_t offset, buf_len;
2434 : 288 : uint64_t expected = 0, remapped;
2435 : 216 : uint8_t *buf;
2436 : 216 : struct _dif_sgl tmp_sgl;
2437 : 216 : struct spdk_dif dif;
2438 : :
2439 : : /* Fast forward to DIF field. */
2440 [ # # # # ]: 288 : _dif_sgl_advance(sgl, ctx->guard_interval);
2441 : 288 : _dif_sgl_copy(&tmp_sgl, sgl);
2442 : :
2443 : : /* Copy the split DIF field to the temporary DIF buffer */
2444 : 288 : offset = 0;
2445 [ + + # # : 648 : while (offset < _dif_size(ctx->dif_pi_format)) {
# # ]
2446 : 360 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
2447 [ + + # # : 360 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset);
# # # # #
# ]
2448 : :
2449 [ - + - + : 360 : memcpy((uint8_t *)&dif + offset, buf, buf_len);
# # ]
2450 : :
2451 : 360 : _dif_sgl_advance(sgl, buf_len);
2452 : 360 : offset += buf_len;
2453 : : }
2454 : :
2455 [ - + ]: 288 : if (_dif_ignore(&dif, ctx)) {
2456 : 0 : goto end;
2457 : : }
2458 : :
2459 : : /* For type 1 and 2, the Reference Tag is incremented for each
2460 : : * subsequent logical block. For type 3, the Reference Tag
2461 : : * remains the same as the initial Reference Tag.
2462 : : */
2463 [ + - # # : 288 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
# # ]
2464 [ # # # # : 288 : expected = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
# # # # ]
2465 [ # # # # : 288 : remapped = ctx->remapped_init_ref_tag + ctx->ref_tag_offset + offset_blocks;
# # # # ]
2466 : 72 : } else {
2467 [ # # # # ]: 0 : remapped = ctx->remapped_init_ref_tag;
2468 : : }
2469 : :
2470 : : /* Verify the stored Reference Tag. */
2471 [ + - + + : 288 : if (check_ref_tag && !_dif_reftag_check(&dif, ctx, expected, offset_blocks, err_blk)) {
# # ]
2472 : 0 : return -1;
2473 : : }
2474 : :
2475 : : /* Update the stored Reference Tag to the remapped one. */
2476 [ # # # # ]: 288 : _dif_set_reftag(&dif, remapped, ctx->dif_pi_format);
2477 : :
2478 : 288 : offset = 0;
2479 [ + + # # : 648 : while (offset < _dif_size(ctx->dif_pi_format)) {
# # ]
2480 : 360 : _dif_sgl_get_buf(&tmp_sgl, &buf, &buf_len);
2481 [ + + # # : 360 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset);
# # # # #
# ]
2482 : :
2483 [ - + - + : 360 : memcpy(buf, (uint8_t *)&dif + offset, buf_len);
# # ]
2484 : :
2485 : 360 : _dif_sgl_advance(&tmp_sgl, buf_len);
2486 : 360 : offset += buf_len;
2487 : : }
2488 : :
2489 : 216 : end:
2490 [ # # # # : 288 : _dif_sgl_advance(sgl, ctx->block_size - ctx->guard_interval - _dif_size(ctx->dif_pi_format));
# # # # #
# # # ]
2491 : :
2492 : 288 : return 0;
2493 : 72 : }
2494 : :
2495 : : int
2496 : 48 : spdk_dif_remap_ref_tag(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
2497 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk,
2498 : : bool check_ref_tag)
2499 : : {
2500 : 36 : struct _dif_sgl sgl;
2501 : : uint32_t offset_blocks;
2502 : : int rc;
2503 : :
2504 : 48 : _dif_sgl_init(&sgl, iovs, iovcnt);
2505 : :
2506 [ - + # # : 48 : if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) {
# # ]
2507 : 0 : SPDK_ERRLOG("Size of iovec array is not valid.\n");
2508 : 0 : return -EINVAL;
2509 : : }
2510 : :
2511 [ - + # # : 48 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
2512 : 0 : return 0;
2513 : : }
2514 : :
2515 [ + + # # : 48 : if (!(ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK)) {
# # # # ]
2516 : 0 : return 0;
2517 : : }
2518 : :
2519 [ + + ]: 336 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
2520 [ # # ]: 288 : rc = _dif_remap_ref_tag(&sgl, offset_blocks, ctx, err_blk, check_ref_tag);
2521 [ + + ]: 288 : if (rc != 0) {
2522 : 0 : return rc;
2523 : : }
2524 : 72 : }
2525 : :
2526 : 48 : return 0;
2527 : 12 : }
2528 : :
2529 : : static int
2530 : 800 : _dix_remap_ref_tag(struct _dif_sgl *md_sgl, uint32_t offset_blocks,
2531 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk,
2532 : : bool check_ref_tag)
2533 : : {
2534 : 800 : uint64_t expected = 0, remapped;
2535 : 600 : uint8_t *md_buf;
2536 : : struct spdk_dif *dif;
2537 : :
2538 : 800 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
2539 : :
2540 [ # # # # : 800 : dif = (struct spdk_dif *)(md_buf + ctx->guard_interval);
# # ]
2541 : :
2542 [ - + ]: 800 : if (_dif_ignore(dif, ctx)) {
2543 : 0 : goto end;
2544 : : }
2545 : :
2546 : : /* For type 1 and 2, the Reference Tag is incremented for each
2547 : : * subsequent logical block. For type 3, the Reference Tag
2548 : : * remains the same as the initialReference Tag.
2549 : : */
2550 [ + - # # : 800 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
# # ]
2551 [ # # # # : 800 : expected = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
# # # # ]
2552 [ # # # # : 800 : remapped = ctx->remapped_init_ref_tag + ctx->ref_tag_offset + offset_blocks;
# # # # ]
2553 : 200 : } else {
2554 [ # # # # ]: 0 : remapped = ctx->remapped_init_ref_tag;
2555 : : }
2556 : :
2557 : : /* Verify the stored Reference Tag. */
2558 [ + + + + : 800 : if (check_ref_tag && !_dif_reftag_check(dif, ctx, expected, offset_blocks, err_blk)) {
# # ]
2559 : 0 : return -1;
2560 : : }
2561 : :
2562 : : /* Update the stored Reference Tag to the remapped one. */
2563 [ # # # # ]: 800 : _dif_set_reftag(dif, remapped, ctx->dif_pi_format);
2564 : :
2565 : 600 : end:
2566 [ # # # # ]: 800 : _dif_sgl_advance(md_sgl, ctx->md_size);
2567 : :
2568 : 800 : return 0;
2569 : 200 : }
2570 : :
2571 : : int
2572 : 48 : spdk_dix_remap_ref_tag(struct iovec *md_iov, uint32_t num_blocks,
2573 : : const struct spdk_dif_ctx *ctx,
2574 : : struct spdk_dif_error *err_blk,
2575 : : bool check_ref_tag)
2576 : : {
2577 : 36 : struct _dif_sgl md_sgl;
2578 : : uint32_t offset_blocks;
2579 : : int rc;
2580 : :
2581 : 48 : _dif_sgl_init(&md_sgl, md_iov, 1);
2582 : :
2583 [ - + # # : 48 : if (!_dif_sgl_is_valid(&md_sgl, ctx->md_size * num_blocks)) {
# # ]
2584 : 0 : SPDK_ERRLOG("Size of metadata iovec array is not valid.\n");
2585 : 0 : return -EINVAL;
2586 : : }
2587 : :
2588 [ - + # # : 48 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
2589 : 0 : return 0;
2590 : : }
2591 : :
2592 [ + + # # : 48 : if (!(ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK)) {
# # # # ]
2593 : 0 : return 0;
2594 : : }
2595 : :
2596 [ + + ]: 848 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
2597 [ # # ]: 800 : rc = _dix_remap_ref_tag(&md_sgl, offset_blocks, ctx, err_blk, check_ref_tag);
2598 [ + + ]: 800 : if (rc != 0) {
2599 : 0 : return rc;
2600 : : }
2601 : 200 : }
2602 : :
2603 : 48 : return 0;
2604 : 12 : }
|