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