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