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 : 12364085 : _dif_sgl_init(struct _dif_sgl *s, struct iovec *iovs, int iovcnt)
65 : : {
66 [ # # # # ]: 12364085 : s->iov = iovs;
67 [ # # # # ]: 12364085 : s->iovcnt = iovcnt;
68 [ # # # # ]: 12364085 : s->iov_offset = 0;
69 [ # # # # ]: 12364085 : s->total_size = 0;
70 : 12364085 : }
71 : :
72 : : static void
73 : 181345448 : _dif_sgl_advance(struct _dif_sgl *s, uint32_t step)
74 : : {
75 [ # # # # ]: 181345448 : s->iov_offset += step;
76 [ + + # # : 191342981 : while (s->iovcnt != 0) {
# # ]
77 [ + + # # : 181522501 : if (s->iov_offset < s->iov->iov_len) {
# # # # #
# # # #
# ]
78 : 171524968 : break;
79 : : }
80 : :
81 [ # # # # : 9997533 : s->iov_offset -= s->iov->iov_len;
# # # # #
# # # ]
82 [ # # # # ]: 9997533 : s->iov++;
83 [ # # # # ]: 9997533 : s->iovcnt--;
84 : : }
85 : 181345448 : }
86 : :
87 : : static inline void
88 : 148979230 : _dif_sgl_get_buf(struct _dif_sgl *s, uint8_t **_buf, uint32_t *_buf_len)
89 : : {
90 [ + - ]: 148979230 : if (_buf != NULL) {
91 [ # # # # : 148979230 : *_buf = (uint8_t *)s->iov->iov_base + s->iov_offset;
# # # # #
# # # # #
# # ]
92 : 0 : }
93 [ + + ]: 148979230 : if (_buf_len != NULL) {
94 [ # # # # : 90302722 : *_buf_len = s->iov->iov_len - s->iov_offset;
# # # # #
# # # #
# ]
95 : 0 : }
96 : 148979230 : }
97 : :
98 : : static inline bool
99 : 30237722 : _dif_sgl_append(struct _dif_sgl *s, uint8_t *data, uint32_t data_len)
100 : : {
101 [ - + # # : 30237722 : assert(s->iovcnt > 0);
# # # # ]
102 [ # # # # : 30237722 : s->iov->iov_base = data;
# # # # ]
103 [ # # # # : 30237722 : s->iov->iov_len = data_len;
# # # # ]
104 [ # # # # ]: 30237722 : s->total_size += data_len;
105 [ # # # # ]: 30237722 : s->iov++;
106 [ # # # # ]: 30237722 : s->iovcnt--;
107 : :
108 [ + + # # : 30237722 : if (s->iovcnt > 0) {
# # ]
109 : 29847348 : return true;
110 : : } else {
111 : 390374 : return false;
112 : : }
113 : 0 : }
114 : :
115 : : static inline bool
116 : 30166388 : _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 [ + + ]: 60013736 : while (data_len != 0) {
122 : 30237722 : _dif_sgl_get_buf(src, &buf, &buf_len);
123 [ # # ]: 30237722 : buf_len = spdk_min(buf_len, data_len);
124 : :
125 [ + + ]: 30237722 : if (!_dif_sgl_append(dst, buf, buf_len)) {
126 : 390374 : return false;
127 : : }
128 : :
129 : 29847348 : _dif_sgl_advance(src, buf_len);
130 : 29847348 : data_len -= buf_len;
131 : : }
132 : :
133 : 29776014 : return true;
134 : 0 : }
135 : :
136 : : /* This function must be used before starting iteration. */
137 : : static bool
138 : 6914380 : _dif_sgl_is_bytes_multiple(struct _dif_sgl *s, uint32_t bytes)
139 : : {
140 : : int i;
141 : :
142 [ + + # # : 13794995 : for (i = 0; i < s->iovcnt; i++) {
# # # # ]
143 [ + + + + : 6917581 : if (s->iov[i].iov_len % bytes) {
# # # # #
# # # #
# ]
144 : 36966 : return false;
145 : : }
146 : 0 : }
147 : :
148 : 6877414 : return true;
149 : 0 : }
150 : :
151 : : /* This function must be used before starting iteration. */
152 : : static bool
153 : 10512088 : _dif_sgl_is_valid(struct _dif_sgl *s, uint32_t bytes)
154 : : {
155 : 10512088 : uint64_t total = 0;
156 : : int i;
157 : :
158 [ + + # # : 21487264 : for (i = 0; i < s->iovcnt; i++) {
# # # # ]
159 [ # # # # : 10975176 : total += s->iov[i].iov_len;
# # # # #
# ]
160 : 0 : }
161 : :
162 : 10512088 : return total >= bytes;
163 : : }
164 : :
165 : : static void
166 : 216 : _dif_sgl_copy(struct _dif_sgl *to, struct _dif_sgl *from)
167 : : {
168 [ - + - + ]: 216 : memcpy(to, from, sizeof(struct _dif_sgl));
169 : 216 : }
170 : :
171 : : static bool
172 : 5408102 : _dif_is_disabled(enum spdk_dif_type dif_type)
173 : : {
174 [ + + ]: 5408102 : if (dif_type == SPDK_DIF_DISABLE) {
175 : 149576 : return true;
176 : : } else {
177 : 5258526 : return false;
178 : : }
179 : 0 : }
180 : :
181 : : static inline size_t
182 : 80698830 : _dif_size(enum spdk_dif_pi_format dif_pi_format)
183 : : {
184 : : uint8_t size;
185 : :
186 [ + + ]: 80698830 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
187 : 80691041 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g16);
188 [ + + ]: 7789 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
189 : 3962 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g32);
190 : 0 : } else {
191 : 3827 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g64);
192 : : }
193 : :
194 : 80698830 : 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 : 4033422 : _get_guard_interval(uint32_t block_size, uint32_t md_size, bool dif_loc, bool md_interleave,
205 : : size_t dif_size)
206 : : {
207 [ + + # # ]: 4033422 : 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 [ + + # # ]: 3165209 : if (md_interleave) {
214 : 3015423 : return block_size - dif_size;
215 : : } else {
216 : 149786 : 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 [ + + # # ]: 868213 : if (md_interleave) {
224 : 867889 : return block_size - md_size;
225 : : } else {
226 : 324 : return 0;
227 : : }
228 : : }
229 : 0 : }
230 : :
231 : : static inline uint8_t
232 : 540 : _dif_guard_size(enum spdk_dif_pi_format dif_pi_format)
233 : : {
234 : : uint8_t size;
235 : :
236 [ + + ]: 540 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
237 : 180 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g16.guard);
238 [ + + ]: 360 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
239 : 180 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g32.guard);
240 : 0 : } else {
241 : 180 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g64.guard);
242 : : }
243 : :
244 : 540 : return size;
245 : : }
246 : :
247 : : static inline void
248 : 30873579 : _dif_set_guard(struct spdk_dif *dif, uint64_t guard, enum spdk_dif_pi_format dif_pi_format)
249 : : {
250 [ + + ]: 30873579 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
251 [ # # # # : 30869337 : to_be16(&(dif->g16.guard), (uint16_t)guard);
# # ]
252 [ + + ]: 4242 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
253 [ # # # # : 2154 : to_be32(&(dif->g32.guard), (uint32_t)guard);
# # ]
254 : 0 : } else {
255 [ # # # # : 2088 : to_be64(&(dif->g64.guard), guard);
# # ]
256 : : }
257 : 30873579 : }
258 : :
259 : : static inline uint64_t
260 : 36197411 : _dif_get_guard(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
261 : : {
262 : : uint64_t guard;
263 : :
264 [ + + ]: 36197411 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
265 [ # # # # : 36194842 : guard = (uint64_t)from_be16(&(dif->g16.guard));
# # ]
266 [ + + ]: 2569 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
267 [ # # # # : 1283 : guard = (uint64_t)from_be32(&(dif->g32.guard));
# # ]
268 : 0 : } else {
269 [ # # # # : 1286 : guard = from_be64(&(dif->g64.guard));
# # ]
270 : : }
271 : :
272 : 36197411 : return guard;
273 : : }
274 : :
275 : : static inline uint64_t
276 : 69706292 : _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 [ + + ]: 69706292 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
282 : 69698165 : guard = (uint64_t)spdk_crc16_t10dif((uint16_t)guard_seed, buf, buf_len);
283 [ + + ]: 8127 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
284 : 4107 : guard = (uint64_t)spdk_crc32c_nvme(buf, buf_len, guard_seed);
285 : 0 : } else {
286 : 4020 : guard = spdk_crc64_nvme(buf, buf_len, guard_seed);
287 : : }
288 : :
289 : 69706292 : return guard;
290 : : }
291 : :
292 : : static uint64_t
293 : 24209443 : 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 : 24209443 : uint64_t guard = guard_seed;
297 : 1752 : uint32_t offset, end, buf_len;
298 : 1752 : uint8_t *buf;
299 : :
300 : 24209443 : offset = start;
301 [ # # # # : 24209443 : end = start + spdk_min(len, ctx->guard_interval - start);
# # # # #
# ]
302 : :
303 [ + + ]: 48490976 : while (offset < end) {
304 : 24281533 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
305 [ # # ]: 24281533 : buf_len = spdk_min(buf_len, end - offset);
306 : :
307 [ + - # # : 24281533 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
308 [ # # # # ]: 24281533 : guard = _dif_generate_guard(guard, buf, buf_len, ctx->dif_pi_format);
309 : 0 : }
310 : :
311 : 24281533 : _dif_sgl_advance(sgl, buf_len);
312 : 24281533 : offset += buf_len;
313 : : }
314 : :
315 : 24209443 : return guard;
316 : : }
317 : :
318 : : static inline uint64_t
319 : 13246145 : _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 [ + + ]: 13246145 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
325 : 13244273 : guard = (uint64_t)spdk_crc16_t10dif_copy((uint16_t)guard_seed, dst, src, buf_len);
326 [ + + ]: 1872 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
327 [ - + - + ]: 936 : memcpy(dst, src, buf_len);
328 : 936 : guard = (uint64_t)spdk_crc32c_nvme(src, buf_len, guard_seed);
329 : 0 : } else {
330 [ - + - + ]: 936 : memcpy(dst, src, buf_len);
331 : 936 : guard = spdk_crc64_nvme(src, buf_len, guard_seed);
332 : : }
333 : :
334 : 13246145 : return guard;
335 : : }
336 : :
337 : : static uint64_t
338 : 426 : _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 : 426 : uint32_t offset = 0, src_len, dst_len, buf_len;
343 : 426 : uint8_t *src, *dst;
344 : :
345 [ + + ]: 1284 : while (offset < data_len) {
346 : 858 : _dif_sgl_get_buf(src_sgl, &src, &src_len);
347 : 858 : _dif_sgl_get_buf(dst_sgl, &dst, &dst_len);
348 [ # # ]: 858 : buf_len = spdk_min(src_len, dst_len);
349 [ # # ]: 858 : buf_len = spdk_min(buf_len, data_len - offset);
350 : :
351 : 858 : guard = _dif_generate_guard_copy(guard, dst, src, buf_len, dif_pi_format);
352 : :
353 : 858 : _dif_sgl_advance(src_sgl, buf_len);
354 : 858 : _dif_sgl_advance(dst_sgl, buf_len);
355 : 858 : offset += buf_len;
356 : : }
357 : :
358 : 426 : 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 : 360 : _dif_apptag_offset(enum spdk_dif_pi_format dif_pi_format)
383 : : {
384 : 360 : return _dif_guard_size(dif_pi_format);
385 : : }
386 : :
387 : : static inline uint8_t
388 : 360 : _dif_apptag_size(void)
389 : : {
390 : 360 : return SPDK_SIZEOF_MEMBER(struct spdk_dif, g16.app_tag);
391 : : }
392 : :
393 : : static inline void
394 : 30873579 : _dif_set_apptag(struct spdk_dif *dif, uint16_t app_tag, enum spdk_dif_pi_format dif_pi_format)
395 : : {
396 [ + + ]: 30873579 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
397 [ # # # # : 30869337 : to_be16(&(dif->g16.app_tag), app_tag);
# # ]
398 [ + + ]: 4242 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
399 [ # # # # : 2154 : to_be16(&(dif->g32.app_tag), app_tag);
# # ]
400 : 0 : } else {
401 [ # # # # : 2088 : to_be16(&(dif->g64.app_tag), app_tag);
# # ]
402 : : }
403 : 30873579 : }
404 : :
405 : : static inline uint16_t
406 : 41815891 : _dif_get_apptag(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
407 : : {
408 : : uint16_t app_tag;
409 : :
410 [ + + ]: 41815891 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
411 [ # # # # : 41809772 : app_tag = from_be16(&(dif->g16.app_tag));
# # ]
412 [ + + ]: 6119 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
413 [ # # # # : 3061 : app_tag = from_be16(&(dif->g32.app_tag));
# # ]
414 : 0 : } else {
415 [ # # # # : 3058 : app_tag = from_be16(&(dif->g64.app_tag));
# # ]
416 : : }
417 : :
418 : 41815891 : return app_tag;
419 : : }
420 : :
421 : : static inline bool
422 : 36251968 : _dif_apptag_ignore(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
423 : : {
424 : 36251968 : return _dif_get_apptag(dif, dif_pi_format) == SPDK_DIF_APPTAG_IGNORE;
425 : : }
426 : :
427 : : static inline uint8_t
428 : 180 : _dif_reftag_offset(enum spdk_dif_pi_format dif_pi_format)
429 : : {
430 : : uint8_t offset;
431 : :
432 [ + + ]: 180 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
433 : 60 : offset = _dif_apptag_offset(dif_pi_format) + _dif_apptag_size();
434 [ + + ]: 120 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
435 : 60 : offset = _dif_apptag_offset(dif_pi_format) + _dif_apptag_size()
436 : 0 : + SPDK_SIZEOF_MEMBER(struct spdk_dif, g32.stor_ref_space_p1);
437 : 0 : } else {
438 : 60 : offset = _dif_apptag_offset(dif_pi_format) + _dif_apptag_size();
439 : : }
440 : :
441 : 180 : return offset;
442 : : }
443 : :
444 : : static inline uint8_t
445 : 180 : _dif_reftag_size(enum spdk_dif_pi_format dif_pi_format)
446 : : {
447 : : uint8_t size;
448 : :
449 [ + + ]: 180 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
450 : 60 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g16.stor_ref_space);
451 [ + + ]: 120 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
452 : 60 : size = SPDK_SIZEOF_MEMBER(struct spdk_dif, g32.stor_ref_space_p2);
453 : 0 : } else {
454 : 60 : 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 : 180 : return size;
459 : : }
460 : :
461 : : static inline void
462 : 30874395 : _dif_set_reftag(struct spdk_dif *dif, uint64_t ref_tag, enum spdk_dif_pi_format dif_pi_format)
463 : : {
464 [ + + ]: 30874395 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
465 [ # # # # : 30869865 : to_be32(&(dif->g16.stor_ref_space), (uint32_t)ref_tag);
# # ]
466 [ + + ]: 4530 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
467 [ # # # # : 2298 : to_be64(&(dif->g32.stor_ref_space_p2), ref_tag);
# # ]
468 : 0 : } else {
469 [ # # # # : 2232 : to_be16(&(dif->g64.stor_ref_space_p1), (uint16_t)(ref_tag >> 32));
# # # # ]
470 [ # # # # : 2232 : to_be32(&(dif->g64.stor_ref_space_p2), (uint32_t)ref_tag);
# # ]
471 : : }
472 : 30874395 : }
473 : :
474 : : static inline uint64_t
475 : 27072512 : _dif_get_reftag(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
476 : : {
477 : : uint64_t ref_tag;
478 : :
479 [ + + ]: 27072512 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
480 [ # # # # : 27069934 : ref_tag = (uint64_t)from_be32(&(dif->g16.stor_ref_space));
# # ]
481 [ + + ]: 2578 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
482 [ # # # # : 1289 : ref_tag = from_be64(&(dif->g32.stor_ref_space_p2));
# # ]
483 : 0 : } else {
484 [ # # # # : 1289 : ref_tag = (uint64_t)from_be16(&(dif->g64.stor_ref_space_p1));
# # ]
485 [ # # ]: 1289 : ref_tag <<= 32;
486 [ # # # # : 1289 : ref_tag |= (uint64_t)from_be32(&(dif->g64.stor_ref_space_p2));
# # ]
487 : : }
488 : :
489 : 27072512 : return ref_tag;
490 : : }
491 : :
492 : : static inline bool
493 : 27072290 : _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 : 27072290 : _ref_tag = _dif_get_reftag(dif, dif_pi_format);
500 : :
501 [ + + ]: 27072290 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
502 : 27069844 : match = (_ref_tag == (ref_tag & REFTAG_MASK_16));
503 [ + + ]: 2446 : } else if (dif_pi_format == SPDK_DIF_PI_FORMAT_32) {
504 : 1223 : match = (_ref_tag == ref_tag);
505 : 0 : } else {
506 : 1223 : match = (_ref_tag == (ref_tag & REFTAG_MASK_64));
507 : : }
508 : :
509 [ # # ]: 27072290 : return match;
510 : : }
511 : :
512 : : static inline bool
513 : 21 : _dif_reftag_ignore(struct spdk_dif *dif, enum spdk_dif_pi_format dif_pi_format)
514 : : {
515 : 21 : return _dif_reftag_match(dif, REFTAG_MASK_32, dif_pi_format);
516 : : }
517 : :
518 : : static bool
519 : 36251968 : _dif_ignore(struct spdk_dif *dif, const struct spdk_dif_ctx *ctx)
520 : : {
521 [ + + - # : 36251968 : switch (ctx->dif_type) {
# # # ]
522 : 27126901 : 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 [ + + # # : 27126901 : if (_dif_apptag_ignore(dif, ctx->dif_pi_format)) {
# # ]
528 : 51833 : return true;
529 : : }
530 : 27075068 : break;
531 : 9125067 : 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 [ + + + + : 9125088 : if (_dif_apptag_ignore(dif, ctx->dif_pi_format) &&
# # # # ]
538 [ # # # # ]: 21 : _dif_reftag_ignore(dif, ctx->dif_pi_format)) {
539 : 12 : return true;
540 : : }
541 : 9125055 : break;
542 : 0 : default:
543 : 0 : break;
544 : : }
545 : :
546 : 36200123 : return false;
547 : 0 : }
548 : :
549 : : static bool
550 : 4033428 : _dif_pi_format_is_valid(enum spdk_dif_pi_format dif_pi_format)
551 : : {
552 [ + + ]: 4033428 : switch (dif_pi_format) {
553 : 4033425 : case SPDK_DIF_PI_FORMAT_16:
554 : : case SPDK_DIF_PI_FORMAT_32:
555 : : case SPDK_DIF_PI_FORMAT_64:
556 : 4033425 : return true;
557 : 3 : default:
558 : 3 : return false;
559 : : }
560 : 0 : }
561 : :
562 : : static bool
563 : 4033431 : _dif_type_is_valid(enum spdk_dif_type dif_type)
564 : : {
565 [ + + ]: 4033431 : switch (dif_type) {
566 : 4033428 : case SPDK_DIF_DISABLE:
567 : : case SPDK_DIF_TYPE1:
568 : : case SPDK_DIF_TYPE2:
569 : : case SPDK_DIF_TYPE3:
570 : 4033428 : return true;
571 : 3 : default:
572 : 3 : return false;
573 : : }
574 : 0 : }
575 : :
576 : : int
577 : 4033416 : 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 : 4033416 : enum spdk_dif_pi_format dif_pi_format = SPDK_DIF_PI_FORMAT_16;
584 : :
585 [ + - ]: 4033416 : if (opts != NULL) {
586 [ - + # # : 4033416 : 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 [ # # # # ]: 4033416 : dif_pi_format = opts->dif_pi_format;
592 : 0 : }
593 : :
594 [ - + ]: 4033416 : 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 [ + + ]: 4033416 : if (md_size < _dif_size(dif_pi_format)) {
600 : 33 : SPDK_ERRLOG("Metadata size is smaller than DIF size.\n");
601 : 33 : return -EINVAL;
602 : : }
603 : :
604 [ + + # # ]: 4033383 : if (md_interleave) {
605 [ - + ]: 3883258 : if (block_size < md_size) {
606 : 0 : SPDK_ERRLOG("Block size is smaller than DIF size.\n");
607 : 0 : return -EINVAL;
608 : : }
609 : 3883258 : data_block_size = block_size - md_size;
610 : 0 : } else {
611 : 150125 : data_block_size = block_size;
612 : : }
613 : :
614 [ + + ]: 4033383 : if (data_block_size == 0) {
615 : 6 : SPDK_ERRLOG("Zero data block size is not allowed\n");
616 : 6 : return -EINVAL;
617 : : }
618 : :
619 [ + + ]: 4033377 : if (dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
620 [ - + # # ]: 4032384 : 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 : 0 : } else {
625 [ + + # # ]: 993 : if ((data_block_size % 4096) != 0) {
626 : 18 : SPDK_ERRLOG("Data block size should be a multiple of 4kB\n");
627 : 18 : return -EINVAL;
628 : : }
629 : : }
630 : :
631 [ # # # # ]: 4033359 : ctx->block_size = block_size;
632 [ # # # # ]: 4033359 : ctx->md_size = md_size;
633 [ # # # # : 4033359 : ctx->md_interleave = md_interleave;
# # ]
634 [ # # # # ]: 4033359 : ctx->dif_pi_format = dif_pi_format;
635 [ # # # # : 4033359 : ctx->guard_interval = _get_guard_interval(block_size, md_size, dif_loc, md_interleave,
# # # # ]
636 [ # # # # ]: 4033359 : _dif_size(ctx->dif_pi_format));
637 [ # # # # ]: 4033359 : ctx->dif_type = dif_type;
638 [ # # # # ]: 4033359 : ctx->dif_flags = dif_flags;
639 [ # # # # ]: 4033359 : ctx->init_ref_tag = init_ref_tag;
640 [ # # # # ]: 4033359 : ctx->apptag_mask = apptag_mask;
641 [ # # # # ]: 4033359 : ctx->app_tag = app_tag;
642 [ # # # # ]: 4033359 : ctx->data_offset = data_offset;
643 [ - + # # : 4033359 : ctx->ref_tag_offset = data_offset / data_block_size;
# # ]
644 [ # # # # ]: 4033359 : ctx->last_guard = guard_seed;
645 [ # # # # ]: 4033359 : ctx->guard_seed = guard_seed;
646 [ # # # # ]: 4033359 : ctx->remapped_init_ref_tag = 0;
647 : :
648 : 4033359 : return 0;
649 : 0 : }
650 : :
651 : : void
652 : 1211231 : spdk_dif_ctx_set_data_offset(struct spdk_dif_ctx *ctx, uint32_t data_offset)
653 : : {
654 : : uint32_t data_block_size;
655 : :
656 [ + + + - : 1211231 : if (ctx->md_interleave) {
# # # # ]
657 [ # # # # : 1211231 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
658 : 0 : } else {
659 [ # # # # ]: 0 : data_block_size = ctx->block_size;
660 : : }
661 : :
662 [ # # # # ]: 1211231 : ctx->data_offset = data_offset;
663 [ - + # # : 1211231 : ctx->ref_tag_offset = data_offset / data_block_size;
# # ]
664 : 1211231 : }
665 : :
666 : : void
667 : 72 : spdk_dif_ctx_set_remapped_init_ref_tag(struct spdk_dif_ctx *ctx,
668 : : uint32_t remapped_init_ref_tag)
669 : : {
670 [ # # # # ]: 72 : ctx->remapped_init_ref_tag = remapped_init_ref_tag;
671 : 72 : }
672 : :
673 : : static void
674 : 30873579 : _dif_generate(void *_dif, uint64_t guard, uint32_t offset_blocks,
675 : : const struct spdk_dif_ctx *ctx)
676 : : {
677 : 30873579 : struct spdk_dif *dif = _dif;
678 : : uint64_t ref_tag;
679 : :
680 [ + + # # : 30873579 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
681 [ # # # # ]: 30871833 : _dif_set_guard(dif, guard, ctx->dif_pi_format);
682 : 0 : } else {
683 [ # # # # ]: 1746 : _dif_set_guard(dif, 0, ctx->dif_pi_format);
684 : : }
685 : :
686 [ + + # # : 30873579 : if (ctx->dif_flags & SPDK_DIF_FLAGS_APPTAG_CHECK) {
# # # # ]
687 [ # # # # : 10590131 : _dif_set_apptag(dif, ctx->app_tag, ctx->dif_pi_format);
# # # # ]
688 : 0 : } else {
689 [ # # # # ]: 20283448 : _dif_set_apptag(dif, 0, ctx->dif_pi_format);
690 : : }
691 : :
692 [ + + # # : 30873579 : 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 [ + + # # : 21746946 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
# # ]
698 [ # # # # : 21746925 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
# # # # ]
699 : 0 : } else {
700 [ # # # # : 21 : 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 [ + + # # : 21746946 : if (ctx->init_ref_tag == SPDK_DIF_REFTAG_IGNORE) {
# # ]
705 [ + - # # : 24582 : if (ctx->dif_pi_format == SPDK_DIF_PI_FORMAT_16) {
# # ]
706 : 24582 : ref_tag = REFTAG_MASK_16;
707 [ # # # # : 0 : } 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 : 0 : }
713 : :
714 [ # # # # ]: 21746946 : _dif_set_reftag(dif, ref_tag, ctx->dif_pi_format);
715 : 0 : } else {
716 [ # # # # ]: 9126633 : _dif_set_reftag(dif, 0, ctx->dif_pi_format);
717 : : }
718 : 30873579 : }
719 : :
720 : : static void
721 : 1569827 : dif_generate(struct _dif_sgl *sgl, uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
722 : : {
723 : : uint32_t offset_blocks;
724 : 309284 : uint8_t *buf;
725 : 1569827 : uint64_t guard = 0;
726 : :
727 [ + + ]: 15270300 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
728 : 13700473 : _dif_sgl_get_buf(sgl, &buf, NULL);
729 : :
730 [ + + # # : 13700473 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
731 [ # # # # : 13700023 : guard = _dif_generate_guard(ctx->guard_seed, buf, ctx->guard_interval, ctx->dif_pi_format);
# # # # #
# # # ]
732 : 0 : }
733 : :
734 [ # # # # : 13700473 : _dif_generate(buf + ctx->guard_interval, guard, offset_blocks, ctx);
# # ]
735 : :
736 [ # # # # ]: 13700473 : _dif_sgl_advance(sgl, ctx->block_size);
737 : 0 : }
738 : 1569827 : }
739 : :
740 : : static void
741 : 9125502 : dif_store_split(struct _dif_sgl *sgl, struct spdk_dif *dif,
742 : : const struct spdk_dif_ctx *ctx)
743 : : {
744 : 9125502 : uint32_t offset = 0, rest_md_len, buf_len;
745 : 894 : uint8_t *buf;
746 : :
747 [ # # # # : 9125502 : rest_md_len = ctx->block_size - ctx->guard_interval;
# # # # ]
748 : :
749 [ + + ]: 18251616 : while (offset < rest_md_len) {
750 : 9126114 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
751 : :
752 [ + + # # : 9126114 : if (offset < _dif_size(ctx->dif_pi_format)) {
# # ]
753 [ + + # # : 9125766 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset);
# # # # #
# ]
754 [ - + - + : 9125766 : memcpy(buf, (uint8_t *)dif + offset, buf_len);
# # ]
755 : 0 : } else {
756 [ # # ]: 348 : buf_len = spdk_min(buf_len, rest_md_len - offset);
757 : : }
758 : :
759 : 9126114 : _dif_sgl_advance(sgl, buf_len);
760 : 9126114 : offset += buf_len;
761 : : }
762 : 9125502 : }
763 : :
764 : : static uint64_t
765 : 9125394 : _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 : 9125394 : struct spdk_dif dif = {};
769 : :
770 [ - + # # : 9125394 : assert(offset_in_block < ctx->guard_interval);
# # # # ]
771 [ + + - + : 9125394 : 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 : 9125394 : guard = dif_generate_guard_split(guard, sgl, offset_in_block, data_len, ctx);
776 : :
777 [ + + # # : 9125394 : if (offset_in_block + data_len < ctx->guard_interval) {
# # ]
778 : 117 : 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 : 9125277 : _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 : 9125277 : dif_store_split(sgl, &dif, ctx);
790 : :
791 [ + - # # : 9125277 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
792 [ # # # # ]: 9125277 : guard = ctx->guard_seed;
793 : 0 : }
794 : :
795 : 9125277 : return guard;
796 : 0 : }
797 : :
798 : : static void
799 : 36099 : 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 : 36099 : uint64_t guard = 0;
804 : :
805 [ + - # # : 36099 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
806 [ # # # # ]: 36099 : guard = ctx->guard_seed;
807 : 0 : }
808 : :
809 [ + + ]: 9161238 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
810 [ # # # # ]: 9125139 : _dif_generate_split(sgl, 0, ctx->block_size, guard, offset_blocks, ctx);
811 : 0 : }
812 : 36099 : }
813 : :
814 : : int
815 : 1605902 : spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
816 : : const struct spdk_dif_ctx *ctx)
817 : : {
818 : 309716 : struct _dif_sgl sgl;
819 : :
820 : 1605902 : _dif_sgl_init(&sgl, iovs, iovcnt);
821 : :
822 [ - + # # : 1605902 : 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 [ + + # # : 1605902 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
828 : 3 : return 0;
829 : : }
830 : :
831 [ + + # # : 1605899 : if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
# # ]
832 : 1569800 : dif_generate(&sgl, num_blocks, ctx);
833 : 0 : } else {
834 : 36099 : dif_generate_split(&sgl, num_blocks, ctx);
835 : : }
836 : :
837 : 1605899 : return 0;
838 : 0 : }
839 : :
840 : : static void
841 : 837 : _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 [ + + ]: 837 : if (err_blk) {
845 [ # # # # ]: 810 : err_blk->err_type = err_type;
846 [ # # # # ]: 810 : err_blk->expected = expected;
847 [ # # # # ]: 810 : err_blk->actual = actual;
848 [ # # # # ]: 810 : err_blk->err_offset = err_offset;
849 : 0 : }
850 : 837 : }
851 : :
852 : : static bool
853 : 36199118 : _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 [ + + # # : 36199118 : if (ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK) {
# # # # ]
859 [ + - - # : 27072269 : switch (ctx->dif_type) {
# # # ]
860 : 27072269 : 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 [ + + # # : 27072269 : if (!_dif_reftag_match(dif, expected_reftag, ctx->dif_pi_format)) {
# # ]
869 [ # # # # ]: 216 : reftag = _dif_get_reftag(dif, ctx->dif_pi_format);
870 : 216 : _dif_error_set(err_blk, SPDK_DIF_REFTAG_ERROR, expected_reftag,
871 : 0 : reftag, offset_blocks);
872 : 216 : SPDK_ERRLOG("Failed to compare Ref Tag: LBA=%" PRIu64 "," \
873 : : " Expected=%lx, Actual=%lx\n",
874 : : expected_reftag, expected_reftag, reftag);
875 : 216 : return false;
876 : : }
877 : 27072053 : 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 : 0 : }
887 : :
888 : 36198902 : return true;
889 : 0 : }
890 : :
891 : : static int
892 : 36251152 : _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 : 36251152 : struct spdk_dif *dif = _dif;
896 : : uint64_t _guard;
897 : : uint16_t _app_tag;
898 : : uint64_t ref_tag;
899 : :
900 [ + + ]: 36251152 : if (_dif_ignore(dif, ctx)) {
901 : 51845 : 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 [ + + # # : 36199307 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
# # ]
909 [ # # # # : 27074252 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
# # # # ]
910 : 0 : } else {
911 [ # # # # : 9125055 : ref_tag = ctx->init_ref_tag + ctx->ref_tag_offset;
# # # # ]
912 : : }
913 : :
914 [ + + # # : 36199307 : 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 [ # # # # ]: 36197381 : _guard = _dif_get_guard(dif, ctx->dif_pi_format);
919 [ + + ]: 36197381 : if (_guard != guard) {
920 : 387 : _dif_error_set(err_blk, SPDK_DIF_GUARD_ERROR, _guard, guard,
921 : 0 : offset_blocks);
922 : 387 : SPDK_ERRLOG("Failed to compare Guard: LBA=%" PRIu64 "," \
923 : : " Expected=%lx, Actual=%lx\n",
924 : : ref_tag, _guard, guard);
925 : 387 : return -1;
926 : : }
927 : 0 : }
928 : :
929 [ + + # # : 36198920 : 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 [ # # # # ]: 5563917 : _app_tag = _dif_get_apptag(dif, ctx->dif_pi_format);
934 [ + + # # : 5563917 : if ((_app_tag & ctx->apptag_mask) != (ctx->app_tag & ctx->apptag_mask)) {
# # # # #
# # # #
# ]
935 [ # # # # ]: 234 : _dif_error_set(err_blk, SPDK_DIF_APPTAG_ERROR, ctx->app_tag,
936 [ # # # # ]: 234 : (_app_tag & ctx->apptag_mask), offset_blocks);
937 [ # # # # : 234 : 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 : 234 : return -1;
941 : : }
942 : 0 : }
943 : :
944 [ + + ]: 36198686 : if (!_dif_reftag_check(dif, ctx, ref_tag, offset_blocks, err_blk)) {
945 : 216 : return -1;
946 : : }
947 : :
948 : 36198470 : return 0;
949 : 0 : }
950 : :
951 : : static int
952 : 1681873 : 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 : 1108333 : uint8_t *buf;
958 : 1681873 : uint64_t guard = 0;
959 : :
960 [ + + ]: 15135600 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
961 : 13453853 : _dif_sgl_get_buf(sgl, &buf, NULL);
962 : :
963 [ + + # # : 13453853 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
964 [ # # # # : 13453265 : guard = _dif_generate_guard(ctx->guard_seed, buf, ctx->guard_interval, ctx->dif_pi_format);
# # # # #
# # # ]
965 : 0 : }
966 : :
967 [ # # # # : 13453853 : rc = _dif_verify(buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
# # ]
968 [ + + ]: 13453853 : if (rc != 0) {
969 : 126 : return rc;
970 : : }
971 : :
972 [ # # # # ]: 13453727 : _dif_sgl_advance(sgl, ctx->block_size);
973 : 0 : }
974 : :
975 : 1681747 : return 0;
976 : 0 : }
977 : :
978 : : static void
979 : 15083827 : dif_load_split(struct _dif_sgl *sgl, struct spdk_dif *dif,
980 : : const struct spdk_dif_ctx *ctx)
981 : : {
982 : 15083827 : uint32_t offset = 0, rest_md_len, buf_len;
983 : 744 : uint8_t *buf;
984 : :
985 [ # # # # : 15083827 : rest_md_len = ctx->block_size - ctx->guard_interval;
# # # # ]
986 : :
987 [ + + ]: 30168260 : while (offset < rest_md_len) {
988 : 15084433 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
989 : :
990 [ + + # # : 15084433 : if (offset < _dif_size(ctx->dif_pi_format)) {
# # ]
991 [ + + # # : 15084082 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset);
# # # # #
# ]
992 [ - + - + : 15084082 : memcpy((uint8_t *)dif + offset, buf, buf_len);
# # ]
993 : 0 : } else {
994 [ # # ]: 351 : buf_len = spdk_min(buf_len, rest_md_len - offset);
995 : : }
996 : :
997 : 15084433 : _dif_sgl_advance(sgl, buf_len);
998 : 15084433 : offset += buf_len;
999 : : }
1000 : 15083827 : }
1001 : :
1002 : : static int
1003 : 15083671 : _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 [ # # ]: 15083671 : uint64_t guard = *_guard;
1008 : 15083671 : struct spdk_dif dif = {};
1009 : : int rc;
1010 : :
1011 [ - + # # ]: 15083671 : assert(_guard != NULL);
1012 [ - + # # : 15083671 : assert(offset_in_block < ctx->guard_interval);
# # # # ]
1013 [ + + - + : 15083671 : assert(offset_in_block + data_len < ctx->guard_interval ||
# # # # #
# # # #
# ]
1014 : : offset_in_block + data_len == ctx->block_size);
1015 : :
1016 : 15083671 : guard = dif_generate_guard_split(guard, sgl, offset_in_block, data_len, ctx);
1017 : :
1018 [ + + # # : 15083671 : if (offset_in_block + data_len < ctx->guard_interval) {
# # ]
1019 [ # # ]: 45 : *_guard = guard;
1020 : 45 : return 0;
1021 : : }
1022 : :
1023 : 15083626 : dif_load_split(sgl, &dif, ctx);
1024 : :
1025 : 15083626 : rc = _dif_verify(&dif, guard, offset_blocks, ctx, err_blk);
1026 [ + + ]: 15083626 : if (rc != 0) {
1027 : 360 : return rc;
1028 : : }
1029 : :
1030 [ + - # # : 15083266 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1031 [ # # # # ]: 15083266 : guard = ctx->guard_seed;
1032 : 0 : }
1033 : :
1034 [ # # ]: 15083266 : *_guard = guard;
1035 : 15083266 : return 0;
1036 : 0 : }
1037 : :
1038 : : static int
1039 : 453 : 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 : 453 : uint64_t guard = 0;
1044 : : int rc;
1045 : :
1046 [ + - # # : 453 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1047 [ # # # # ]: 453 : guard = ctx->guard_seed;
1048 : 0 : }
1049 : :
1050 [ + + ]: 645 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1051 [ # # # # ]: 552 : rc = _dif_verify_split(sgl, 0, ctx->block_size, &guard, offset_blocks,
1052 : 0 : ctx, err_blk);
1053 [ + + ]: 552 : if (rc != 0) {
1054 : 360 : return rc;
1055 : : }
1056 : 0 : }
1057 : :
1058 : 93 : return 0;
1059 : 0 : }
1060 : :
1061 : : int
1062 : 1682302 : 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 : 1108759 : struct _dif_sgl sgl;
1066 : :
1067 : 1682302 : _dif_sgl_init(&sgl, iovs, iovcnt);
1068 : :
1069 [ - + # # : 1682302 : 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 [ + + # # : 1682302 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
1075 : 3 : return 0;
1076 : : }
1077 : :
1078 [ + + # # : 1682299 : if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
# # ]
1079 : 1681846 : return dif_verify(&sgl, num_blocks, ctx, err_blk);
1080 : : } else {
1081 : 453 : return dif_verify_split(&sgl, num_blocks, ctx, err_blk);
1082 : : }
1083 : 0 : }
1084 : :
1085 : : static uint32_t
1086 : 27 : 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 [ + + ]: 135 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1093 : 108 : _dif_sgl_get_buf(sgl, &buf, NULL);
1094 : :
1095 [ # # # # : 108 : crc32c = spdk_crc32c_update(buf, ctx->block_size - ctx->md_size, crc32c);
# # # # ]
1096 : :
1097 [ # # # # ]: 108 : _dif_sgl_advance(sgl, ctx->block_size);
1098 : 0 : }
1099 : :
1100 : 27 : return crc32c;
1101 : : }
1102 : :
1103 : : static uint32_t
1104 : 5763188 : _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 [ # # # # : 5763188 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1111 : :
1112 [ - + # # : 5763188 : assert(offset_in_block + data_len <= ctx->block_size);
# # # # ]
1113 : :
1114 [ + + ]: 17312138 : while (data_len != 0) {
1115 : 11548950 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
1116 [ # # ]: 11548950 : buf_len = spdk_min(buf_len, data_len);
1117 : :
1118 [ + + ]: 11548950 : if (offset_in_block < data_block_size) {
1119 [ # # ]: 5785753 : buf_len = spdk_min(buf_len, data_block_size - offset_in_block);
1120 : 5785753 : crc32c = spdk_crc32c_update(buf, buf_len, crc32c);
1121 : 0 : }
1122 : :
1123 : 11548950 : _dif_sgl_advance(sgl, buf_len);
1124 : 11548950 : offset_in_block += buf_len;
1125 : 11548950 : data_len -= buf_len;
1126 : : }
1127 : :
1128 : 5763188 : return crc32c;
1129 : : }
1130 : :
1131 : : static uint32_t
1132 : 18 : 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 [ + + ]: 90 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1138 [ # # # # ]: 72 : crc32c = _dif_update_crc32c_split(sgl, 0, ctx->block_size, crc32c, ctx);
1139 : 0 : }
1140 : :
1141 : 18 : return crc32c;
1142 : : }
1143 : :
1144 : : int
1145 : 45 : 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 [ - + ]: 45 : if (_crc32c == NULL) {
1151 : 0 : return -EINVAL;
1152 : : }
1153 : :
1154 : 45 : _dif_sgl_init(&sgl, iovs, iovcnt);
1155 : :
1156 [ - + # # : 45 : 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 [ + + # # : 45 : if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
# # ]
1162 [ # # # # ]: 27 : *_crc32c = dif_update_crc32c(&sgl, num_blocks, *_crc32c, ctx);
1163 : 0 : } else {
1164 [ # # # # ]: 18 : *_crc32c = dif_update_crc32c_split(&sgl, num_blocks, *_crc32c, ctx);
1165 : : }
1166 : :
1167 : 45 : return 0;
1168 : 0 : }
1169 : :
1170 : : static void
1171 : 8043332 : _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 : 4821460 : uint8_t *src, *dst;
1176 : 8043332 : uint64_t guard = 0;
1177 : :
1178 [ # # # # : 8043332 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1179 : :
1180 : 8043332 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1181 : 8043332 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1182 : :
1183 [ + + # # : 8043332 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1184 [ # # # # ]: 8042858 : guard = _dif_generate_guard_copy(ctx->guard_seed, dst, src, data_block_size,
1185 [ # # # # ]: 8042858 : ctx->dif_pi_format);
1186 [ # # ]: 8042858 : guard = _dif_generate_guard(guard, dst + data_block_size,
1187 [ # # # # : 8042858 : ctx->guard_interval - data_block_size, ctx->dif_pi_format);
# # # # ]
1188 : 0 : } else {
1189 [ - + - + ]: 474 : memcpy(dst, src, data_block_size);
1190 : : }
1191 : :
1192 [ # # # # : 8043332 : _dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx);
# # ]
1193 : :
1194 : 8043332 : _dif_sgl_advance(src_sgl, data_block_size);
1195 [ # # # # ]: 8043332 : _dif_sgl_advance(dst_sgl, ctx->block_size);
1196 : 8043332 : }
1197 : :
1198 : : static void
1199 : 1005400 : 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 [ + + ]: 9048732 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1205 : 8043332 : _dif_insert_copy(src_sgl, dst_sgl, offset_blocks, ctx);
1206 : 0 : }
1207 : 1005400 : }
1208 : :
1209 : : static void
1210 : 201 : _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 : 201 : uint64_t guard = 0;
1215 : 201 : struct spdk_dif dif = {};
1216 : :
1217 [ # # # # : 201 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1218 : :
1219 [ + - # # : 201 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1220 [ # # # # ]: 201 : guard = _dif_generate_guard_copy_split(ctx->guard_seed, dst_sgl, src_sgl,
1221 [ # # # # ]: 201 : data_block_size, ctx->dif_pi_format);
1222 : 201 : guard = dif_generate_guard_split(guard, dst_sgl, data_block_size,
1223 [ # # # # ]: 201 : ctx->guard_interval - data_block_size, ctx);
1224 : 0 : } 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 : 201 : _dif_generate(&dif, guard, offset_blocks, ctx);
1230 : :
1231 : 201 : dif_store_split(dst_sgl, &dif, ctx);
1232 : 201 : }
1233 : :
1234 : : static void
1235 : 93 : 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 [ + + ]: 294 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1241 : 201 : _dif_insert_copy_split(src_sgl, dst_sgl, offset_blocks, ctx);
1242 : 0 : }
1243 : 93 : }
1244 : :
1245 : : static void
1246 : 36 : _dif_disable_insert_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1247 : : const struct spdk_dif_ctx *ctx)
1248 : : {
1249 : 36 : uint32_t offset = 0, src_len, dst_len, buf_len, data_block_size;
1250 : 36 : uint8_t *src, *dst;
1251 : :
1252 [ # # # # : 36 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1253 : :
1254 [ + + ]: 96 : while (offset < data_block_size) {
1255 : 60 : _dif_sgl_get_buf(src_sgl, &src, &src_len);
1256 : 60 : _dif_sgl_get_buf(dst_sgl, &dst, &dst_len);
1257 [ # # ]: 60 : buf_len = spdk_min(src_len, dst_len);
1258 [ # # ]: 60 : buf_len = spdk_min(buf_len, data_block_size - offset);
1259 : :
1260 [ - + - + ]: 60 : memcpy(dst, src, buf_len);
1261 : :
1262 : 60 : _dif_sgl_advance(src_sgl, buf_len);
1263 : 60 : _dif_sgl_advance(dst_sgl, buf_len);
1264 : 60 : offset += buf_len;
1265 : : }
1266 : :
1267 [ # # # # ]: 36 : _dif_sgl_advance(dst_sgl, ctx->md_size);
1268 : 36 : }
1269 : :
1270 : : static void
1271 : 9 : 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 [ + + ]: 45 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1277 : 36 : _dif_disable_insert_copy(src_sgl, dst_sgl, ctx);
1278 : 0 : }
1279 : 9 : }
1280 : :
1281 : : static int
1282 : 1005505 : _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 [ # # # # : 1005505 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1288 : :
1289 [ + - # # ]: 1005505 : if (!_dif_sgl_is_valid(src_sgl, data_block_size * num_blocks) ||
1290 [ + + # # ]: 1005505 : !_dif_sgl_is_valid(dst_sgl, ctx->block_size * num_blocks)) {
1291 : 3 : SPDK_ERRLOG("Size of iovec arrays are not valid.\n");
1292 : 3 : return -EINVAL;
1293 : : }
1294 : :
1295 [ + + # # : 1005502 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
1296 : 9 : dif_disable_insert_copy(src_sgl, dst_sgl, num_blocks, ctx);
1297 : 9 : return 0;
1298 : : }
1299 : :
1300 [ + + + - ]: 2010893 : if (_dif_sgl_is_bytes_multiple(src_sgl, data_block_size) &&
1301 [ # # # # ]: 1005400 : _dif_sgl_is_bytes_multiple(dst_sgl, ctx->block_size)) {
1302 : 1005400 : dif_insert_copy(src_sgl, dst_sgl, num_blocks, ctx);
1303 : 0 : } else {
1304 : 93 : dif_insert_copy_split(src_sgl, dst_sgl, num_blocks, ctx);
1305 : : }
1306 : :
1307 : 1005493 : return 0;
1308 : 0 : }
1309 : :
1310 : : static void
1311 : 288 : _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 : 288 : uint64_t guard = 0;
1316 : :
1317 : 288 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1318 : 288 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1319 : :
1320 [ + + # # : 288 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1321 [ # # # # : 72 : guard = _dif_generate_guard_copy(ctx->guard_seed, dst, src, ctx->guard_interval,
# # # # ]
1322 [ # # # # ]: 72 : ctx->dif_pi_format);
1323 : 0 : } else {
1324 [ - + - + : 216 : memcpy(dst, src, ctx->guard_interval);
# # # # ]
1325 : : }
1326 : :
1327 [ # # # # : 288 : _dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx);
# # ]
1328 : :
1329 [ # # # # ]: 288 : _dif_sgl_advance(src_sgl, ctx->block_size);
1330 [ # # # # ]: 288 : _dif_sgl_advance(dst_sgl, ctx->block_size);
1331 : 288 : }
1332 : :
1333 : : static void
1334 : 48 : 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 [ + + ]: 336 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1340 : 288 : _dif_overwrite_copy(src_sgl, dst_sgl, offset_blocks, ctx);
1341 : 0 : }
1342 : 48 : }
1343 : :
1344 : : static void
1345 : 24 : _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 : 24 : uint64_t guard = 0;
1349 : 24 : struct spdk_dif dif = {};
1350 : :
1351 [ + - # # : 24 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1352 [ # # # # ]: 24 : guard = _dif_generate_guard_copy_split(ctx->guard_seed, dst_sgl, src_sgl,
1353 [ # # # # : 24 : ctx->guard_interval, ctx->dif_pi_format);
# # # # ]
1354 : 0 : } else {
1355 [ # # # # ]: 0 : _data_copy_split(dst_sgl, src_sgl, ctx->guard_interval);
1356 : : }
1357 : :
1358 [ # # # # : 24 : _dif_sgl_advance(src_sgl, ctx->block_size - ctx->guard_interval);
# # # # ]
1359 : :
1360 : 24 : _dif_generate(&dif, guard, offset_blocks, ctx);
1361 : 24 : dif_store_split(dst_sgl, &dif, ctx);
1362 : 24 : }
1363 : :
1364 : : static void
1365 : 6 : 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 [ + + ]: 30 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1371 : 24 : _dif_overwrite_copy_split(src_sgl, dst_sgl, offset_blocks, ctx);
1372 : 0 : }
1373 : 6 : }
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 : 54 : _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 [ + - # # : 54 : if (!_dif_sgl_is_valid(src_sgl, ctx->block_size * num_blocks) ||
# # # # ]
1387 [ - + # # ]: 54 : !_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 [ - + # # : 54 : 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 [ + + + - : 102 : if (_dif_sgl_is_bytes_multiple(src_sgl, ctx->block_size) &&
# # # # ]
1398 [ # # # # ]: 48 : _dif_sgl_is_bytes_multiple(dst_sgl, ctx->block_size)) {
1399 : 48 : dif_overwrite_copy(src_sgl, dst_sgl, num_blocks, ctx);
1400 : 0 : } else {
1401 : 6 : dif_overwrite_copy_split(src_sgl, dst_sgl, num_blocks, ctx);
1402 : : }
1403 : :
1404 : 54 : return 0;
1405 : 0 : }
1406 : :
1407 : : int
1408 : 1005559 : 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 : 602823 : struct _dif_sgl src_sgl, dst_sgl;
1413 : :
1414 : 1005559 : _dif_sgl_init(&src_sgl, iovs, iovcnt);
1415 : 1005559 : _dif_sgl_init(&dst_sgl, bounce_iovs, bounce_iovcnt);
1416 : :
1417 [ + + - + : 1005613 : if (!(ctx->dif_flags & SPDK_DIF_FLAGS_NVME_PRACT) ||
# # # # #
# ]
1418 [ # # # # : 54 : ctx->md_size == _dif_size(ctx->dif_pi_format)) {
# # # # ]
1419 : 1005505 : return _spdk_dif_insert_copy(&src_sgl, &dst_sgl, num_blocks, ctx);
1420 : : } else {
1421 : 54 : return _spdk_dif_overwrite_copy(&src_sgl, &dst_sgl, num_blocks, ctx);
1422 : : }
1423 : 0 : }
1424 : :
1425 : : static int
1426 : 5202837 : _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 : 3940863 : uint8_t *src, *dst;
1432 : : int rc;
1433 : 5202837 : uint64_t guard = 0;
1434 : :
1435 [ # # # # : 5202837 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1436 : :
1437 : 5202837 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1438 : 5202837 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1439 : :
1440 [ + + # # : 5202837 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1441 [ # # # # ]: 5202285 : guard = _dif_generate_guard_copy(ctx->guard_seed, dst, src, data_block_size,
1442 [ # # # # ]: 5202285 : ctx->dif_pi_format);
1443 [ # # ]: 5202285 : guard = _dif_generate_guard(guard, src + data_block_size,
1444 [ # # # # : 5202285 : ctx->guard_interval - data_block_size, ctx->dif_pi_format);
# # # # ]
1445 : 0 : } else {
1446 [ - + - + ]: 552 : memcpy(dst, src, data_block_size);
1447 : : }
1448 : :
1449 [ # # # # : 5202837 : rc = _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
# # ]
1450 [ + + ]: 5202837 : if (rc != 0) {
1451 : 81 : return rc;
1452 : : }
1453 : :
1454 [ # # # # ]: 5202756 : _dif_sgl_advance(src_sgl, ctx->block_size);
1455 : 5202756 : _dif_sgl_advance(dst_sgl, data_block_size);
1456 : :
1457 : 5202756 : return 0;
1458 : 0 : }
1459 : :
1460 : : static int
1461 : 650385 : 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 [ + + ]: 5853141 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1469 : 5202837 : rc = _dif_strip_copy(src_sgl, dst_sgl, offset_blocks, ctx, err_blk);
1470 [ + + ]: 5202837 : if (rc != 0) {
1471 : 81 : return rc;
1472 : : }
1473 : 0 : }
1474 : :
1475 : 650304 : return 0;
1476 : 0 : }
1477 : :
1478 : : static int
1479 : 177 : _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 : 177 : uint64_t guard = 0;
1485 : 177 : struct spdk_dif dif = {};
1486 : :
1487 [ # # # # : 177 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1488 : :
1489 [ + - # # : 177 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1490 [ # # # # ]: 177 : guard = _dif_generate_guard_copy_split(ctx->guard_seed, dst_sgl, src_sgl,
1491 [ # # # # ]: 177 : data_block_size, ctx->dif_pi_format);
1492 : 177 : guard = dif_generate_guard_split(guard, src_sgl, data_block_size,
1493 [ # # # # ]: 177 : ctx->guard_interval - data_block_size, ctx);
1494 : 0 : } 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 : 177 : dif_load_split(src_sgl, &dif, ctx);
1500 : :
1501 : 177 : return _dif_verify(&dif, guard, offset_blocks, ctx, err_blk);
1502 : : }
1503 : :
1504 : : static int
1505 : 93 : 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 [ + + ]: 198 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1513 : 177 : rc = _dif_strip_copy_split(src_sgl, dst_sgl, offset_blocks, ctx, err_blk);
1514 [ + + ]: 177 : if (rc != 0) {
1515 : 72 : return rc;
1516 : : }
1517 : 0 : }
1518 : :
1519 : 21 : return 0;
1520 : 0 : }
1521 : :
1522 : : static void
1523 : 36 : _dif_disable_strip_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
1524 : : const struct spdk_dif_ctx *ctx)
1525 : : {
1526 : 36 : uint32_t offset = 0, src_len, dst_len, buf_len, data_block_size;
1527 : 36 : uint8_t *src, *dst;
1528 : :
1529 [ # # # # : 36 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1530 : :
1531 [ + + ]: 96 : while (offset < data_block_size) {
1532 : 60 : _dif_sgl_get_buf(src_sgl, &src, &src_len);
1533 : 60 : _dif_sgl_get_buf(dst_sgl, &dst, &dst_len);
1534 [ # # ]: 60 : buf_len = spdk_min(src_len, dst_len);
1535 [ # # ]: 60 : buf_len = spdk_min(buf_len, data_block_size - offset);
1536 : :
1537 [ - + - + ]: 60 : memcpy(dst, src, buf_len);
1538 : :
1539 : 60 : _dif_sgl_advance(src_sgl, buf_len);
1540 : 60 : _dif_sgl_advance(dst_sgl, buf_len);
1541 : 60 : offset += buf_len;
1542 : : }
1543 : :
1544 [ # # # # ]: 36 : _dif_sgl_advance(src_sgl, ctx->md_size);
1545 : 36 : }
1546 : :
1547 : : static void
1548 : 9 : 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 [ + + ]: 45 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1554 : 36 : _dif_disable_strip_copy(src_sgl, dst_sgl, ctx);
1555 : 0 : }
1556 : 9 : }
1557 : :
1558 : : static int
1559 : 650487 : _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 [ # # # # : 650487 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
1566 : :
1567 [ + - # # ]: 650487 : if (!_dif_sgl_is_valid(dst_sgl, data_block_size * num_blocks) ||
1568 [ - + # # ]: 650487 : !_dif_sgl_is_valid(src_sgl, ctx->block_size * num_blocks)) {
1569 : 0 : SPDK_ERRLOG("Size of iovec arrays are not valid\n");
1570 : 0 : return -EINVAL;
1571 : : }
1572 : :
1573 [ + + # # : 650487 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
1574 : 9 : dif_disable_strip_copy(src_sgl, dst_sgl, num_blocks, ctx);
1575 : 9 : return 0;
1576 : : }
1577 : :
1578 [ + + + - ]: 1300863 : if (_dif_sgl_is_bytes_multiple(dst_sgl, data_block_size) &&
1579 [ # # # # ]: 650385 : _dif_sgl_is_bytes_multiple(src_sgl, ctx->block_size)) {
1580 : 650385 : return dif_strip_copy(src_sgl, dst_sgl, num_blocks, ctx, err_blk);
1581 : : } else {
1582 : 93 : return dif_strip_copy_split(src_sgl, dst_sgl, num_blocks, ctx, err_blk);
1583 : : }
1584 : 0 : }
1585 : :
1586 : : static int
1587 : 288 : _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 : 288 : uint64_t guard = 0;
1594 : :
1595 : 288 : _dif_sgl_get_buf(src_sgl, &src, NULL);
1596 : 288 : _dif_sgl_get_buf(dst_sgl, &dst, NULL);
1597 : :
1598 [ + + # # : 288 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1599 [ # # # # : 72 : guard = _dif_generate_guard_copy(ctx->guard_seed, dst, src, ctx->guard_interval,
# # # # ]
1600 [ # # # # ]: 72 : ctx->dif_pi_format);
1601 : 0 : } else {
1602 [ - + - + : 216 : memcpy(dst, src, ctx->guard_interval);
# # # # ]
1603 : : }
1604 : :
1605 [ # # # # : 288 : rc = _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
# # ]
1606 [ - + ]: 288 : if (rc != 0) {
1607 : 0 : return rc;
1608 : : }
1609 : :
1610 [ # # # # ]: 288 : _dif_sgl_advance(src_sgl, ctx->block_size);
1611 [ # # # # ]: 288 : _dif_sgl_advance(dst_sgl, ctx->block_size);
1612 : :
1613 : 288 : return 0;
1614 : 0 : }
1615 : :
1616 : : static int
1617 : 48 : 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 [ + + ]: 336 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1625 : 288 : rc = _dif_verify_copy(src_sgl, dst_sgl, offset_blocks, ctx, err_blk);
1626 [ - + ]: 288 : if (rc != 0) {
1627 : 0 : return rc;
1628 : : }
1629 : 0 : }
1630 : :
1631 : 48 : return 0;
1632 : 0 : }
1633 : :
1634 : : static int
1635 : 24 : _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 : 24 : uint64_t guard = 0;
1640 : 24 : struct spdk_dif dif = {};
1641 : :
1642 [ + - # # : 24 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1643 [ # # # # ]: 24 : guard = _dif_generate_guard_copy_split(ctx->guard_seed, dst_sgl, src_sgl,
1644 [ # # # # : 24 : ctx->guard_interval, ctx->dif_pi_format);
# # # # ]
1645 : 0 : } else {
1646 [ # # # # ]: 0 : _data_copy_split(dst_sgl, src_sgl, ctx->guard_interval);
1647 : : }
1648 : :
1649 : 24 : dif_load_split(src_sgl, &dif, ctx);
1650 [ # # # # : 24 : _dif_sgl_advance(dst_sgl, ctx->block_size - ctx->guard_interval);
# # # # ]
1651 : :
1652 : 24 : return _dif_verify(&dif, guard, offset_blocks, ctx, err_blk);
1653 : : }
1654 : :
1655 : : static int
1656 : 6 : 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 [ + + ]: 30 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1664 : 24 : rc = _dif_verify_copy_split(src_sgl, dst_sgl, offset_blocks, ctx, err_blk);
1665 [ - + ]: 24 : if (rc != 0) {
1666 : 0 : return rc;
1667 : : }
1668 : 0 : }
1669 : :
1670 : 6 : return 0;
1671 : 0 : }
1672 : :
1673 : : static int
1674 : 54 : _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 [ + - # # : 54 : if (!_dif_sgl_is_valid(dst_sgl, ctx->block_size * num_blocks) ||
# # # # ]
1679 [ - + # # ]: 54 : !_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 [ - + # # : 54 : 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 [ + + + - : 102 : if (_dif_sgl_is_bytes_multiple(dst_sgl, ctx->block_size) &&
# # # # ]
1690 [ # # # # ]: 48 : _dif_sgl_is_bytes_multiple(src_sgl, ctx->block_size)) {
1691 : 48 : return dif_verify_copy(src_sgl, dst_sgl, num_blocks, ctx, err_blk);
1692 : : } else {
1693 : 6 : return dif_verify_copy_split(src_sgl, dst_sgl, num_blocks, ctx, err_blk);
1694 : : }
1695 : 0 : }
1696 : :
1697 : : int
1698 : 650541 : 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 : 492789 : struct _dif_sgl src_sgl, dst_sgl;
1704 : :
1705 : 650541 : _dif_sgl_init(&src_sgl, bounce_iovs, bounce_iovcnt);
1706 : 650541 : _dif_sgl_init(&dst_sgl, iovs, iovcnt);
1707 : :
1708 [ + + - + : 650595 : if (!(ctx->dif_flags & SPDK_DIF_FLAGS_NVME_PRACT) ||
# # # # #
# ]
1709 [ # # # # : 54 : ctx->md_size == _dif_size(ctx->dif_pi_format)) {
# # # # ]
1710 : 650487 : return _spdk_dif_strip_copy(&src_sgl, &dst_sgl, num_blocks, ctx, err_blk);
1711 : : } else {
1712 : 54 : return _spdk_dif_verify_copy(&src_sgl, &dst_sgl, num_blocks, ctx, err_blk);
1713 : : }
1714 : 0 : }
1715 : :
1716 : : static void
1717 : 720 : _bit_flip(uint8_t *buf, uint32_t flip_bit)
1718 : : {
1719 : : uint8_t byte;
1720 : :
1721 [ # # ]: 720 : byte = *buf;
1722 [ - + # # ]: 720 : byte ^= 1 << flip_bit;
1723 [ # # ]: 720 : *buf = byte;
1724 : 720 : }
1725 : :
1726 : : static int
1727 : 720 : _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 : 720 : _dif_sgl_advance(sgl, block_size * inject_offset_blocks);
1737 : :
1738 : 720 : offset_in_block = 0;
1739 : :
1740 [ + - ]: 981 : while (offset_in_block < block_size) {
1741 : 981 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
1742 [ # # ]: 981 : buf_len = spdk_min(buf_len, block_size - offset_in_block);
1743 : :
1744 [ + - # # ]: 981 : if (inject_offset_bytes >= offset_in_block &&
1745 [ + + ]: 981 : inject_offset_bytes < offset_in_block + buf_len) {
1746 [ # # ]: 720 : buf += inject_offset_bytes - offset_in_block;
1747 : 720 : _bit_flip(buf, inject_offset_bits);
1748 : 720 : return 0;
1749 : : }
1750 : :
1751 : 261 : _dif_sgl_advance(sgl, buf_len);
1752 : 261 : offset_in_block += buf_len;
1753 : : }
1754 : :
1755 : 0 : return -1;
1756 : 0 : }
1757 : :
1758 : : static int
1759 : 720 : 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 : 720 : srand(time(0));
1768 : :
1769 [ - + ]: 720 : inject_offset_blocks = rand() % num_blocks;
1770 [ - + ]: 720 : inject_offset_bytes = start_inject_bytes + (rand() % inject_range_bytes);
1771 [ # # ]: 720 : inject_offset_bits = rand() % 8;
1772 : :
1773 [ + - ]: 1824 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1774 [ + + ]: 1824 : if (offset_blocks == inject_offset_blocks) {
1775 : 720 : rc = _dif_inject_error(sgl, block_size, num_blocks,
1776 : 0 : inject_offset_blocks,
1777 : 0 : inject_offset_bytes,
1778 : 0 : inject_offset_bits);
1779 [ + - ]: 720 : if (rc == 0) {
1780 [ # # ]: 720 : *inject_offset = inject_offset_blocks;
1781 : 0 : }
1782 : 720 : return rc;
1783 : : }
1784 : 0 : }
1785 : :
1786 : 0 : return -1;
1787 : 0 : }
1788 : :
1789 : : int
1790 : 576 : 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 : 576 : _dif_sgl_init(&sgl, iovs, iovcnt);
1798 : :
1799 [ - + # # : 576 : 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 [ + + ]: 576 : if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
1805 [ # # # # ]: 192 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1806 [ # # # # : 144 : ctx->guard_interval + _dif_reftag_offset(ctx->dif_pi_format),
# # # # ]
1807 [ # # # # ]: 144 : _dif_reftag_size(ctx->dif_pi_format),
1808 : 0 : inject_offset);
1809 [ - + ]: 144 : if (rc != 0) {
1810 : 0 : SPDK_ERRLOG("Failed to inject error to Reference Tag.\n");
1811 : 0 : return rc;
1812 : : }
1813 : 0 : }
1814 : :
1815 [ + + ]: 576 : if (inject_flags & SPDK_DIF_APPTAG_ERROR) {
1816 [ # # # # ]: 192 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1817 [ # # # # : 144 : ctx->guard_interval + _dif_apptag_offset(ctx->dif_pi_format),
# # # # ]
1818 : 144 : _dif_apptag_size(),
1819 : 0 : inject_offset);
1820 [ - + ]: 144 : if (rc != 0) {
1821 : 0 : SPDK_ERRLOG("Failed to inject error to Application Tag.\n");
1822 : 0 : return rc;
1823 : : }
1824 : 0 : }
1825 [ + + ]: 576 : if (inject_flags & SPDK_DIF_GUARD_ERROR) {
1826 [ # # # # ]: 144 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1827 [ # # # # ]: 144 : ctx->guard_interval,
1828 [ # # # # ]: 144 : _dif_guard_size(ctx->dif_pi_format),
1829 : 0 : inject_offset);
1830 [ - + ]: 144 : if (rc != 0) {
1831 : 0 : SPDK_ERRLOG("Failed to inject error to Guard.\n");
1832 : 0 : return rc;
1833 : : }
1834 : 0 : }
1835 : :
1836 [ + + ]: 576 : 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 [ # # # # ]: 144 : rc = dif_inject_error(&sgl, ctx->block_size, num_blocks,
1846 : : 0,
1847 [ # # # # : 144 : ctx->block_size - ctx->md_size,
# # # # ]
1848 : 0 : inject_offset);
1849 [ - + ]: 144 : if (rc != 0) {
1850 : 0 : SPDK_ERRLOG("Failed to inject error to data block.\n");
1851 : 0 : return rc;
1852 : : }
1853 : 0 : }
1854 : :
1855 : 576 : return 0;
1856 : 0 : }
1857 : :
1858 : : static void
1859 : 342 : 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 : 342 : uint32_t offset_blocks = 0;
1863 : 238 : uint8_t *data_buf, *md_buf;
1864 : : uint64_t guard;
1865 : :
1866 [ + + ]: 4038 : while (offset_blocks < num_blocks) {
1867 : 3696 : _dif_sgl_get_buf(data_sgl, &data_buf, NULL);
1868 : 3696 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1869 : :
1870 : 3696 : guard = 0;
1871 [ + + # # : 3696 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1872 [ # # # # : 3090 : guard = _dif_generate_guard(ctx->guard_seed, data_buf, ctx->block_size,
# # # # ]
1873 [ # # # # ]: 3090 : ctx->dif_pi_format);
1874 [ # # # # ]: 3090 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1875 [ # # # # ]: 3090 : ctx->dif_pi_format);
1876 : 0 : }
1877 : :
1878 [ # # # # : 3696 : _dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx);
# # ]
1879 : :
1880 [ # # # # ]: 3696 : _dif_sgl_advance(data_sgl, ctx->block_size);
1881 [ # # # # ]: 3696 : _dif_sgl_advance(md_sgl, ctx->md_size);
1882 : 3696 : offset_blocks++;
1883 : : }
1884 : 342 : }
1885 : :
1886 : : static void
1887 : 225 : _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 : 225 : uint64_t guard = 0;
1893 : :
1894 : 225 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1895 : :
1896 [ + - # # : 225 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1897 [ # # # # ]: 225 : guard = ctx->guard_seed;
1898 : 0 : }
1899 : 225 : offset_in_block = 0;
1900 : :
1901 [ + + # # : 693 : while (offset_in_block < ctx->block_size) {
# # ]
1902 : 468 : _dif_sgl_get_buf(data_sgl, &data_buf, &data_buf_len);
1903 [ # # # # : 468 : data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block);
# # # # #
# ]
1904 : :
1905 [ + - # # : 468 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1906 : 468 : guard = _dif_generate_guard(guard, data_buf, data_buf_len,
1907 [ # # # # ]: 468 : ctx->dif_pi_format);
1908 : 0 : }
1909 : :
1910 : 468 : _dif_sgl_advance(data_sgl, data_buf_len);
1911 : 468 : offset_in_block += data_buf_len;
1912 : : }
1913 : :
1914 [ + - # # : 225 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1915 [ # # # # ]: 225 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1916 [ # # # # ]: 225 : ctx->dif_pi_format);
1917 : 0 : }
1918 : :
1919 [ # # # # ]: 225 : _dif_sgl_advance(md_sgl, ctx->md_size);
1920 : :
1921 [ # # # # : 225 : _dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx);
# # ]
1922 : 225 : }
1923 : :
1924 : : static void
1925 : 99 : 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 [ + + ]: 324 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
1931 : 225 : _dix_generate_split(data_sgl, md_sgl, offset_blocks, ctx);
1932 : 0 : }
1933 : 99 : }
1934 : :
1935 : : int
1936 : 9977 : 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 : 9873 : struct _dif_sgl data_sgl, md_sgl;
1940 : :
1941 : 9977 : _dif_sgl_init(&data_sgl, iovs, iovcnt);
1942 : 9977 : _dif_sgl_init(&md_sgl, md_iov, 1);
1943 : :
1944 [ + - # # : 9977 : if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) ||
# # # # ]
1945 [ - + # # ]: 9977 : !_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 [ + + # # : 9977 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
1951 : 9536 : return 0;
1952 : : }
1953 : :
1954 [ + + # # : 441 : if (_dif_sgl_is_bytes_multiple(&data_sgl, ctx->block_size)) {
# # ]
1955 : 342 : dix_generate(&data_sgl, &md_sgl, num_blocks, ctx);
1956 : 0 : } else {
1957 : 99 : dix_generate_split(&data_sgl, &md_sgl, num_blocks, ctx);
1958 : : }
1959 : :
1960 : 441 : return 0;
1961 : 0 : }
1962 : :
1963 : : static int
1964 : 313637 : 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 : 313637 : uint32_t offset_blocks = 0;
1969 : 100413 : uint8_t *data_buf, *md_buf;
1970 : : uint64_t guard;
1971 : : int rc;
1972 : :
1973 [ + + ]: 2823621 : while (offset_blocks < num_blocks) {
1974 : 2510083 : _dif_sgl_get_buf(data_sgl, &data_buf, NULL);
1975 : 2510083 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
1976 : :
1977 : 2510083 : guard = 0;
1978 [ + + # # : 2510083 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
1979 [ # # # # : 2509417 : guard = _dif_generate_guard(ctx->guard_seed, data_buf, ctx->block_size,
# # # # ]
1980 [ # # # # ]: 2509417 : ctx->dif_pi_format);
1981 [ # # # # ]: 2509417 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
1982 [ # # # # ]: 2509417 : ctx->dif_pi_format);
1983 : 0 : }
1984 : :
1985 [ # # # # : 2510083 : rc = _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
# # ]
1986 [ + + ]: 2510083 : if (rc != 0) {
1987 : 99 : return rc;
1988 : : }
1989 : :
1990 [ # # # # ]: 2509984 : _dif_sgl_advance(data_sgl, ctx->block_size);
1991 [ # # # # ]: 2509984 : _dif_sgl_advance(md_sgl, ctx->md_size);
1992 : 2509984 : offset_blocks++;
1993 : : }
1994 : :
1995 : 313538 : return 0;
1996 : 0 : }
1997 : :
1998 : : static int
1999 : 201 : _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 : 201 : uint64_t guard = 0;
2006 : :
2007 : 201 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
2008 : :
2009 [ + - # # : 201 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2010 [ # # # # ]: 201 : guard = ctx->guard_seed;
2011 : 0 : }
2012 : 201 : offset_in_block = 0;
2013 : :
2014 [ + + # # : 621 : while (offset_in_block < ctx->block_size) {
# # ]
2015 : 420 : _dif_sgl_get_buf(data_sgl, &data_buf, &data_buf_len);
2016 [ # # # # : 420 : data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block);
# # # # #
# ]
2017 : :
2018 [ + - # # : 420 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2019 : 420 : guard = _dif_generate_guard(guard, data_buf, data_buf_len,
2020 [ # # # # ]: 420 : ctx->dif_pi_format);
2021 : 0 : }
2022 : :
2023 : 420 : _dif_sgl_advance(data_sgl, data_buf_len);
2024 : 420 : offset_in_block += data_buf_len;
2025 : : }
2026 : :
2027 [ + - # # : 201 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2028 [ # # # # ]: 201 : guard = _dif_generate_guard(guard, md_buf, ctx->guard_interval,
2029 [ # # # # ]: 201 : ctx->dif_pi_format);
2030 : 0 : }
2031 : :
2032 [ # # # # ]: 201 : _dif_sgl_advance(md_sgl, ctx->md_size);
2033 : :
2034 [ # # # # : 201 : return _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
# # ]
2035 : : }
2036 : :
2037 : : static int
2038 : 99 : 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 [ + + ]: 228 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
2046 : 201 : rc = _dix_verify_split(data_sgl, md_sgl, offset_blocks, ctx, err_blk);
2047 [ + + ]: 201 : if (rc != 0) {
2048 : 72 : return rc;
2049 : : }
2050 : 0 : }
2051 : :
2052 : 27 : return 0;
2053 : 0 : }
2054 : :
2055 : : int
2056 : 453752 : 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 : 240528 : struct _dif_sgl data_sgl, md_sgl;
2061 : :
2062 [ - + # # : 453752 : if (md_iov->iov_base == NULL) {
# # ]
2063 : 0 : SPDK_ERRLOG("Metadata buffer is NULL.\n");
2064 : 0 : return -EINVAL;
2065 : : }
2066 : :
2067 : 453752 : _dif_sgl_init(&data_sgl, iovs, iovcnt);
2068 : 453752 : _dif_sgl_init(&md_sgl, md_iov, 1);
2069 : :
2070 [ + - # # : 453752 : if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) ||
# # # # ]
2071 [ - + # # ]: 453752 : !_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 [ + + # # : 453752 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
2077 : 140016 : return 0;
2078 : : }
2079 : :
2080 [ + + # # : 313736 : if (_dif_sgl_is_bytes_multiple(&data_sgl, ctx->block_size)) {
# # ]
2081 : 313637 : return dix_verify(&data_sgl, &md_sgl, num_blocks, ctx, err_blk);
2082 : : } else {
2083 : 99 : return dix_verify_split(&data_sgl, &md_sgl, num_blocks, ctx, err_blk);
2084 : : }
2085 : 0 : }
2086 : :
2087 : : int
2088 : 144 : 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 : 144 : _dif_sgl_init(&data_sgl, iovs, iovcnt);
2096 : 144 : _dif_sgl_init(&md_sgl, md_iov, 1);
2097 : :
2098 [ + - # # : 144 : if (!_dif_sgl_is_valid(&data_sgl, ctx->block_size * num_blocks) ||
# # # # ]
2099 [ - + # # ]: 144 : !_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 [ + + ]: 144 : if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
2105 [ # # # # ]: 48 : rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks,
2106 [ # # # # : 36 : ctx->guard_interval + _dif_reftag_offset(ctx->dif_pi_format),
# # # # ]
2107 [ # # # # ]: 36 : _dif_reftag_size(ctx->dif_pi_format),
2108 : 0 : inject_offset);
2109 [ - + ]: 36 : if (rc != 0) {
2110 : 0 : SPDK_ERRLOG("Failed to inject error to Reference Tag.\n");
2111 : 0 : return rc;
2112 : : }
2113 : 0 : }
2114 : :
2115 [ + + ]: 144 : if (inject_flags & SPDK_DIF_APPTAG_ERROR) {
2116 [ # # # # ]: 48 : rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks,
2117 [ # # # # : 36 : ctx->guard_interval + _dif_apptag_offset(ctx->dif_pi_format),
# # # # ]
2118 : 36 : _dif_apptag_size(),
2119 : 0 : inject_offset);
2120 [ - + ]: 36 : if (rc != 0) {
2121 : 0 : SPDK_ERRLOG("Failed to inject error to Application Tag.\n");
2122 : 0 : return rc;
2123 : : }
2124 : 0 : }
2125 : :
2126 [ + + ]: 144 : if (inject_flags & SPDK_DIF_GUARD_ERROR) {
2127 [ # # # # ]: 36 : rc = dif_inject_error(&md_sgl, ctx->md_size, num_blocks,
2128 [ # # # # ]: 36 : ctx->guard_interval,
2129 [ # # # # ]: 36 : _dif_guard_size(ctx->dif_pi_format),
2130 : 0 : inject_offset);
2131 [ - + ]: 36 : if (rc != 0) {
2132 : 0 : SPDK_ERRLOG("Failed to inject error to Guard.\n");
2133 : 0 : return rc;
2134 : : }
2135 : 0 : }
2136 : :
2137 [ + + ]: 144 : 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 [ # # # # ]: 36 : rc = dif_inject_error(&data_sgl, ctx->block_size, num_blocks,
2142 : : 0,
2143 [ # # # # ]: 36 : ctx->block_size,
2144 : 0 : inject_offset);
2145 [ - + ]: 36 : if (rc != 0) {
2146 : 0 : SPDK_ERRLOG("Failed to inject error to Guard.\n");
2147 : 0 : return rc;
2148 : : }
2149 : 0 : }
2150 : :
2151 : 144 : return 0;
2152 : 0 : }
2153 : :
2154 : : static uint32_t
2155 : 102025405 : _to_next_boundary(uint32_t offset, uint32_t boundary)
2156 : : {
2157 [ - + ]: 102025405 : return boundary - (offset % boundary);
2158 : : }
2159 : :
2160 : : static uint32_t
2161 : 9024252 : _to_size_with_md(uint32_t size, uint32_t data_block_size, uint32_t block_size)
2162 : : {
2163 [ - + - + ]: 9024252 : return (size / data_block_size) * block_size + (size % data_block_size);
2164 : : }
2165 : :
2166 : : int
2167 : 1851916 : 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 [ + - + - : 1851916 : if (iovs == NULL || iovcnt == 0 || buf_iovs == NULL || buf_iovcnt == 0) {
+ - - + ]
2178 : 0 : return -EINVAL;
2179 : : }
2180 : :
2181 [ # # # # : 1851916 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
2182 : :
2183 [ - + # # : 1851916 : data_unalign = ctx->data_offset % data_block_size;
# # ]
2184 : :
2185 : 1851916 : buf_len = _to_size_with_md(data_unalign + data_offset + data_len, data_block_size,
2186 [ # # # # ]: 1851916 : ctx->block_size);
2187 : 1851916 : buf_len -= data_unalign;
2188 : :
2189 : 1851916 : _dif_sgl_init(&dif_sgl, iovs, iovcnt);
2190 : 1851916 : _dif_sgl_init(&buf_sgl, buf_iovs, buf_iovcnt);
2191 : :
2192 [ + + ]: 1851916 : if (!_dif_sgl_is_valid(&buf_sgl, buf_len)) {
2193 : 3 : SPDK_ERRLOG("Buffer overflow will occur.\n");
2194 : 3 : return -ERANGE;
2195 : : }
2196 : :
2197 [ # # # # ]: 1851913 : buf_offset = _to_size_with_md(data_unalign + data_offset, data_block_size, ctx->block_size);
2198 : 1851913 : buf_offset -= data_unalign;
2199 : :
2200 : 1851913 : _dif_sgl_advance(&buf_sgl, buf_offset);
2201 : :
2202 [ + + ]: 31627927 : while (data_len != 0) {
2203 [ + + # # : 30166388 : len = spdk_min(data_len, _to_next_boundary(ctx->data_offset + data_offset, data_block_size));
# # # # #
# ]
2204 [ + + ]: 30166388 : if (!_dif_sgl_append_split(&dif_sgl, &buf_sgl, len)) {
2205 : 390374 : break;
2206 : : }
2207 [ # # # # ]: 29776014 : _dif_sgl_advance(&buf_sgl, ctx->md_size);
2208 : 29776014 : data_offset += len;
2209 : 29776014 : data_len -= len;
2210 : : }
2211 : :
2212 [ + - ]: 1851913 : if (_mapped_len != NULL) {
2213 [ # # # # ]: 1851913 : *_mapped_len = dif_sgl.total_size;
2214 : 0 : }
2215 : :
2216 [ # # # # ]: 1851913 : return iovcnt - dif_sgl.iovcnt;
2217 : 0 : }
2218 : :
2219 : : static int
2220 : 1128716 : _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 [ # # # # : 1128716 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
2227 : :
2228 [ - + # # : 1128716 : 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 : 1128716 : buf_len = _to_size_with_md(data_unalign + data_offset + data_len, data_block_size,
2234 [ # # # # ]: 1128716 : ctx->block_size);
2235 : 1128716 : buf_len -= data_unalign;
2236 : :
2237 [ + + ]: 1128716 : if (!_dif_sgl_is_valid(sgl, buf_len)) {
2238 : 9 : return -ERANGE;
2239 : : }
2240 : :
2241 [ # # # # ]: 1128707 : buf_offset = _to_size_with_md(data_unalign + data_offset, data_block_size, ctx->block_size);
2242 : 1128707 : buf_offset -= data_unalign;
2243 : :
2244 : 1128707 : _dif_sgl_advance(sgl, buf_offset);
2245 : 1128707 : buf_len -= buf_offset;
2246 : :
2247 : 1128707 : buf_offset += data_unalign;
2248 : :
2249 [ # # ]: 1128707 : *_buf_offset = buf_offset;
2250 [ # # ]: 1128707 : *_buf_len = buf_len;
2251 : :
2252 : 1128707 : return 0;
2253 : 0 : }
2254 : :
2255 : : int
2256 : 147 : 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 : 147 : uint32_t buf_len = 0, buf_offset = 0;
2261 : : uint32_t len, offset_in_block, offset_blocks;
2262 : 147 : uint64_t guard = 0;
2263 : 147 : struct _dif_sgl sgl;
2264 : : int rc;
2265 : :
2266 [ + - - + ]: 147 : if (iovs == NULL || iovcnt == 0) {
2267 : 0 : return -EINVAL;
2268 : : }
2269 : :
2270 [ + - # # : 147 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2271 [ # # # # ]: 147 : guard = ctx->last_guard;
2272 : 0 : }
2273 : :
2274 : 147 : _dif_sgl_init(&sgl, iovs, iovcnt);
2275 : :
2276 : 147 : rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx);
2277 [ + + ]: 147 : if (rc != 0) {
2278 : 9 : return rc;
2279 : : }
2280 : :
2281 [ + + ]: 366 : while (buf_len != 0) {
2282 [ + + # # : 228 : len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size));
# # # # #
# ]
2283 [ - + # # : 228 : offset_in_block = buf_offset % ctx->block_size;
# # ]
2284 [ - + # # : 228 : offset_blocks = buf_offset / ctx->block_size;
# # ]
2285 : :
2286 : 228 : guard = _dif_generate_split(&sgl, offset_in_block, len, guard, offset_blocks, ctx);
2287 : :
2288 : 228 : buf_len -= len;
2289 : 228 : buf_offset += len;
2290 : : }
2291 : :
2292 [ + - # # : 138 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2293 [ # # # # ]: 138 : ctx->last_guard = guard;
2294 : 0 : }
2295 : :
2296 : 138 : return 0;
2297 : 0 : }
2298 : :
2299 : : int
2300 : 925928 : 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 : 925928 : uint32_t buf_len = 0, buf_offset = 0;
2306 : : uint32_t len, offset_in_block, offset_blocks;
2307 : 925928 : uint64_t guard = 0;
2308 : 27 : struct _dif_sgl sgl;
2309 : 925928 : int rc = 0;
2310 : :
2311 [ + - - + ]: 925928 : if (iovs == NULL || iovcnt == 0) {
2312 : 0 : return -EINVAL;
2313 : : }
2314 : :
2315 [ + - # # : 925928 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2316 [ # # # # ]: 925928 : guard = ctx->last_guard;
2317 : 0 : }
2318 : :
2319 : 925928 : _dif_sgl_init(&sgl, iovs, iovcnt);
2320 : :
2321 : 925928 : rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx);
2322 [ - + ]: 925928 : if (rc != 0) {
2323 : 0 : return rc;
2324 : : }
2325 : :
2326 [ + + ]: 16009020 : while (buf_len != 0) {
2327 [ + + # # : 15083092 : len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size));
# # # # #
# ]
2328 [ - + # # : 15083092 : offset_in_block = buf_offset % ctx->block_size;
# # ]
2329 [ - + # # : 15083092 : offset_blocks = buf_offset / ctx->block_size;
# # ]
2330 : :
2331 : 15083092 : rc = _dif_verify_split(&sgl, offset_in_block, len, &guard, offset_blocks,
2332 : 0 : ctx, err_blk);
2333 [ - + ]: 15083092 : if (rc != 0) {
2334 : 0 : goto error;
2335 : : }
2336 : :
2337 : 15083092 : buf_len -= len;
2338 : 15083092 : buf_offset += len;
2339 : : }
2340 : :
2341 [ - + # # : 925928 : if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
# # # # ]
2342 [ # # # # ]: 925928 : ctx->last_guard = guard;
2343 : 0 : }
2344 : 27 : error:
2345 : 925928 : return rc;
2346 : 0 : }
2347 : :
2348 : : int
2349 : 202641 : 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 : 202641 : 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 [ + - - + ]: 202641 : if (iovs == NULL || iovcnt == 0) {
2359 : 0 : return -EINVAL;
2360 : : }
2361 : :
2362 [ # # ]: 202641 : crc32c = *_crc32c;
2363 : 202641 : _dif_sgl_init(&sgl, iovs, iovcnt);
2364 : :
2365 : 202641 : rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx);
2366 [ - + ]: 202641 : if (rc != 0) {
2367 : 0 : return rc;
2368 : : }
2369 : :
2370 [ + + ]: 5965730 : while (buf_len != 0) {
2371 [ + + # # : 5763089 : len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size));
# # # # #
# ]
2372 [ - + # # : 5763089 : offset_in_block = buf_offset % ctx->block_size;
# # ]
2373 : :
2374 : 5763089 : crc32c = _dif_update_crc32c_split(&sgl, offset_in_block, len, crc32c, ctx);
2375 : :
2376 : 5763089 : buf_len -= len;
2377 : 5763089 : buf_offset += len;
2378 : : }
2379 : :
2380 [ # # ]: 202641 : *_crc32c = crc32c;
2381 : :
2382 : 202641 : return 0;
2383 : 0 : }
2384 : :
2385 : : void
2386 : 1211135 : 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 [ - + - + : 1211135 : if (!ctx->md_interleave) {
# # # # ]
2393 : 0 : buf_offset = data_offset;
2394 : 0 : buf_len = data_len;
2395 : 0 : } else {
2396 [ # # # # : 1211135 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
2397 : :
2398 [ - + ]: 1211135 : data_unalign = data_offset % data_block_size;
2399 : :
2400 [ # # # # ]: 1211135 : buf_offset = _to_size_with_md(data_offset, data_block_size, ctx->block_size);
2401 [ # # # # ]: 1211135 : buf_len = _to_size_with_md(data_unalign + data_len, data_block_size, ctx->block_size) -
2402 : 0 : data_unalign;
2403 : : }
2404 : :
2405 [ + - ]: 1211135 : if (_buf_offset != NULL) {
2406 [ # # ]: 1211135 : *_buf_offset = buf_offset;
2407 : 0 : }
2408 : :
2409 [ + - ]: 1211135 : if (_buf_len != NULL) {
2410 [ # # ]: 1211135 : *_buf_len = buf_len;
2411 : 0 : }
2412 : 1211135 : }
2413 : :
2414 : : uint32_t
2415 : 640730 : 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 [ - + - + : 640730 : if (!ctx->md_interleave) {
# # # # ]
2420 : 0 : return data_len;
2421 : : } else {
2422 [ # # # # : 640730 : data_block_size = ctx->block_size - ctx->md_size;
# # # # ]
2423 : :
2424 [ # # # # ]: 640730 : return _to_size_with_md(data_len, data_block_size, ctx->block_size);
2425 : : }
2426 : 0 : }
2427 : :
2428 : : static int
2429 : 216 : _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 : 216 : 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 [ # # # # ]: 216 : _dif_sgl_advance(sgl, ctx->guard_interval);
2441 : 216 : _dif_sgl_copy(&tmp_sgl, sgl);
2442 : :
2443 : : /* Copy the split DIF field to the temporary DIF buffer */
2444 : 216 : offset = 0;
2445 [ + + # # : 486 : while (offset < _dif_size(ctx->dif_pi_format)) {
# # ]
2446 : 270 : _dif_sgl_get_buf(sgl, &buf, &buf_len);
2447 [ + + # # : 270 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset);
# # # # #
# ]
2448 : :
2449 [ - + - + : 270 : memcpy((uint8_t *)&dif + offset, buf, buf_len);
# # ]
2450 : :
2451 : 270 : _dif_sgl_advance(sgl, buf_len);
2452 : 270 : offset += buf_len;
2453 : : }
2454 : :
2455 [ - + ]: 216 : 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 [ + - # # : 216 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
# # ]
2464 [ # # # # : 216 : expected = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
# # # # ]
2465 [ # # # # : 216 : remapped = ctx->remapped_init_ref_tag + ctx->ref_tag_offset + offset_blocks;
# # # # ]
2466 : 0 : } else {
2467 [ # # # # ]: 0 : remapped = ctx->remapped_init_ref_tag;
2468 : : }
2469 : :
2470 : : /* Verify the stored Reference Tag. */
2471 [ + - - + : 216 : 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 [ # # # # ]: 216 : _dif_set_reftag(&dif, remapped, ctx->dif_pi_format);
2477 : :
2478 : 216 : offset = 0;
2479 [ + + # # : 486 : while (offset < _dif_size(ctx->dif_pi_format)) {
# # ]
2480 : 270 : _dif_sgl_get_buf(&tmp_sgl, &buf, &buf_len);
2481 [ + + # # : 270 : buf_len = spdk_min(buf_len, _dif_size(ctx->dif_pi_format) - offset);
# # # # #
# ]
2482 : :
2483 [ - + - + : 270 : memcpy(buf, (uint8_t *)&dif + offset, buf_len);
# # ]
2484 : :
2485 : 270 : _dif_sgl_advance(&tmp_sgl, buf_len);
2486 : 270 : offset += buf_len;
2487 : : }
2488 : :
2489 : 216 : end:
2490 [ # # # # : 216 : _dif_sgl_advance(sgl, ctx->block_size - ctx->guard_interval - _dif_size(ctx->dif_pi_format));
# # # # #
# # # ]
2491 : :
2492 : 216 : return 0;
2493 : 0 : }
2494 : :
2495 : : int
2496 : 36 : 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 : 36 : _dif_sgl_init(&sgl, iovs, iovcnt);
2505 : :
2506 [ - + # # : 36 : 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 [ - + # # : 36 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
2512 : 0 : return 0;
2513 : : }
2514 : :
2515 [ - + # # : 36 : if (!(ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK)) {
# # # # ]
2516 : 0 : return 0;
2517 : : }
2518 : :
2519 [ + + ]: 252 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
2520 [ # # ]: 216 : rc = _dif_remap_ref_tag(&sgl, offset_blocks, ctx, err_blk, check_ref_tag);
2521 [ - + ]: 216 : if (rc != 0) {
2522 : 0 : return rc;
2523 : : }
2524 : 0 : }
2525 : :
2526 : 36 : return 0;
2527 : 0 : }
2528 : :
2529 : : static int
2530 : 600 : _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 : 600 : uint64_t expected = 0, remapped;
2535 : 600 : uint8_t *md_buf;
2536 : : struct spdk_dif *dif;
2537 : :
2538 : 600 : _dif_sgl_get_buf(md_sgl, &md_buf, NULL);
2539 : :
2540 [ # # # # : 600 : dif = (struct spdk_dif *)(md_buf + ctx->guard_interval);
# # ]
2541 : :
2542 [ - + ]: 600 : 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 [ + - # # : 600 : if (ctx->dif_type != SPDK_DIF_TYPE3) {
# # ]
2551 [ # # # # : 600 : expected = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
# # # # ]
2552 [ # # # # : 600 : remapped = ctx->remapped_init_ref_tag + ctx->ref_tag_offset + offset_blocks;
# # # # ]
2553 : 0 : } else {
2554 [ # # # # ]: 0 : remapped = ctx->remapped_init_ref_tag;
2555 : : }
2556 : :
2557 : : /* Verify the stored Reference Tag. */
2558 [ + + - + : 600 : 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 [ # # # # ]: 600 : _dif_set_reftag(dif, remapped, ctx->dif_pi_format);
2564 : :
2565 : 600 : end:
2566 [ # # # # ]: 600 : _dif_sgl_advance(md_sgl, ctx->md_size);
2567 : :
2568 : 600 : return 0;
2569 : 0 : }
2570 : :
2571 : : int
2572 : 36 : 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 : 36 : _dif_sgl_init(&md_sgl, md_iov, 1);
2582 : :
2583 [ - + # # : 36 : 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 [ - + # # : 36 : if (_dif_is_disabled(ctx->dif_type)) {
# # ]
2589 : 0 : return 0;
2590 : : }
2591 : :
2592 [ - + # # : 36 : if (!(ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK)) {
# # # # ]
2593 : 0 : return 0;
2594 : : }
2595 : :
2596 [ + + ]: 636 : for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
2597 [ # # ]: 600 : rc = _dix_remap_ref_tag(&md_sgl, offset_blocks, ctx, err_blk, check_ref_tag);
2598 [ - + ]: 600 : if (rc != 0) {
2599 : 0 : return rc;
2600 : : }
2601 : 0 : }
2602 : :
2603 : 36 : return 0;
2604 : 0 : }
|