xref: /spdk/lib/util/dif.c (revision 5b1b3ddf33574616fcf1c507af3c61f895a0c6fb)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/dif.h"
35 #include "spdk/crc16.h"
36 #include "spdk/endian.h"
37 #include "spdk/log.h"
38 #include "spdk/util.h"
39 
40 /* Context to iterate a iovec array. */
41 struct _iov_iter {
42 	/* Current iovec in the iteration */
43 	struct iovec *iov;
44 
45 	/* Remaining count of iovecs in the iteration. */
46 	int iovcnt;
47 
48 	/* Current offset in the iovec */
49 	uint32_t iov_offset;
50 };
51 
52 static inline void
53 _iov_iter_init(struct _iov_iter *i, struct iovec *iovs, int iovcnt)
54 {
55 	i->iov = iovs;
56 	i->iovcnt = iovcnt;
57 	i->iov_offset = 0;
58 }
59 
60 static inline bool
61 _iov_iter_cont(struct _iov_iter *i)
62 {
63 	return i->iovcnt != 0;
64 }
65 
66 static inline void
67 _iov_iter_advance(struct _iov_iter *i, uint32_t step)
68 {
69 	i->iov_offset += step;
70 	if (i->iov_offset == i->iov->iov_len) {
71 		i->iov++;
72 		i->iovcnt--;
73 		i->iov_offset = 0;
74 	}
75 }
76 
77 static inline void
78 _iov_iter_get_buf(struct _iov_iter *i, void **_buf, uint32_t *_buf_len)
79 {
80 	if (_buf != NULL) {
81 		*_buf = i->iov->iov_base + i->iov_offset;
82 	}
83 	if (_buf_len != NULL) {
84 		*_buf_len = i->iov->iov_len - i->iov_offset;
85 	}
86 }
87 
88 static void
89 _iov_iter_fast_forward(struct _iov_iter *i, uint32_t offset)
90 {
91 	i->iov_offset = offset;
92 	while (i->iovcnt != 0) {
93 		if (i->iov_offset < i->iov->iov_len) {
94 			break;
95 		}
96 
97 		i->iov_offset -= i->iov->iov_len;
98 		i->iov++;
99 		i->iovcnt--;
100 	}
101 }
102 
103 static bool
104 _are_iovs_bytes_multiple(struct iovec *iovs, int iovcnt, uint32_t bytes)
105 {
106 	int i;
107 
108 	for (i = 0; i < iovcnt; i++) {
109 		if (iovs[i].iov_len % bytes) {
110 			return false;
111 		}
112 	}
113 
114 	return true;
115 }
116 
117 static bool
118 _are_iovs_valid(struct iovec *iovs, int iovcnt, uint32_t bytes)
119 {
120 	uint64_t total = 0;
121 	int i;
122 
123 	for (i = 0; i < iovcnt; i++) {
124 		total += iovs[i].iov_len;
125 	}
126 
127 	return total >= bytes;
128 }
129 
130 static bool
131 _dif_type_is_valid(enum spdk_dif_type dif_type, uint32_t dif_flags)
132 {
133 	switch (dif_type) {
134 	case SPDK_DIF_TYPE1:
135 	case SPDK_DIF_TYPE2:
136 	case SPDK_DIF_DISABLE:
137 		break;
138 	case SPDK_DIF_TYPE3:
139 		if (dif_flags & SPDK_DIF_REFTAG_CHECK) {
140 			SPDK_ERRLOG("Reference Tag should not be checked for Type 3\n");
141 			return false;
142 		}
143 		break;
144 	default:
145 		SPDK_ERRLOG("Unknown DIF Type: %d\n", dif_type);
146 		return false;
147 	}
148 
149 	return true;
150 }
151 
152 static bool
153 _dif_is_disabled(enum spdk_dif_type dif_type)
154 {
155 	if (dif_type == SPDK_DIF_DISABLE) {
156 		return true;
157 	} else {
158 		return false;
159 	}
160 }
161 
162 
163 static uint32_t
164 _get_guard_interval(uint32_t block_size, uint32_t md_size, bool dif_loc, bool md_interleave)
165 {
166 	if (dif_loc) {
167 		/* For metadata formats with more than 8 bytes, if the DIF is
168 		 * contained in the last 8 bytes of metadata, then the CRC
169 		 * covers all metadata up to but excluding these last 8 bytes.
170 		 */
171 		if (md_interleave) {
172 			return block_size - sizeof(struct spdk_dif);
173 		} else {
174 			return md_size - sizeof(struct spdk_dif);
175 		}
176 	} else {
177 		/* For metadata formats with more than 8 bytes, if the DIF is
178 		 * contained in the first 8 bytes of metadata, then the CRC
179 		 * does not cover any metadata.
180 		 */
181 		if (md_interleave) {
182 			return block_size - md_size;
183 		} else {
184 			return 0;
185 		}
186 	}
187 }
188 
189 int
190 spdk_dif_ctx_init(struct spdk_dif_ctx *ctx, uint32_t block_size, uint32_t md_size,
191 		  bool md_interleave, bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
192 		  uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag)
193 {
194 	if (md_size < sizeof(struct spdk_dif)) {
195 		SPDK_ERRLOG("Metadata size is smaller than DIF size.\n");
196 		return -EINVAL;
197 	}
198 
199 	if (md_interleave) {
200 		if (block_size < md_size) {
201 			SPDK_ERRLOG("Block size is smaller than DIF size.\n");
202 			return -EINVAL;
203 		}
204 	} else {
205 		if (block_size == 0 || (block_size % 512) != 0) {
206 			SPDK_ERRLOG("Zero block size is not allowed\n");
207 			return -EINVAL;
208 		}
209 	}
210 
211 	if (!_dif_type_is_valid(dif_type, dif_flags)) {
212 		SPDK_ERRLOG("DIF type is invalid.\n");
213 		return -EINVAL;
214 	}
215 
216 	ctx->block_size = block_size;
217 	ctx->md_size = md_size;
218 	ctx->guard_interval = _get_guard_interval(block_size, md_size, dif_loc, md_interleave);
219 	ctx->dif_type = dif_type;
220 	ctx->dif_flags = dif_flags;
221 	ctx->init_ref_tag = init_ref_tag;
222 	ctx->apptag_mask = apptag_mask;
223 	ctx->app_tag = app_tag;
224 
225 	return 0;
226 }
227 
228 static void
229 _dif_generate(void *_dif, uint16_t guard, uint32_t offset_blocks,
230 	      const struct spdk_dif_ctx *ctx)
231 {
232 	struct spdk_dif *dif = _dif;
233 	uint32_t ref_tag;
234 
235 	if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
236 		to_be16(&dif->guard, guard);
237 	}
238 
239 	if (ctx->dif_flags & SPDK_DIF_APPTAG_CHECK) {
240 		to_be16(&dif->app_tag, ctx->app_tag);
241 	}
242 
243 	if (ctx->dif_flags & SPDK_DIF_REFTAG_CHECK) {
244 		/* For type 1 and 2, the reference tag is incremented for each
245 		 * subsequent logical block. For type 3, the reference tag
246 		 * remains the same as the initial reference tag.
247 		 */
248 		if (ctx->dif_type != SPDK_DIF_TYPE3) {
249 			ref_tag = ctx->init_ref_tag + offset_blocks;
250 		} else {
251 			ref_tag = ctx->init_ref_tag;
252 		}
253 
254 		to_be32(&dif->ref_tag, ref_tag);
255 	}
256 }
257 
258 static void
259 dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
260 	     const struct spdk_dif_ctx *ctx)
261 {
262 	struct _iov_iter iter;
263 	uint32_t offset_blocks;
264 	void *buf;
265 	uint16_t guard = 0;
266 
267 	offset_blocks = 0;
268 	_iov_iter_init(&iter, iovs, iovcnt);
269 
270 	while (offset_blocks < num_blocks && _iov_iter_cont(&iter)) {
271 		_iov_iter_get_buf(&iter, &buf, NULL);
272 
273 		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
274 			guard = spdk_crc16_t10dif(0, buf, ctx->guard_interval);
275 		}
276 
277 		_dif_generate(buf + ctx->guard_interval, guard, offset_blocks, ctx);
278 
279 		_iov_iter_advance(&iter, ctx->block_size);
280 		offset_blocks++;
281 	}
282 }
283 
284 static void
285 _dif_generate_split(struct _iov_iter *iter, uint32_t offset_blocks,
286 		    const struct spdk_dif_ctx *ctx)
287 {
288 	uint32_t offset_in_block, offset_in_dif, buf_len;
289 	void *buf;
290 	uint16_t guard;
291 	struct spdk_dif dif = {};
292 
293 	guard = 0;
294 	offset_in_block = 0;
295 
296 	while (offset_in_block < ctx->block_size && _iov_iter_cont(iter)) {
297 		_iov_iter_get_buf(iter, &buf, &buf_len);
298 
299 		if (offset_in_block < ctx->guard_interval) {
300 			buf_len = spdk_min(buf_len, ctx->guard_interval - offset_in_block);
301 
302 			if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
303 				/* Compute CRC over split logical block data. */
304 				guard = spdk_crc16_t10dif(guard, buf, buf_len);
305 			}
306 
307 			if (offset_in_block + buf_len == ctx->guard_interval) {
308 				/* If a whole logical block data is parsed, generate DIF
309 				 * and save it to the temporary DIF area.
310 				 */
311 				_dif_generate(&dif, guard, offset_blocks, ctx);
312 			}
313 		} else if (offset_in_block < ctx->guard_interval + sizeof(struct spdk_dif)) {
314 			/* Copy generated DIF to the split DIF field. */
315 			offset_in_dif = offset_in_block - ctx->guard_interval;
316 			buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset_in_dif);
317 
318 			memcpy(buf, ((uint8_t *)&dif) + offset_in_dif, buf_len);
319 		} else {
320 			/* Skip metadata field after DIF field. */
321 			buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block);
322 		}
323 
324 		_iov_iter_advance(iter, buf_len);
325 		offset_in_block += buf_len;
326 	}
327 }
328 
329 static void
330 dif_generate_split(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
331 		   const struct spdk_dif_ctx *ctx)
332 {
333 	struct _iov_iter iter;
334 	uint32_t offset_blocks;
335 
336 	offset_blocks = 0;
337 	_iov_iter_init(&iter, iovs, iovcnt);
338 
339 	while (offset_blocks < num_blocks && _iov_iter_cont(&iter)) {
340 		_dif_generate_split(&iter, offset_blocks, ctx);
341 		offset_blocks++;
342 	}
343 }
344 
345 int
346 spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
347 		  const struct spdk_dif_ctx *ctx)
348 {
349 	if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks)) {
350 		SPDK_ERRLOG("Size of iovec array is not valid.\n");
351 		return -EINVAL;
352 	}
353 
354 	if (_dif_is_disabled(ctx->dif_type)) {
355 		return 0;
356 	}
357 
358 	if (_are_iovs_bytes_multiple(iovs, iovcnt, ctx->block_size)) {
359 		dif_generate(iovs, iovcnt, num_blocks, ctx);
360 	} else {
361 		dif_generate_split(iovs, iovcnt, num_blocks, ctx);
362 	}
363 
364 	return 0;
365 }
366 
367 static void
368 _dif_error_set(struct spdk_dif_error *err_blk, uint8_t err_type,
369 	       uint32_t expected, uint32_t actual, uint32_t err_offset)
370 {
371 	if (err_blk) {
372 		err_blk->err_type = err_type;
373 		err_blk->expected = expected;
374 		err_blk->actual = actual;
375 		err_blk->err_offset = err_offset;
376 	}
377 }
378 
379 static int
380 _dif_verify(void *_dif, uint16_t guard, uint32_t offset_blocks,
381 	    const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
382 {
383 	struct spdk_dif *dif = _dif;
384 	uint16_t _guard;
385 	uint16_t _app_tag;
386 	uint32_t ref_tag, _ref_tag;
387 
388 	switch (ctx->dif_type) {
389 	case SPDK_DIF_TYPE1:
390 	case SPDK_DIF_TYPE2:
391 		/* If Type 1 or 2 is used, then all DIF checks are disabled when
392 		 * the Application Tag is 0xFFFF.
393 		 */
394 		if (dif->app_tag == 0xFFFF) {
395 			return 0;
396 		}
397 		break;
398 	case SPDK_DIF_TYPE3:
399 		/* If Type 3 is used, then all DIF checks are disabled when the
400 		 * Application Tag is 0xFFFF and the Reference Tag is 0xFFFFFFFF.
401 		 */
402 		if (dif->app_tag == 0xFFFF && dif->ref_tag == 0xFFFFFFFF) {
403 			return 0;
404 		}
405 		break;
406 	default:
407 		break;
408 	}
409 
410 	/* For type 1 and 2, the reference tag is incremented for each
411 	 * subsequent logical block. For type 3, the reference tag
412 	 * remains the same as the initial reference tag.
413 	 */
414 	if (ctx->dif_type != SPDK_DIF_TYPE3) {
415 		ref_tag = ctx->init_ref_tag + offset_blocks;
416 	} else {
417 		ref_tag = ctx->init_ref_tag;
418 	}
419 
420 	if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
421 		/* Compare the DIF Guard field to the CRC computed over the logical
422 		 * block data.
423 		 */
424 		_guard = from_be16(&dif->guard);
425 		if (_guard != guard) {
426 			_dif_error_set(err_blk, SPDK_DIF_GUARD_ERROR, _guard, guard,
427 				       offset_blocks);
428 			SPDK_ERRLOG("Failed to compare Guard: LBA=%" PRIu32 "," \
429 				    "  Expected=%x, Actual=%x\n",
430 				    ref_tag, _guard, guard);
431 			return -1;
432 		}
433 	}
434 
435 	if (ctx->dif_flags & SPDK_DIF_APPTAG_CHECK) {
436 		/* Compare unmasked bits in the DIF Application Tag field to the
437 		 * passed Application Tag.
438 		 */
439 		_app_tag = from_be16(&dif->app_tag);
440 		if ((_app_tag & ctx->apptag_mask) != ctx->app_tag) {
441 			_dif_error_set(err_blk, SPDK_DIF_APPTAG_ERROR, ctx->app_tag,
442 				       (_app_tag & ctx->apptag_mask), offset_blocks);
443 			SPDK_ERRLOG("Failed to compare App Tag: LBA=%" PRIu32 "," \
444 				    "  Expected=%x, Actual=%x\n",
445 				    ref_tag, ctx->app_tag, (_app_tag & ctx->apptag_mask));
446 			return -1;
447 		}
448 	}
449 
450 	if (ctx->dif_flags & SPDK_DIF_REFTAG_CHECK) {
451 		switch (ctx->dif_type) {
452 		case SPDK_DIF_TYPE1:
453 		case SPDK_DIF_TYPE2:
454 			/* Compare the DIF Reference Tag field to the passed Reference Tag.
455 			 * The passed Reference Tag will be the least significant 4 bytes
456 			 * of the LBA when Type 1 is used, and application specific value
457 			 * if Type 2 is used,
458 			 */
459 			_ref_tag = from_be32(&dif->ref_tag);
460 			if (_ref_tag != ref_tag) {
461 				_dif_error_set(err_blk, SPDK_DIF_REFTAG_ERROR, ref_tag,
462 					       _ref_tag, offset_blocks);
463 				SPDK_ERRLOG("Failed to compare Ref Tag: LBA=%" PRIu32 "," \
464 					    " Expected=%x, Actual=%x\n",
465 					    ref_tag, ref_tag, _ref_tag);
466 				return -1;
467 			}
468 			break;
469 		case SPDK_DIF_TYPE3:
470 			/* For Type 3, computed Reference Tag remains unchanged.
471 			 * Hence ignore the Reference Tag field.
472 			 */
473 			break;
474 		default:
475 			break;
476 		}
477 	}
478 
479 	return 0;
480 }
481 
482 static int
483 dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
484 	   const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
485 {
486 	struct _iov_iter iter;
487 	uint32_t offset_blocks;
488 	int rc;
489 	void *buf;
490 	uint16_t guard = 0;
491 
492 	offset_blocks = 0;
493 	_iov_iter_init(&iter, iovs, iovcnt);
494 
495 	while (offset_blocks < num_blocks && _iov_iter_cont(&iter)) {
496 		_iov_iter_get_buf(&iter, &buf, NULL);
497 
498 		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
499 			guard = spdk_crc16_t10dif(0, buf, ctx->guard_interval);
500 		}
501 
502 		rc = _dif_verify(buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
503 		if (rc != 0) {
504 			return rc;
505 		}
506 
507 		_iov_iter_advance(&iter, ctx->block_size);
508 		offset_blocks++;
509 	}
510 
511 	return 0;
512 }
513 
514 static int
515 _dif_verify_split(struct _iov_iter *iter, uint32_t offset_blocks,
516 		  const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
517 {
518 	uint32_t offset_in_block, offset_in_dif, buf_len;
519 	void *buf;
520 	uint16_t guard;
521 	struct spdk_dif dif = {};
522 
523 	guard = 0;
524 	offset_in_block = 0;
525 
526 	while (offset_in_block < ctx->block_size && _iov_iter_cont(iter)) {
527 		_iov_iter_get_buf(iter, &buf, &buf_len);
528 
529 		if (offset_in_block < ctx->guard_interval) {
530 			buf_len = spdk_min(buf_len, ctx->guard_interval - offset_in_block);
531 
532 			if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
533 				/* Compute CRC over split logical block data. */
534 				guard = spdk_crc16_t10dif(guard, buf, buf_len);
535 			}
536 		} else if (offset_in_block < ctx->guard_interval + sizeof(struct spdk_dif)) {
537 			/* Copy the split DIF field to the temporary DIF buffer. */
538 			offset_in_dif = offset_in_block - ctx->guard_interval;
539 			buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset_in_dif);
540 
541 			memcpy((uint8_t *)&dif + offset_in_dif, buf, buf_len);
542 		} else {
543 			/* Skip metadata field after DIF field. */
544 			buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block);
545 		}
546 
547 		_iov_iter_advance(iter, buf_len);
548 		offset_in_block += buf_len;
549 	}
550 
551 	return _dif_verify(&dif, guard, offset_blocks, ctx, err_blk);
552 }
553 
554 static int
555 dif_verify_split(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
556 		 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
557 {
558 	struct _iov_iter iter;
559 	uint32_t offset_blocks;
560 	int rc;
561 
562 	offset_blocks = 0;
563 	_iov_iter_init(&iter, iovs, iovcnt);
564 
565 	while (offset_blocks < num_blocks && _iov_iter_cont(&iter)) {
566 		rc = _dif_verify_split(&iter, offset_blocks, ctx, err_blk);
567 		if (rc != 0) {
568 			return rc;
569 		}
570 		offset_blocks++;
571 	}
572 
573 	return 0;
574 }
575 
576 int
577 spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
578 		const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
579 {
580 	if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks)) {
581 		SPDK_ERRLOG("Size of iovec array is not valid.\n");
582 		return -EINVAL;
583 	}
584 
585 	if (_dif_is_disabled(ctx->dif_type)) {
586 		return 0;
587 	}
588 
589 	if (_are_iovs_bytes_multiple(iovs, iovcnt, ctx->block_size)) {
590 		return dif_verify(iovs, iovcnt, num_blocks, ctx, err_blk);
591 	} else {
592 		return dif_verify_split(iovs, iovcnt, num_blocks, ctx, err_blk);
593 	}
594 }
595 
596 static void
597 dif_generate_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov,
598 		  uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
599 {
600 	struct _iov_iter src_iter, dst_iter;
601 	uint32_t offset_blocks, data_block_size;
602 	void *src, *dst;
603 	uint16_t guard;
604 
605 	offset_blocks = 0;
606 	_iov_iter_init(&src_iter, iovs, iovcnt);
607 	_iov_iter_init(&dst_iter, bounce_iov, 1);
608 
609 	data_block_size = ctx->block_size - ctx->md_size;
610 
611 	while (offset_blocks < num_blocks &&
612 	       _iov_iter_cont(&src_iter) && _iov_iter_cont(&dst_iter)) {
613 
614 		_iov_iter_get_buf(&src_iter, &src, NULL);
615 		_iov_iter_get_buf(&dst_iter, &dst, NULL);
616 
617 		guard = 0;
618 		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
619 			guard = spdk_crc16_t10dif_copy(0, dst, src, data_block_size);
620 			guard = spdk_crc16_t10dif(guard, dst + data_block_size,
621 						  ctx->guard_interval - data_block_size);
622 		} else {
623 			memcpy(dst, src, data_block_size);
624 		}
625 
626 		_dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx);
627 
628 		_iov_iter_advance(&src_iter, data_block_size);
629 		_iov_iter_advance(&dst_iter, ctx->block_size);
630 		offset_blocks++;
631 	}
632 }
633 
634 static void
635 _dif_generate_copy_split(struct _iov_iter *src_iter, struct _iov_iter *dst_iter,
636 			 uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
637 {
638 	uint32_t offset_in_block, src_len, data_block_size;
639 	uint16_t guard;
640 	void *src, *dst;
641 
642 	_iov_iter_get_buf(dst_iter, &dst, NULL);
643 
644 	data_block_size = ctx->block_size - ctx->md_size;
645 
646 	guard = 0;
647 	offset_in_block = 0;
648 
649 	while (offset_in_block < data_block_size && _iov_iter_cont(src_iter)) {
650 		/* Compute CRC over split logical block data and copy
651 		 * data to bounce buffer.
652 		 */
653 		_iov_iter_get_buf(src_iter, &src, &src_len);
654 		src_len = spdk_min(src_len, data_block_size - offset_in_block);
655 
656 		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
657 			guard = spdk_crc16_t10dif_copy(guard, dst + offset_in_block,
658 						       src, src_len);
659 		} else {
660 			memcpy(dst + offset_in_block, src, src_len);
661 		}
662 
663 		_iov_iter_advance(src_iter, src_len);
664 		offset_in_block += src_len;
665 	}
666 
667 	if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
668 		guard = spdk_crc16_t10dif(guard, dst + data_block_size,
669 					  ctx->guard_interval - data_block_size);
670 	}
671 
672 	_iov_iter_advance(dst_iter, ctx->block_size);
673 
674 	_dif_generate(dst + ctx->guard_interval, guard, offset_blocks, ctx);
675 }
676 
677 static void
678 dif_generate_copy_split(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov,
679 			uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
680 {
681 	struct _iov_iter src_iter, dst_iter;
682 	uint32_t offset_blocks;
683 
684 	offset_blocks = 0;
685 	_iov_iter_init(&src_iter, iovs, iovcnt);
686 	_iov_iter_init(&dst_iter, bounce_iov, 1);
687 
688 	while (offset_blocks < num_blocks &&
689 	       _iov_iter_cont(&src_iter) && _iov_iter_cont(&dst_iter)) {
690 		_dif_generate_copy_split(&src_iter, &dst_iter, offset_blocks, ctx);
691 		offset_blocks++;
692 	}
693 }
694 
695 int
696 spdk_dif_generate_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov,
697 		       uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
698 {
699 	uint32_t data_block_size;
700 
701 	data_block_size = ctx->block_size - ctx->md_size;
702 
703 	if (!_are_iovs_valid(iovs, iovcnt, data_block_size * num_blocks) ||
704 	    !_are_iovs_valid(bounce_iov, 1, ctx->block_size * num_blocks)) {
705 		SPDK_ERRLOG("Size of iovec arrays are not valid.\n");
706 		return -EINVAL;
707 	}
708 
709 	if (_dif_is_disabled(ctx->dif_type)) {
710 		return 0;
711 	}
712 
713 	if (_are_iovs_bytes_multiple(iovs, iovcnt, data_block_size)) {
714 		dif_generate_copy(iovs, iovcnt, bounce_iov, num_blocks, ctx);
715 	} else {
716 		dif_generate_copy_split(iovs, iovcnt, bounce_iov, num_blocks, ctx);
717 	}
718 
719 	return 0;
720 }
721 
722 static int
723 dif_verify_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov,
724 		uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
725 		struct spdk_dif_error *err_blk)
726 {
727 	struct _iov_iter src_iter, dst_iter;
728 	uint32_t offset_blocks, data_block_size;
729 	void *src, *dst;
730 	int rc;
731 	uint16_t guard;
732 
733 	offset_blocks = 0;
734 	_iov_iter_init(&src_iter, bounce_iov, 1);
735 	_iov_iter_init(&dst_iter, iovs, iovcnt);
736 
737 	data_block_size = ctx->block_size - ctx->md_size;
738 
739 	while (offset_blocks < num_blocks && _iov_iter_cont(&src_iter) &&
740 	       _iov_iter_cont(&dst_iter)) {
741 
742 		_iov_iter_get_buf(&src_iter, &src, NULL);
743 		_iov_iter_get_buf(&dst_iter, &dst, NULL);
744 
745 		guard = 0;
746 		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
747 			guard = spdk_crc16_t10dif_copy(0, dst, src, data_block_size);
748 			guard = spdk_crc16_t10dif(guard, src + data_block_size,
749 						  ctx->guard_interval - data_block_size);
750 		} else {
751 			memcpy(dst, src, data_block_size);
752 		}
753 
754 		rc = _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
755 		if (rc != 0) {
756 			return rc;
757 		}
758 
759 		_iov_iter_advance(&src_iter, ctx->block_size);
760 		_iov_iter_advance(&dst_iter, data_block_size);
761 		offset_blocks++;
762 	}
763 
764 	return 0;
765 }
766 
767 static int
768 _dif_verify_copy_split(struct _iov_iter *src_iter, struct _iov_iter *dst_iter,
769 		       uint32_t offset_blocks, const struct spdk_dif_ctx *ctx,
770 		       struct spdk_dif_error *err_blk)
771 {
772 	uint32_t offset_in_block, dst_len, data_block_size;
773 	uint16_t guard;
774 	void *src, *dst;
775 
776 	_iov_iter_get_buf(src_iter, &src, NULL);
777 
778 	data_block_size = ctx->block_size - ctx->md_size;
779 
780 	guard = 0;
781 	offset_in_block = 0;
782 
783 	while (offset_in_block < data_block_size) {
784 		/* Compute CRC over split logical block data and copy
785 		 * data to bounce buffer.
786 		 */
787 		_iov_iter_get_buf(dst_iter, &dst, &dst_len);
788 		dst_len = spdk_min(dst_len, data_block_size - offset_in_block);
789 
790 		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
791 			guard = spdk_crc16_t10dif_copy(guard, dst,
792 						       src + offset_in_block, dst_len);
793 		} else {
794 			memcpy(dst, src + offset_in_block, dst_len);
795 		}
796 
797 		_iov_iter_advance(dst_iter, dst_len);
798 		offset_in_block += dst_len;
799 	}
800 
801 	if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
802 		guard = spdk_crc16_t10dif(guard, src + data_block_size,
803 					  ctx->guard_interval - data_block_size);
804 	}
805 
806 	_iov_iter_advance(src_iter, ctx->block_size);
807 
808 	return _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
809 }
810 
811 static int
812 dif_verify_copy_split(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov,
813 		      uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
814 		      struct spdk_dif_error *err_blk)
815 {
816 	struct _iov_iter src_iter, dst_iter;
817 	uint32_t offset_blocks;
818 	int rc;
819 
820 	offset_blocks = 0;
821 	_iov_iter_init(&src_iter, bounce_iov, 1);
822 	_iov_iter_init(&dst_iter, iovs, iovcnt);
823 
824 	while (offset_blocks < num_blocks &&
825 	       _iov_iter_cont(&src_iter) && _iov_iter_cont(&dst_iter)) {
826 		rc = _dif_verify_copy_split(&src_iter, &dst_iter, offset_blocks, ctx, err_blk);
827 		if (rc != 0) {
828 			return rc;
829 		}
830 		offset_blocks++;
831 	}
832 
833 	return 0;
834 }
835 
836 int
837 spdk_dif_verify_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov,
838 		     uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
839 		     struct spdk_dif_error *err_blk)
840 {
841 	uint32_t data_block_size;
842 
843 	data_block_size = ctx->block_size - ctx->md_size;
844 
845 	if (!_are_iovs_valid(iovs, iovcnt, data_block_size * num_blocks) ||
846 	    !_are_iovs_valid(bounce_iov, 1, ctx->block_size * num_blocks)) {
847 		SPDK_ERRLOG("Size of iovec arrays are not valid\n");
848 		return -EINVAL;
849 	}
850 
851 	if (_dif_is_disabled(ctx->dif_type)) {
852 		return 0;
853 	}
854 
855 	if (_are_iovs_bytes_multiple(iovs, iovcnt, data_block_size)) {
856 		return dif_verify_copy(iovs, iovcnt, bounce_iov, num_blocks, ctx, err_blk);
857 	} else {
858 		return dif_verify_copy_split(iovs, iovcnt, bounce_iov, num_blocks, ctx, err_blk);
859 	}
860 }
861 
862 static void
863 _bit_flip(uint8_t *buf, uint32_t flip_bit)
864 {
865 	uint8_t byte;
866 
867 	byte = *buf;
868 	byte ^= 1 << flip_bit;
869 	*buf = byte;
870 }
871 
872 static int
873 _dif_inject_error(struct iovec *iovs, int iovcnt,
874 		  uint32_t block_size, uint32_t num_blocks,
875 		  uint32_t inject_offset_blocks,
876 		  uint32_t inject_offset_bytes,
877 		  uint32_t inject_offset_bits)
878 {
879 	struct _iov_iter iter;
880 	uint32_t offset_in_block, buf_len;
881 	void *buf;
882 
883 	_iov_iter_init(&iter, iovs, iovcnt);
884 
885 	_iov_iter_fast_forward(&iter, block_size * inject_offset_blocks);
886 
887 	offset_in_block = 0;
888 
889 	while (offset_in_block < block_size && _iov_iter_cont(&iter)) {
890 		_iov_iter_get_buf(&iter, &buf, &buf_len);
891 		buf_len = spdk_min(buf_len, block_size - offset_in_block);
892 
893 		if (inject_offset_bytes >= offset_in_block &&
894 		    inject_offset_bytes < offset_in_block + buf_len) {
895 			buf += inject_offset_bytes - offset_in_block;
896 			_bit_flip(buf, inject_offset_bits);
897 			return 0;
898 		}
899 
900 		_iov_iter_advance(&iter, buf_len);
901 		offset_in_block += buf_len;
902 	}
903 
904 	return -1;
905 }
906 
907 static int
908 dif_inject_error(struct iovec *iovs, int iovcnt,
909 		 uint32_t block_size, uint32_t num_blocks,
910 		 uint32_t start_inject_bytes, uint32_t inject_range_bytes,
911 		 uint32_t *inject_offset)
912 {
913 	uint32_t inject_offset_blocks, inject_offset_bytes, inject_offset_bits;
914 	uint32_t offset_blocks;
915 	int rc;
916 
917 	srand(time(0));
918 
919 	inject_offset_blocks = rand() % num_blocks;
920 	inject_offset_bytes = start_inject_bytes + (rand() % inject_range_bytes);
921 	inject_offset_bits = rand() % 8;
922 
923 	for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
924 		if (offset_blocks == inject_offset_blocks) {
925 			rc = _dif_inject_error(iovs, iovcnt, block_size, num_blocks,
926 					       inject_offset_blocks,
927 					       inject_offset_bytes,
928 					       inject_offset_bits);
929 			if (rc == 0) {
930 				*inject_offset = inject_offset_blocks;
931 			}
932 			return rc;
933 		}
934 	}
935 
936 	return -1;
937 }
938 
939 #define _member_size(type, member)	sizeof(((type *)0)->member)
940 
941 int
942 spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
943 		      const struct spdk_dif_ctx *ctx, uint32_t inject_flags,
944 		      uint32_t *inject_offset)
945 {
946 	int rc;
947 
948 	if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks)) {
949 		SPDK_ERRLOG("Size of iovec array is not valid.\n");
950 		return -EINVAL;
951 	}
952 
953 	if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
954 		rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
955 				      ctx->guard_interval + offsetof(struct spdk_dif, ref_tag),
956 				      _member_size(struct spdk_dif, ref_tag),
957 				      inject_offset);
958 		if (rc != 0) {
959 			SPDK_ERRLOG("Failed to inject error to Reference Tag.\n");
960 			return rc;
961 		}
962 	}
963 
964 	if (inject_flags & SPDK_DIF_APPTAG_ERROR) {
965 		rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
966 				      ctx->guard_interval + offsetof(struct spdk_dif, app_tag),
967 				      _member_size(struct spdk_dif, app_tag),
968 				      inject_offset);
969 		if (rc != 0) {
970 			SPDK_ERRLOG("Failed to inject error to Application Tag.\n");
971 			return rc;
972 		}
973 	}
974 	if (inject_flags & SPDK_DIF_GUARD_ERROR) {
975 		rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
976 				      ctx->guard_interval,
977 				      _member_size(struct spdk_dif, guard),
978 				      inject_offset);
979 		if (rc != 0) {
980 			SPDK_ERRLOG("Failed to inject error to Guard.\n");
981 			return rc;
982 		}
983 	}
984 
985 	if (inject_flags & SPDK_DIF_DATA_ERROR) {
986 		/* If the DIF information is contained within the last 8 bytes of
987 		 * metadata, then the CRC covers all metadata bytes up to but excluding
988 		 * the last 8 bytes. But error injection does not cover these metadata
989 		 * because classification is not determined yet.
990 		 *
991 		 * Note: Error injection to data block is expected to be detected as
992 		 * guard error.
993 		 */
994 		rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
995 				      0,
996 				      ctx->block_size - ctx->md_size,
997 				      inject_offset);
998 		if (rc != 0) {
999 			SPDK_ERRLOG("Failed to inject error to data block.\n");
1000 			return rc;
1001 		}
1002 	}
1003 
1004 	return 0;
1005 }
1006 
1007 static void
1008 dix_generate(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1009 	     uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1010 {
1011 	struct _iov_iter data_iter, md_iter;
1012 	uint32_t offset_blocks;
1013 	uint16_t guard;
1014 	void *data_buf, *md_buf;
1015 
1016 	offset_blocks = 0;
1017 	_iov_iter_init(&data_iter, iovs, iovcnt);
1018 	_iov_iter_init(&md_iter, md_iov, 1);
1019 
1020 	while (offset_blocks < num_blocks &&
1021 	       _iov_iter_cont(&data_iter) && _iov_iter_cont(&md_iter)) {
1022 
1023 		_iov_iter_get_buf(&data_iter, &data_buf, NULL);
1024 		_iov_iter_get_buf(&md_iter, &md_buf, NULL);
1025 
1026 		guard = 0;
1027 		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
1028 			guard = spdk_crc16_t10dif(0, data_buf, ctx->block_size);
1029 			guard = spdk_crc16_t10dif(guard, md_buf, ctx->guard_interval);
1030 		}
1031 
1032 		_dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx);
1033 
1034 		_iov_iter_advance(&data_iter, ctx->block_size);
1035 		_iov_iter_advance(&md_iter, ctx->md_size);
1036 		offset_blocks++;
1037 	}
1038 }
1039 
1040 static void
1041 _dix_generate_split(struct _iov_iter *data_iter, struct _iov_iter *md_iter,
1042 		    uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
1043 {
1044 	uint32_t offset_in_block, data_buf_len;
1045 	uint16_t guard;
1046 	void *data_buf, *md_buf;
1047 
1048 	_iov_iter_get_buf(md_iter, &md_buf, NULL);
1049 
1050 	guard = 0;
1051 	if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
1052 		guard = spdk_crc16_t10dif(0, md_buf, ctx->guard_interval);
1053 	}
1054 
1055 	offset_in_block = 0;
1056 
1057 	while (offset_in_block < ctx->block_size && _iov_iter_cont(data_iter)) {
1058 		_iov_iter_get_buf(data_iter, &data_buf, &data_buf_len);
1059 		data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block);
1060 
1061 		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
1062 			guard = spdk_crc16_t10dif(guard, data_buf, data_buf_len);
1063 		}
1064 
1065 		_iov_iter_advance(data_iter, data_buf_len);
1066 		offset_in_block += data_buf_len;
1067 	}
1068 
1069 	_iov_iter_advance(md_iter, ctx->md_size);
1070 
1071 	_dif_generate(md_buf + ctx->guard_interval, guard, offset_blocks, ctx);
1072 }
1073 
1074 static void
1075 dix_generate_split(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1076 		   uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1077 {
1078 	struct _iov_iter data_iter, md_iter;
1079 	uint32_t offset_blocks;
1080 
1081 	offset_blocks = 0;
1082 	_iov_iter_init(&data_iter, iovs, iovcnt);
1083 	_iov_iter_init(&md_iter, md_iov, 1);
1084 
1085 	while (offset_blocks < num_blocks &&
1086 	       _iov_iter_cont(&data_iter) && _iov_iter_cont(&md_iter)) {
1087 		_dix_generate_split(&data_iter, &md_iter, offset_blocks, ctx);
1088 		offset_blocks++;
1089 	}
1090 }
1091 
1092 int
1093 spdk_dix_generate(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1094 		  uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
1095 {
1096 	if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks) ||
1097 	    !_are_iovs_valid(md_iov, 1, ctx->md_size * num_blocks)) {
1098 		SPDK_ERRLOG("Size of iovec array is not valid.\n");
1099 		return -EINVAL;
1100 	}
1101 
1102 	if (_dif_is_disabled(ctx->dif_type)) {
1103 		return 0;
1104 	}
1105 
1106 	if (_are_iovs_bytes_multiple(iovs, iovcnt, ctx->block_size)) {
1107 		dix_generate(iovs, iovcnt, md_iov, num_blocks, ctx);
1108 	} else {
1109 		dix_generate_split(iovs, iovcnt, md_iov, num_blocks, ctx);
1110 	}
1111 
1112 	return 0;
1113 }
1114 
1115 static int
1116 dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1117 	   uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1118 	   struct spdk_dif_error *err_blk)
1119 {
1120 	struct _iov_iter data_iter, md_iter;
1121 	uint32_t offset_blocks;
1122 	uint16_t guard;
1123 	void *data_buf, *md_buf;
1124 	int rc;
1125 
1126 	offset_blocks = 0;
1127 	_iov_iter_init(&data_iter, iovs, iovcnt);
1128 	_iov_iter_init(&md_iter, md_iov, 1);
1129 
1130 	while (offset_blocks < num_blocks &&
1131 	       _iov_iter_cont(&data_iter) && _iov_iter_cont(&md_iter)) {
1132 
1133 		_iov_iter_get_buf(&data_iter, &data_buf, NULL);
1134 		_iov_iter_get_buf(&md_iter, &md_buf, NULL);
1135 
1136 		guard = 0;
1137 		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
1138 			guard = spdk_crc16_t10dif(0, data_buf, ctx->block_size);
1139 			guard = spdk_crc16_t10dif(guard, md_buf, ctx->guard_interval);
1140 		}
1141 
1142 		rc = _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
1143 		if (rc != 0) {
1144 			return rc;
1145 		}
1146 
1147 		_iov_iter_advance(&data_iter, ctx->block_size);
1148 		_iov_iter_advance(&md_iter, ctx->md_size);
1149 		offset_blocks++;
1150 	}
1151 
1152 	return 0;
1153 }
1154 
1155 static int
1156 _dix_verify_split(struct _iov_iter *data_iter, struct _iov_iter *md_iter,
1157 		  uint32_t offset_blocks, const struct spdk_dif_ctx *ctx,
1158 		  struct spdk_dif_error *err_blk)
1159 {
1160 	uint32_t offset_in_block, data_buf_len;
1161 	uint16_t guard;
1162 	void *data_buf, *md_buf;
1163 
1164 	_iov_iter_get_buf(md_iter, &md_buf, NULL);
1165 
1166 	guard = 0;
1167 	if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
1168 		guard = spdk_crc16_t10dif(0, md_buf, ctx->guard_interval);
1169 	}
1170 
1171 	offset_in_block = 0;
1172 
1173 	while (offset_in_block < ctx->block_size && _iov_iter_cont(data_iter)) {
1174 		_iov_iter_get_buf(data_iter, &data_buf, &data_buf_len);
1175 		data_buf_len = spdk_min(data_buf_len, ctx->block_size - offset_in_block);
1176 
1177 		if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
1178 			guard = spdk_crc16_t10dif(guard, data_buf, data_buf_len);
1179 		}
1180 
1181 		_iov_iter_advance(data_iter, data_buf_len);
1182 		offset_in_block += data_buf_len;
1183 	}
1184 
1185 	_iov_iter_advance(md_iter, ctx->md_size);
1186 
1187 	return _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
1188 }
1189 
1190 static int
1191 dix_verify_split(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1192 		 uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1193 		 struct spdk_dif_error *err_blk)
1194 {
1195 	struct _iov_iter data_iter, md_iter;
1196 	uint32_t offset_blocks;
1197 	int rc;
1198 
1199 	offset_blocks = 0;
1200 	_iov_iter_init(&data_iter, iovs, iovcnt);
1201 	_iov_iter_init(&md_iter, md_iov, 1);
1202 
1203 	while (offset_blocks < num_blocks &&
1204 	       _iov_iter_cont(&data_iter) && _iov_iter_cont(&md_iter)) {
1205 		rc = _dix_verify_split(&data_iter, &md_iter, offset_blocks, ctx, err_blk);
1206 		if (rc != 0) {
1207 			return rc;
1208 		}
1209 		offset_blocks++;
1210 	}
1211 
1212 	return 0;
1213 }
1214 
1215 int
1216 spdk_dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1217 		uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1218 		struct spdk_dif_error *err_blk)
1219 {
1220 	if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks) ||
1221 	    !_are_iovs_valid(md_iov, 1, ctx->md_size * num_blocks)) {
1222 		SPDK_ERRLOG("Size of iovec array is not valid.\n");
1223 		return -EINVAL;
1224 	}
1225 
1226 	if (_dif_is_disabled(ctx->dif_type)) {
1227 		return 0;
1228 	}
1229 
1230 	if (_are_iovs_bytes_multiple(iovs, iovcnt, ctx->block_size)) {
1231 		return dix_verify(iovs, iovcnt, md_iov, num_blocks, ctx, err_blk);
1232 	} else {
1233 		return dix_verify_split(iovs, iovcnt, md_iov, num_blocks, ctx, err_blk);
1234 	}
1235 }
1236 
1237 int
1238 spdk_dix_inject_error(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1239 		      uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
1240 		      uint32_t inject_flags, uint32_t *inject_offset)
1241 {
1242 	int rc;
1243 
1244 	if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks) ||
1245 	    !_are_iovs_valid(md_iov, 1, ctx->md_size * num_blocks)) {
1246 		SPDK_ERRLOG("Size of iovec array is not valid.\n");
1247 		return -EINVAL;
1248 	}
1249 
1250 	if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
1251 		rc = dif_inject_error(md_iov, 1, ctx->md_size, num_blocks,
1252 				      ctx->guard_interval + offsetof(struct spdk_dif, ref_tag),
1253 				      _member_size(struct spdk_dif, ref_tag),
1254 				      inject_offset);
1255 		if (rc != 0) {
1256 			SPDK_ERRLOG("Failed to inject error to Reference Tag.\n");
1257 			return rc;
1258 		}
1259 	}
1260 
1261 	if (inject_flags & SPDK_DIF_APPTAG_ERROR) {
1262 		rc = dif_inject_error(md_iov, 1, ctx->md_size, num_blocks,
1263 				      ctx->guard_interval + offsetof(struct spdk_dif, app_tag),
1264 				      _member_size(struct spdk_dif, app_tag),
1265 				      inject_offset);
1266 		if (rc != 0) {
1267 			SPDK_ERRLOG("Failed to inject error to Application Tag.\n");
1268 			return rc;
1269 		}
1270 	}
1271 
1272 	if (inject_flags & SPDK_DIF_GUARD_ERROR) {
1273 		rc = dif_inject_error(md_iov, 1, ctx->md_size, num_blocks,
1274 				      ctx->guard_interval,
1275 				      _member_size(struct spdk_dif, guard),
1276 				      inject_offset);
1277 		if (rc != 0) {
1278 			SPDK_ERRLOG("Failed to inject error to Guard.\n");
1279 			return rc;
1280 		}
1281 	}
1282 
1283 	if (inject_flags & SPDK_DIF_DATA_ERROR) {
1284 		/* Note: Error injection to data block is expected to be detected
1285 		 * as guard error.
1286 		 */
1287 		rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
1288 				      0,
1289 				      ctx->block_size,
1290 				      inject_offset);
1291 		if (rc != 0) {
1292 			SPDK_ERRLOG("Failed to inject error to Guard.\n");
1293 			return rc;
1294 		}
1295 	}
1296 
1297 	return 0;
1298 }
1299