xref: /spdk/test/unit/lib/util/dif.c/dif_ut.c (revision adc8da4aac6f6586171a6f4da28242d4aa6474b8)
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/stdinc.h"
35 
36 #include "spdk_cunit.h"
37 
38 #include "util/dif.c"
39 
40 #define DATA_PATTERN(offset)	((uint8_t)(0xAB + (offset)))
41 #define GUARD_SEED		0xCD
42 
43 static int
44 ut_data_pattern_generate(struct iovec *iovs, int iovcnt,
45 			 uint32_t block_size, uint32_t md_size, uint32_t num_blocks)
46 {
47 	struct _iov_iter iter;
48 	uint32_t offset_blocks, offset_in_block, buf_len, data_offset, i;
49 	uint8_t *buf;
50 
51 	if (!_are_iovs_valid(iovs, iovcnt, block_size * num_blocks)) {
52 		return -1;
53 	}
54 
55 	offset_blocks = 0;
56 	_iov_iter_init(&iter, iovs, iovcnt);
57 	data_offset = 0;
58 
59 	while (offset_blocks < num_blocks) {
60 		offset_in_block = 0;
61 		while (offset_in_block < block_size) {
62 			_iov_iter_get_buf(&iter, (void *)&buf, &buf_len);
63 			if (offset_in_block < block_size - md_size) {
64 				buf_len = spdk_min(buf_len,
65 						   block_size - md_size - offset_in_block);
66 				for (i = 0; i < buf_len; i++) {
67 					buf[i] = DATA_PATTERN(data_offset + i);
68 				}
69 				data_offset += buf_len;
70 			} else {
71 				buf_len = spdk_min(buf_len, block_size - offset_in_block);
72 				memset(buf, 0, buf_len);
73 			}
74 			_iov_iter_advance(&iter, buf_len);
75 			offset_in_block += buf_len;
76 		}
77 		offset_blocks++;
78 	}
79 
80 	return 0;
81 }
82 
83 static int
84 ut_data_pattern_verify(struct iovec *iovs, int iovcnt,
85 		       uint32_t block_size, uint32_t md_size, uint32_t num_blocks)
86 {
87 	struct _iov_iter iter;
88 	uint32_t offset_blocks, offset_in_block, buf_len, data_offset, i;
89 	uint8_t *buf;
90 
91 	if (!_are_iovs_valid(iovs, iovcnt, block_size * num_blocks)) {
92 		return -1;
93 	}
94 
95 	offset_blocks = 0;
96 	_iov_iter_init(&iter, iovs, iovcnt);
97 	data_offset = 0;
98 
99 	while (offset_blocks < num_blocks) {
100 		offset_in_block = 0;
101 		while (offset_in_block < block_size) {
102 			_iov_iter_get_buf(&iter, (void *)&buf, &buf_len);
103 
104 			if (offset_in_block < block_size - md_size) {
105 				buf_len = spdk_min(buf_len,
106 						   block_size - md_size - offset_in_block);
107 				for (i = 0; i < buf_len; i++) {
108 					if (buf[i] != DATA_PATTERN(data_offset + i)) {
109 						return -1;
110 					}
111 				}
112 				data_offset += buf_len;
113 			} else {
114 				buf_len = spdk_min(buf_len, block_size - offset_in_block);
115 			}
116 			_iov_iter_advance(&iter, buf_len);
117 			offset_in_block += buf_len;
118 		}
119 		offset_blocks++;
120 	}
121 
122 	return 0;
123 }
124 
125 static void
126 _iov_alloc_buf(struct iovec *iov, uint32_t len)
127 {
128 	iov->iov_base = calloc(1, len);
129 	iov->iov_len = len;
130 	SPDK_CU_ASSERT_FATAL(iov->iov_base != NULL);
131 }
132 
133 static void
134 _iov_free_buf(struct iovec *iov)
135 {
136 	free(iov->iov_base);
137 }
138 
139 static void
140 _dif_generate_and_verify(struct iovec *iov,
141 			 uint32_t block_size, uint32_t md_size, bool dif_loc,
142 			 enum spdk_dif_type dif_type, uint32_t dif_flags,
143 			 uint32_t ref_tag, uint32_t e_ref_tag,
144 			 uint16_t app_tag, uint16_t apptag_mask, uint16_t e_app_tag,
145 			 bool expect_pass)
146 {
147 	struct spdk_dif_ctx ctx = {};
148 	uint32_t guard_interval;
149 	uint16_t guard = 0;
150 	int rc;
151 
152 	rc = ut_data_pattern_generate(iov, 1, block_size, md_size, 1);
153 	CU_ASSERT(rc == 0);
154 
155 	guard_interval = _get_guard_interval(block_size, md_size, dif_loc, true);
156 
157 	ctx.dif_type = dif_type;
158 	ctx.dif_flags = dif_flags;
159 	ctx.init_ref_tag = ref_tag;
160 	ctx.app_tag = app_tag;
161 
162 	if (dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
163 		guard = spdk_crc16_t10dif(0, iov->iov_base, guard_interval);
164 	}
165 
166 	_dif_generate(iov->iov_base + guard_interval, guard, 0, &ctx);
167 
168 	ctx.init_ref_tag = e_ref_tag;
169 	ctx.apptag_mask = apptag_mask;
170 	ctx.app_tag = e_app_tag;
171 
172 	rc = _dif_verify(iov->iov_base + guard_interval, guard, 0, &ctx, NULL);
173 	CU_ASSERT((expect_pass && rc == 0) || (!expect_pass && rc != 0));
174 
175 	rc = ut_data_pattern_verify(iov, 1, block_size, md_size, 1);
176 	CU_ASSERT(rc == 0);
177 }
178 
179 static void
180 dif_generate_and_verify_test(void)
181 {
182 	struct iovec iov;
183 	uint32_t dif_flags;
184 
185 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
186 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
187 
188 	_iov_alloc_buf(&iov, 4096 + 128);
189 
190 	/* Positive cases */
191 
192 	/* The case that DIF is contained in the first 8 bytes of metadata. */
193 	_dif_generate_and_verify(&iov,
194 				 4096 + 128, 128, true,
195 				 SPDK_DIF_TYPE1, dif_flags,
196 				 22, 22,
197 				 0x22, 0xFFFF, 0x22,
198 				 true);
199 
200 	/* The case that DIF is contained in the last 8 bytes of metadata. */
201 	_dif_generate_and_verify(&iov,
202 				 4096 + 128, 128, false,
203 				 SPDK_DIF_TYPE1, dif_flags,
204 				 22, 22,
205 				 0x22, 0xFFFF, 0x22,
206 				 true);
207 
208 	/* Negative cases */
209 
210 	/* Reference tag doesn't match. */
211 	_dif_generate_and_verify(&iov,
212 				 4096 + 128, 128, false,
213 				 SPDK_DIF_TYPE1, dif_flags,
214 				 22, 23,
215 				 0x22, 0xFFFF, 0x22,
216 				 false);
217 
218 	/* Application tag doesn't match. */
219 	_dif_generate_and_verify(&iov,
220 				 4096 + 128, 128, false,
221 				 SPDK_DIF_TYPE1, dif_flags,
222 				 22, 22,
223 				 0x22, 0xFFFF, 0x23,
224 				 false);
225 
226 	_iov_free_buf(&iov);
227 }
228 
229 static void
230 dif_disable_check_test(void)
231 {
232 	struct iovec iov;
233 	uint32_t dif_flags;
234 
235 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
236 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
237 
238 	_iov_alloc_buf(&iov, 4096 + 128);
239 
240 	/* The case that DIF check is disabled when the Application Tag is 0xFFFF for
241 	 * Type 1. DIF check is disabled and pass is expected.
242 	 */
243 	_dif_generate_and_verify(&iov,
244 				 4096 + 128, 128, false,
245 				 SPDK_DIF_TYPE1, dif_flags,
246 				 22, 22,
247 				 0xFFFF, 0xFFFF, 0x22,
248 				 true);
249 
250 	/* The case that DIF check is not disabled when the Application Tag is 0xFFFF but
251 	 * the Reference Tag is not 0xFFFFFFFF for Type 3. DIF check is not disabled and
252 	 * fail is expected.
253 	 */
254 	_dif_generate_and_verify(&iov,
255 				 4096 + 128, 128, false,
256 				 SPDK_DIF_TYPE3, dif_flags,
257 				 22, 22,
258 				 0xFFFF, 0xFFFF, 0x22,
259 				 false);
260 
261 	/* The case that DIF check is disabled when the Application Tag is 0xFFFF and
262 	 * the Reference Tag is 0xFFFFFFFF for Type 3. DIF check is disabled and
263 	 * pass is expected.
264 	 */
265 	_dif_generate_and_verify(&iov,
266 				 4096 + 128, 128, false,
267 				 SPDK_DIF_TYPE3, dif_flags,
268 				 0xFFFFFFFF, 22,
269 				 0xFFFF, 0xFFFF, 0x22,
270 				 true);
271 
272 	_iov_free_buf(&iov);
273 }
274 
275 static void
276 dif_sec_512_md_0_error_test(void)
277 {
278 	struct spdk_dif_ctx ctx = {};
279 	int rc;
280 
281 	/* Metadata size is 0. */
282 	rc = spdk_dif_ctx_init(&ctx, 512, 0, true, false, SPDK_DIF_TYPE1, 0, 0, 0, 0, 0);
283 	CU_ASSERT(rc != 0);
284 }
285 
286 static void
287 dif_guard_seed_test(void)
288 {
289 	struct iovec iov;
290 	struct spdk_dif_ctx ctx = {};
291 	struct spdk_dif_error err_blk = {};
292 	struct spdk_dif *dif;
293 	uint16_t guard;
294 	int rc;
295 
296 	_iov_alloc_buf(&iov, 512 + 8);
297 
298 	memset(iov.iov_base, 0, 512 + 8);
299 
300 	dif = (struct spdk_dif *)(iov.iov_base + 512);
301 
302 	rc = spdk_dif_ctx_init(&ctx, 512 + 8, 8, true, false, SPDK_DIF_TYPE1,
303 			       SPDK_DIF_FLAGS_GUARD_CHECK, 0, 0, 0, 0);
304 	CU_ASSERT(rc == 0);
305 
306 	rc = spdk_dif_generate(&iov, 1, 1, &ctx);
307 	CU_ASSERT(rc == 0);
308 
309 	/* Guard should be zero if the block is all zero and seed is not added. */
310 	guard = from_be16(&dif->guard);
311 	CU_ASSERT(guard == 0);
312 
313 	rc = spdk_dif_verify(&iov, 1, 1, &ctx, &err_blk);
314 	CU_ASSERT(rc == 0);
315 
316 	rc = spdk_dif_ctx_init(&ctx, 512 + 8, 8, true, false, SPDK_DIF_TYPE1,
317 			       SPDK_DIF_FLAGS_GUARD_CHECK, 0, 0, 0, GUARD_SEED);
318 	CU_ASSERT(rc == 0);
319 
320 	rc = spdk_dif_generate(&iov, 1, 1, &ctx);
321 	CU_ASSERT(rc == 0);
322 
323 	/* Guard should not be zero if the block is all zero but seed is added. */
324 	guard = from_be16(&dif->guard);
325 	CU_ASSERT(guard != 0);
326 
327 	rc = spdk_dif_verify(&iov, 1, 1, &ctx, &err_blk);
328 	CU_ASSERT(rc == 0);
329 
330 	_iov_free_buf(&iov);
331 }
332 
333 static void
334 dif_generate_and_verify(struct iovec *iovs, int iovcnt,
335 			uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
336 			bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
337 			uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag)
338 {
339 	struct spdk_dif_ctx ctx = {};
340 	int rc;
341 
342 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, md_size, num_blocks);
343 	CU_ASSERT(rc == 0);
344 
345 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc, dif_type, dif_flags,
346 			       init_ref_tag, apptag_mask, app_tag, GUARD_SEED);
347 	CU_ASSERT(rc == 0);
348 
349 	rc = spdk_dif_generate(iovs, iovcnt, num_blocks, &ctx);
350 	CU_ASSERT(rc == 0);
351 
352 	rc = spdk_dif_verify(iovs, iovcnt, num_blocks, &ctx, NULL);
353 	CU_ASSERT(rc == 0);
354 
355 	rc = ut_data_pattern_verify(iovs, iovcnt, block_size, md_size, num_blocks);
356 	CU_ASSERT(rc == 0);
357 }
358 
359 static void
360 dif_disable_sec_512_md_8_single_iov_test(void)
361 {
362 	struct iovec iov;
363 
364 	_iov_alloc_buf(&iov, 512 + 8);
365 
366 	dif_generate_and_verify(&iov, 1, 512 + 8, 8, 1, false, SPDK_DIF_DISABLE, 0, 0, 0, 0);
367 
368 	_iov_free_buf(&iov);
369 }
370 
371 static void
372 dif_sec_512_md_8_prchk_0_single_iov_test(void)
373 {
374 	struct iovec iov;
375 
376 	_iov_alloc_buf(&iov, 512 + 8);
377 
378 	dif_generate_and_verify(&iov, 1, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1, 0, 0, 0, 0);
379 
380 	_iov_free_buf(&iov);
381 }
382 
383 static void
384 dif_sec_512_md_8_prchk_0_1_2_4_multi_iovs_test(void)
385 {
386 	struct iovec iovs[4];
387 	int i, num_blocks;
388 
389 	num_blocks = 0;
390 
391 	for (i = 0; i < 4; i++) {
392 		_iov_alloc_buf(&iovs[i], (512 + 8) * (i + 1));
393 		num_blocks += i + 1;
394 	}
395 
396 	dif_generate_and_verify(iovs, 4, 512 + 8, 8, num_blocks, false, SPDK_DIF_TYPE1,
397 				0, 22, 0xFFFF, 0x22);
398 
399 	dif_generate_and_verify(iovs, 4, 512 + 8, 8, num_blocks, false, SPDK_DIF_TYPE1,
400 				SPDK_DIF_FLAGS_GUARD_CHECK, 22, 0xFFFF, 0x22);
401 
402 	dif_generate_and_verify(iovs, 4, 512 + 8, 8, num_blocks, false, SPDK_DIF_TYPE1,
403 				SPDK_DIF_FLAGS_APPTAG_CHECK, 22, 0xFFFF, 0x22);
404 
405 	dif_generate_and_verify(iovs, 4, 512 + 8, 8, num_blocks, false, SPDK_DIF_TYPE1,
406 				SPDK_DIF_FLAGS_REFTAG_CHECK, 22, 0xFFFF, 0x22);
407 
408 	for (i = 0; i < 4; i++) {
409 		_iov_free_buf(&iovs[i]);
410 	}
411 }
412 
413 static void
414 dif_sec_4096_md_128_prchk_7_multi_iovs_test(void)
415 {
416 	struct iovec iovs[4];
417 	int i, num_blocks;
418 	uint32_t dif_flags;
419 
420 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
421 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
422 
423 	num_blocks = 0;
424 
425 	for (i = 0; i < 4; i++) {
426 		_iov_alloc_buf(&iovs[i], (4096 + 128) * (i + 1));
427 		num_blocks += i + 1;
428 	}
429 
430 	dif_generate_and_verify(iovs, 4, 4096 + 128, 128, num_blocks, false, SPDK_DIF_TYPE1,
431 				dif_flags, 22, 0xFFFF, 0x22);
432 
433 	dif_generate_and_verify(iovs, 4, 4096 + 128, 128, num_blocks, true, SPDK_DIF_TYPE1,
434 				dif_flags, 22, 0xFFFF, 0x22);
435 
436 	for (i = 0; i < 4; i++) {
437 		_iov_free_buf(&iovs[i]);
438 	}
439 }
440 
441 static void
442 dif_sec_512_md_8_prchk_7_multi_iovs_split_data_and_md_test(void)
443 {
444 	struct iovec iovs[2];
445 	uint32_t dif_flags;
446 
447 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
448 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
449 
450 	_iov_alloc_buf(&iovs[0], 512);
451 	_iov_alloc_buf(&iovs[1], 8);
452 
453 	dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1,
454 				dif_flags, 22, 0xFFFF, 0x22);
455 
456 	_iov_free_buf(&iovs[0]);
457 	_iov_free_buf(&iovs[1]);
458 }
459 
460 static void
461 dif_sec_512_md_8_prchk_7_multi_iovs_split_data_test(void)
462 {
463 	struct iovec iovs[2];
464 	uint32_t dif_flags;
465 
466 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
467 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
468 
469 	_iov_alloc_buf(&iovs[0], 256);
470 	_iov_alloc_buf(&iovs[1], 264);
471 
472 	dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1,
473 				dif_flags, 22, 0xFFFF, 0x22);
474 
475 	_iov_free_buf(&iovs[0]);
476 	_iov_free_buf(&iovs[1]);
477 }
478 
479 static void
480 dif_sec_512_md_8_prchk_7_multi_iovs_split_guard_test(void)
481 {
482 	struct iovec iovs[2];
483 	uint32_t dif_flags;
484 
485 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
486 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
487 
488 	_iov_alloc_buf(&iovs[0], 513);
489 	_iov_alloc_buf(&iovs[1], 7);
490 
491 	dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1,
492 				dif_flags, 22, 0xFFFF, 0x22);
493 
494 	_iov_free_buf(&iovs[0]);
495 	_iov_free_buf(&iovs[1]);
496 }
497 
498 static void
499 dif_sec_512_md_8_prchk_7_multi_iovs_split_apptag_test(void)
500 {
501 	struct iovec iovs[2];
502 	uint32_t dif_flags;
503 
504 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
505 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
506 
507 	_iov_alloc_buf(&iovs[0], 515);
508 	_iov_alloc_buf(&iovs[1], 5);
509 
510 	dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1,
511 				dif_flags, 22, 0xFFFF, 0x22);
512 
513 	_iov_free_buf(&iovs[0]);
514 	_iov_free_buf(&iovs[1]);
515 }
516 
517 static void
518 dif_sec_512_md_8_prchk_7_multi_iovs_split_reftag_test(void)
519 {
520 	struct iovec iovs[2];
521 	uint32_t dif_flags;
522 
523 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
524 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
525 
526 	_iov_alloc_buf(&iovs[0], 518);
527 	_iov_alloc_buf(&iovs[1], 2);
528 
529 	dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1,
530 				dif_flags, 22, 0xFFFF, 0x22);
531 
532 	_iov_free_buf(&iovs[0]);
533 	_iov_free_buf(&iovs[1]);
534 }
535 
536 static void
537 dif_sec_512_md_8_prchk_7_multi_iovs_complex_splits_test(void)
538 {
539 	struct iovec iovs[9];
540 	uint32_t dif_flags;
541 	int i;
542 
543 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
544 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
545 
546 	/* data[0][255:0] */
547 	_iov_alloc_buf(&iovs[0], 256);
548 
549 	/* data[0][511:256], guard[0][0] */
550 	_iov_alloc_buf(&iovs[1], 256 + 1);
551 
552 	/* guard[0][1], apptag[0][0] */
553 	_iov_alloc_buf(&iovs[2], 1 + 1);
554 
555 	/* apptag[0][1], reftag[0][0] */
556 	_iov_alloc_buf(&iovs[3], 1 + 1);
557 
558 	/* reftag[0][3:1], data[1][255:0] */
559 	_iov_alloc_buf(&iovs[4], 3 + 256);
560 
561 	/* data[1][511:256], guard[1][0] */
562 	_iov_alloc_buf(&iovs[5], 256 + 1);
563 
564 	/* guard[1][1], apptag[1][0] */
565 	_iov_alloc_buf(&iovs[6], 1 + 1);
566 
567 	/* apptag[1][1], reftag[1][0] */
568 	_iov_alloc_buf(&iovs[7], 1 + 1);
569 
570 	/* reftag[1][3:1] */
571 	_iov_alloc_buf(&iovs[8], 3);
572 
573 	dif_generate_and_verify(iovs, 9, 512 + 8, 8, 2, false, SPDK_DIF_TYPE1, dif_flags,
574 				22, 0xFFFF, 0x22);
575 
576 	for (i = 0; i < 9; i++) {
577 		_iov_free_buf(&iovs[i]);
578 	}
579 }
580 
581 static void
582 dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_test(void)
583 {
584 	struct iovec iovs[11];
585 	uint32_t dif_flags;
586 	int i;
587 
588 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
589 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
590 
591 	/* data[0][1000:0] */
592 	_iov_alloc_buf(&iovs[0], 1000);
593 
594 	/* data[0][3095:1000], guard[0][0] */
595 	_iov_alloc_buf(&iovs[1], 3096 + 1);
596 
597 	/* guard[0][1], apptag[0][0] */
598 	_iov_alloc_buf(&iovs[2], 1 + 1);
599 
600 	/* apptag[0][1], reftag[0][0] */
601 	_iov_alloc_buf(&iovs[3], 1 + 1);
602 
603 	/* reftag[0][3:1], ignore[0][59:0] */
604 	_iov_alloc_buf(&iovs[4], 3 + 60);
605 
606 	/* ignore[119:60], data[1][3050:0] */
607 	_iov_alloc_buf(&iovs[5], 60 + 3051);
608 
609 	/* data[1][4095:3050], guard[1][0] */
610 	_iov_alloc_buf(&iovs[6], 1045 + 1);
611 
612 	/* guard[1][1], apptag[1][0] */
613 	_iov_alloc_buf(&iovs[7], 1 + 1);
614 
615 	/* apptag[1][1], reftag[1][0] */
616 	_iov_alloc_buf(&iovs[8], 1 + 1);
617 
618 	/* reftag[1][3:1], ignore[1][9:0] */
619 	_iov_alloc_buf(&iovs[9], 3 + 10);
620 
621 	/* ignore[1][127:9] */
622 	_iov_alloc_buf(&iovs[10], 118);
623 
624 	dif_generate_and_verify(iovs, 11, 4096 + 128, 128, 2, false, SPDK_DIF_TYPE1, dif_flags,
625 				22, 0xFFFF, 0x22);
626 	dif_generate_and_verify(iovs, 11, 4096 + 128, 128, 2, true, SPDK_DIF_TYPE1, dif_flags,
627 				22, 0xFFFF, 0x22);
628 
629 	for (i = 0; i < 11; i++) {
630 		_iov_free_buf(&iovs[i]);
631 	}
632 }
633 
634 static void
635 _dif_inject_error_and_verify(struct iovec *iovs, int iovcnt,
636 			     uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
637 			     uint32_t inject_flags, bool dif_loc)
638 {
639 	struct spdk_dif_ctx ctx = {};
640 	struct spdk_dif_error err_blk = {};
641 	uint32_t inject_offset = 0, dif_flags;
642 	int rc;
643 
644 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
645 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
646 
647 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, md_size, num_blocks);
648 	CU_ASSERT(rc == 0);
649 
650 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc,
651 			       SPDK_DIF_TYPE1, dif_flags, 88, 0xFFFF, 0x88, GUARD_SEED);
652 	CU_ASSERT(rc == 0);
653 
654 	rc = spdk_dif_generate(iovs, iovcnt, num_blocks, &ctx);
655 	CU_ASSERT(rc == 0);
656 
657 	rc = spdk_dif_inject_error(iovs, iovcnt, num_blocks, &ctx, inject_flags, &inject_offset);
658 	CU_ASSERT(rc == 0);
659 
660 	rc = spdk_dif_verify(iovs, iovcnt, num_blocks, &ctx, &err_blk);
661 	CU_ASSERT(rc != 0);
662 	if (inject_flags == SPDK_DIF_DATA_ERROR) {
663 		CU_ASSERT(SPDK_DIF_GUARD_ERROR == err_blk.err_type);
664 	} else {
665 		CU_ASSERT(inject_flags == err_blk.err_type);
666 	}
667 	CU_ASSERT(inject_offset == err_blk.err_offset);
668 
669 	rc = ut_data_pattern_verify(iovs, iovcnt, block_size, md_size, num_blocks);
670 	CU_ASSERT((rc == 0 && (inject_flags != SPDK_DIF_DATA_ERROR)) ||
671 		  (rc != 0 && (inject_flags == SPDK_DIF_DATA_ERROR)));
672 }
673 
674 static void
675 dif_inject_error_and_verify(struct iovec *iovs, int iovcnt,
676 			    uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
677 			    uint32_t inject_flags)
678 {
679 	/* The case that DIF is contained in the first 8 bytes of metadata. */
680 	_dif_inject_error_and_verify(iovs, iovcnt, block_size, md_size, num_blocks,
681 				     inject_flags, true);
682 
683 	/* The case that DIF is contained in the last 8 bytes of metadata. */
684 	_dif_inject_error_and_verify(iovs, iovcnt, block_size, md_size, num_blocks,
685 				     inject_flags, false);
686 }
687 
688 static void
689 dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test(void)
690 {
691 	struct iovec iovs[4];
692 	int i, num_blocks;
693 
694 	num_blocks = 0;
695 
696 	for (i = 0; i < 4; i++) {
697 		_iov_alloc_buf(&iovs[i], (4096 + 128) * (i + 1));
698 		num_blocks += i + 1;
699 	}
700 
701 	dif_inject_error_and_verify(iovs, 4, 4096 + 128, 128, num_blocks, SPDK_DIF_GUARD_ERROR);
702 	dif_inject_error_and_verify(iovs, 4, 4096 + 128, 128, num_blocks, SPDK_DIF_APPTAG_ERROR);
703 	dif_inject_error_and_verify(iovs, 4, 4096 + 128, 128, num_blocks, SPDK_DIF_REFTAG_ERROR);
704 	dif_inject_error_and_verify(iovs, 4, 4096 + 128, 128, num_blocks, SPDK_DIF_DATA_ERROR);
705 
706 	for (i = 0; i < 4; i++) {
707 		_iov_free_buf(&iovs[i]);
708 	}
709 }
710 
711 static void
712 dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_data_and_md_test(void)
713 {
714 	struct iovec iovs[2];
715 
716 	_iov_alloc_buf(&iovs[0], 4096);
717 	_iov_alloc_buf(&iovs[1], 128);
718 
719 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_GUARD_ERROR);
720 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_APPTAG_ERROR);
721 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_REFTAG_ERROR);
722 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_DATA_ERROR);
723 
724 	_iov_free_buf(&iovs[0]);
725 	_iov_free_buf(&iovs[1]);
726 }
727 
728 static void
729 dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_data_test(void)
730 {
731 	struct iovec iovs[2];
732 
733 	_iov_alloc_buf(&iovs[0], 2048);
734 	_iov_alloc_buf(&iovs[1], 2048 + 128);
735 
736 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_GUARD_ERROR);
737 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_APPTAG_ERROR);
738 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_REFTAG_ERROR);
739 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_DATA_ERROR);
740 
741 	_iov_free_buf(&iovs[0]);
742 	_iov_free_buf(&iovs[1]);
743 }
744 
745 static void
746 dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_guard_test(void)
747 {
748 	struct iovec iovs[2];
749 
750 	_iov_alloc_buf(&iovs[0], 4096 + 1);
751 	_iov_alloc_buf(&iovs[1], 127);
752 
753 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_GUARD_ERROR);
754 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_APPTAG_ERROR);
755 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_REFTAG_ERROR);
756 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_DATA_ERROR);
757 
758 	_iov_free_buf(&iovs[0]);
759 	_iov_free_buf(&iovs[1]);
760 }
761 
762 static void
763 dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_apptag_test(void)
764 {
765 	struct iovec iovs[2];
766 
767 	_iov_alloc_buf(&iovs[0], 4096 + 3);
768 	_iov_alloc_buf(&iovs[1], 125);
769 
770 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_GUARD_ERROR);
771 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_APPTAG_ERROR);
772 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_REFTAG_ERROR);
773 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_DATA_ERROR);
774 
775 	_iov_free_buf(&iovs[0]);
776 	_iov_free_buf(&iovs[1]);
777 }
778 
779 static void
780 dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_reftag_test(void)
781 {
782 	struct iovec iovs[2];
783 
784 	_iov_alloc_buf(&iovs[0], 4096 + 6);
785 	_iov_alloc_buf(&iovs[1], 122);
786 
787 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_GUARD_ERROR);
788 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_APPTAG_ERROR);
789 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_REFTAG_ERROR);
790 	dif_inject_error_and_verify(iovs, 2, 4096 + 128, 128, 1, SPDK_DIF_DATA_ERROR);
791 
792 	_iov_free_buf(&iovs[0]);
793 	_iov_free_buf(&iovs[1]);
794 }
795 
796 static void
797 dif_copy_gen_and_verify(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov,
798 			uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
799 			bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
800 			uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag)
801 {
802 	struct spdk_dif_ctx ctx = {};
803 	int rc;
804 
805 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size - md_size, 0, num_blocks);
806 	CU_ASSERT(rc == 0);
807 
808 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc, dif_type, dif_flags,
809 			       init_ref_tag, apptag_mask, app_tag, GUARD_SEED);
810 	CU_ASSERT(rc == 0);
811 
812 	rc = spdk_dif_generate_copy(iovs, iovcnt, bounce_iov, num_blocks, &ctx);
813 	CU_ASSERT(rc == 0);
814 
815 	rc = spdk_dif_verify_copy(iovs, iovcnt, bounce_iov, num_blocks, &ctx, NULL);
816 	CU_ASSERT(rc == 0);
817 
818 	rc = ut_data_pattern_verify(iovs, iovcnt, block_size - md_size, 0, num_blocks);
819 	CU_ASSERT(rc == 0);
820 }
821 
822 static void
823 dif_copy_sec_512_md_8_prchk_0_single_iov(void)
824 {
825 	struct iovec iov, bounce_iov;
826 
827 	_iov_alloc_buf(&iov, 512 * 4);
828 	_iov_alloc_buf(&bounce_iov, (512 + 8) * 4);
829 
830 	dif_copy_gen_and_verify(&iov, 1, &bounce_iov, 512 + 8, 8, 4,
831 				false, SPDK_DIF_TYPE1, 0, 0, 0, 0);
832 	dif_copy_gen_and_verify(&iov, 1, &bounce_iov, 512 + 8, 8, 4,
833 				true, SPDK_DIF_TYPE1, 0, 0, 0, 0);
834 
835 	_iov_free_buf(&iov);
836 	_iov_free_buf(&bounce_iov);
837 }
838 
839 static void
840 dif_copy_sec_512_md_8_prchk_0_1_2_4_multi_iovs(void)
841 {
842 	struct iovec iovs[4], bounce_iov;
843 	int i, num_blocks;
844 
845 	num_blocks = 0;
846 
847 	for (i = 0; i < 4; i++) {
848 		_iov_alloc_buf(&iovs[i], 512 * (i + 1));
849 		num_blocks += i + 1;
850 	}
851 
852 	_iov_alloc_buf(&bounce_iov, (512 + 8) * num_blocks);
853 
854 	dif_copy_gen_and_verify(iovs, 4, &bounce_iov, 512 + 8, 8, num_blocks,
855 				false, SPDK_DIF_TYPE1, 0, 22, 0xFFFF, 0x22);
856 
857 	dif_copy_gen_and_verify(iovs, 4, &bounce_iov, 512 + 8, 8, num_blocks,
858 				false, SPDK_DIF_TYPE1, SPDK_DIF_FLAGS_GUARD_CHECK, 22, 0xFFFF, 0x22);
859 
860 	dif_copy_gen_and_verify(iovs, 4, &bounce_iov, 512 + 8, 8, num_blocks,
861 				false, SPDK_DIF_TYPE1, SPDK_DIF_FLAGS_APPTAG_CHECK, 22, 0xFFFF, 0x22);
862 
863 	dif_copy_gen_and_verify(iovs, 4, &bounce_iov, 512 + 8, 8, num_blocks,
864 				false, SPDK_DIF_TYPE1, SPDK_DIF_FLAGS_REFTAG_CHECK, 22, 0xFFFF, 0x22);
865 
866 	for (i = 0; i < 4; i++) {
867 		_iov_free_buf(&iovs[i]);
868 	}
869 	_iov_free_buf(&bounce_iov);
870 }
871 
872 static void
873 dif_copy_sec_4096_md_128_prchk_7_multi_iovs(void)
874 {
875 	struct iovec iovs[4], bounce_iov;
876 	uint32_t dif_flags;
877 	int i, num_blocks;
878 
879 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
880 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
881 
882 	num_blocks = 0;
883 
884 	for (i = 0; i < 4; i++) {
885 		_iov_alloc_buf(&iovs[i], 4096 * (i + 1));
886 		num_blocks += i + 1;
887 	}
888 
889 	_iov_alloc_buf(&bounce_iov, (4096 + 128) * num_blocks);
890 
891 	dif_copy_gen_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128, num_blocks,
892 				false, SPDK_DIF_TYPE1, dif_flags, 22, 0xFFFF, 0x22);
893 	dif_copy_gen_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128, num_blocks,
894 				true, SPDK_DIF_TYPE1, dif_flags, 22, 0xFFFF, 0x22);
895 
896 	for (i = 0; i < 4; i++) {
897 		_iov_free_buf(&iovs[i]);
898 	}
899 	_iov_free_buf(&bounce_iov);
900 }
901 
902 static void
903 dif_copy_sec_512_md_8_prchk_7_multi_iovs_split_data(void)
904 {
905 	struct iovec iovs[2], bounce_iov;
906 	uint32_t dif_flags;
907 
908 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
909 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
910 
911 	_iov_alloc_buf(&iovs[0], 256);
912 	_iov_alloc_buf(&iovs[1], 256);
913 
914 	_iov_alloc_buf(&bounce_iov, 512 + 8);
915 
916 	dif_copy_gen_and_verify(iovs, 2, &bounce_iov, 512 + 8, 8, 1,
917 				false, SPDK_DIF_TYPE1, dif_flags, 22, 0xFFFF, 0x22);
918 
919 	_iov_free_buf(&iovs[0]);
920 	_iov_free_buf(&iovs[1]);
921 	_iov_free_buf(&bounce_iov);
922 }
923 
924 static void
925 dif_copy_sec_512_md_8_prchk_7_multi_iovs_complex_splits(void)
926 {
927 	struct iovec iovs[6], bounce_iov;
928 	uint32_t dif_flags;
929 	int i;
930 
931 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
932 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
933 
934 	/* data[0][255:0] */
935 	_iov_alloc_buf(&iovs[0], 256);
936 
937 	/* data[0][511:256], data[1][255:0] */
938 	_iov_alloc_buf(&iovs[1], 256 + 256);
939 
940 	/* data[1][382:256] */
941 	_iov_alloc_buf(&iovs[2], 128);
942 
943 	/* data[1][383] */
944 	_iov_alloc_buf(&iovs[3], 1);
945 
946 	/* data[1][510:384] */
947 	_iov_alloc_buf(&iovs[4], 126);
948 
949 	/* data[1][511], data[2][511:0], data[3][511:0] */
950 	_iov_alloc_buf(&iovs[5], 1 + 512 * 2);
951 
952 	_iov_alloc_buf(&bounce_iov, (512 + 8) * 4);
953 
954 	dif_copy_gen_and_verify(iovs, 6, &bounce_iov, 512 + 8, 8, 4,
955 				true, SPDK_DIF_TYPE1, dif_flags, 22, 0xFFFF, 0x22);
956 
957 	for (i = 0; i < 6; i++) {
958 		_iov_free_buf(&iovs[i]);
959 	}
960 	_iov_free_buf(&bounce_iov);
961 }
962 
963 static void
964 _dif_copy_inject_error_and_verify(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov,
965 				  uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
966 				  uint32_t inject_flags, bool dif_loc)
967 {
968 	struct spdk_dif_ctx ctx = {};
969 	struct spdk_dif_error err_blk = {};
970 	uint32_t inject_offset = 0, dif_flags;
971 	int rc;
972 
973 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
974 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
975 
976 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size - md_size, 0, num_blocks);
977 	CU_ASSERT(rc == 0);
978 
979 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc, SPDK_DIF_TYPE1, dif_flags,
980 			       88, 0xFFFF, 0x88, GUARD_SEED);
981 	SPDK_CU_ASSERT_FATAL(rc == 0);
982 
983 	rc = spdk_dif_generate_copy(iovs, iovcnt, bounce_iov, num_blocks, &ctx);
984 	CU_ASSERT(rc == 0);
985 
986 	rc = spdk_dif_inject_error(bounce_iov, 1, num_blocks, &ctx, inject_flags, &inject_offset);
987 	CU_ASSERT(rc == 0);
988 
989 	rc = spdk_dif_verify_copy(iovs, iovcnt, bounce_iov, num_blocks, &ctx, &err_blk);
990 	CU_ASSERT(rc != 0);
991 	if (inject_flags == SPDK_DIF_DATA_ERROR) {
992 		CU_ASSERT(SPDK_DIF_GUARD_ERROR == err_blk.err_type);
993 	} else {
994 		CU_ASSERT(inject_flags == err_blk.err_type);
995 	}
996 	CU_ASSERT(inject_offset == err_blk.err_offset);
997 }
998 
999 static void
1000 dif_copy_inject_error_and_verify(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov,
1001 				 uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
1002 				 uint32_t inject_flags)
1003 {
1004 	/* The case that DIF is contained in the first 8 bytes of metadata. */
1005 	_dif_copy_inject_error_and_verify(iovs, iovcnt, bounce_iov,
1006 					  block_size, md_size, num_blocks,
1007 					  inject_flags, true);
1008 
1009 	/* The case that DIF is contained in the last 8 bytes of metadata. */
1010 	_dif_copy_inject_error_and_verify(iovs, iovcnt, bounce_iov,
1011 					  block_size, md_size, num_blocks,
1012 					  inject_flags, false);
1013 }
1014 
1015 static void
1016 dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test(void)
1017 {
1018 	struct iovec iovs[4], bounce_iov;
1019 	int i, num_blocks;
1020 
1021 	num_blocks = 0;
1022 
1023 	for (i = 0; i < 4; i++) {
1024 		_iov_alloc_buf(&iovs[i], 4096 * (i + 1));
1025 		num_blocks += i + 1;
1026 	}
1027 
1028 	_iov_alloc_buf(&bounce_iov, (4096 + 128) * num_blocks);
1029 
1030 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1031 					 num_blocks, SPDK_DIF_GUARD_ERROR);
1032 
1033 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1034 					 num_blocks, SPDK_DIF_APPTAG_ERROR);
1035 
1036 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1037 					 num_blocks, SPDK_DIF_REFTAG_ERROR);
1038 
1039 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1040 					 num_blocks, SPDK_DIF_DATA_ERROR);
1041 
1042 	for (i = 0; i < 4; i++) {
1043 		_iov_free_buf(&iovs[i]);
1044 	}
1045 	_iov_free_buf(&bounce_iov);
1046 }
1047 
1048 static void
1049 dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test(void)
1050 {
1051 	struct iovec iovs[4], bounce_iov;
1052 	int i;
1053 
1054 	_iov_alloc_buf(&iovs[0], 2048);
1055 	_iov_alloc_buf(&iovs[1], 2048);
1056 	_iov_alloc_buf(&iovs[2], 1);
1057 	_iov_alloc_buf(&iovs[3], 4095);
1058 
1059 	_iov_alloc_buf(&bounce_iov, (4096 + 128) * 2);
1060 
1061 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1062 					 2, SPDK_DIF_GUARD_ERROR);
1063 
1064 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1065 					 2, SPDK_DIF_APPTAG_ERROR);
1066 
1067 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1068 					 2, SPDK_DIF_REFTAG_ERROR);
1069 
1070 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1071 					 2, SPDK_DIF_DATA_ERROR);
1072 
1073 	for (i = 0; i < 4; i++) {
1074 		_iov_free_buf(&iovs[i]);
1075 	}
1076 	_iov_free_buf(&bounce_iov);
1077 }
1078 
1079 static void
1080 dix_sec_512_md_0_error(void)
1081 {
1082 	struct spdk_dif_ctx ctx;
1083 	int rc;
1084 
1085 	rc = spdk_dif_ctx_init(&ctx, 512, 0, false, false, SPDK_DIF_TYPE1, 0, 0, 0, 0, 0);
1086 	CU_ASSERT(rc != 0);
1087 }
1088 
1089 static void
1090 dix_generate_and_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1091 			uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
1092 			bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
1093 			uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag)
1094 {
1095 	struct spdk_dif_ctx ctx;
1096 	int rc;
1097 
1098 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, 0, num_blocks);
1099 	CU_ASSERT(rc == 0);
1100 
1101 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, false, dif_loc, dif_type, dif_flags,
1102 			       init_ref_tag, apptag_mask, app_tag, GUARD_SEED);
1103 	CU_ASSERT(rc == 0);
1104 
1105 	rc = spdk_dix_generate(iovs, iovcnt, md_iov, num_blocks, &ctx);
1106 	CU_ASSERT(rc == 0);
1107 
1108 	rc = spdk_dix_verify(iovs, iovcnt, md_iov, num_blocks, &ctx, NULL);
1109 	CU_ASSERT(rc == 0);
1110 
1111 	rc = ut_data_pattern_verify(iovs, iovcnt, block_size, 0, num_blocks);
1112 	CU_ASSERT(rc == 0);
1113 }
1114 
1115 static void
1116 dix_sec_512_md_8_prchk_0_single_iov(void)
1117 {
1118 	struct iovec iov, md_iov;
1119 
1120 	_iov_alloc_buf(&iov, 512 * 4);
1121 	_iov_alloc_buf(&md_iov, 8 * 4);
1122 
1123 	dix_generate_and_verify(&iov, 1, &md_iov, 512, 8, 4, false, SPDK_DIF_TYPE1, 0, 0, 0, 0);
1124 	dix_generate_and_verify(&iov, 1, &md_iov, 512, 8, 4, true, SPDK_DIF_TYPE1, 0, 0, 0, 0);
1125 
1126 	_iov_free_buf(&iov);
1127 	_iov_free_buf(&md_iov);
1128 }
1129 
1130 static void
1131 dix_sec_512_md_8_prchk_0_1_2_4_multi_iovs(void)
1132 {
1133 	struct iovec iovs[4], md_iov;
1134 	int i, num_blocks;
1135 
1136 	num_blocks = 0;
1137 
1138 	for (i = 0; i < 4; i++) {
1139 		_iov_alloc_buf(&iovs[i], 512 * (i + 1));
1140 		num_blocks += i + 1;
1141 	}
1142 	_iov_alloc_buf(&md_iov, 8 * num_blocks);
1143 
1144 	dix_generate_and_verify(iovs, 4, &md_iov, 512, 8, num_blocks, false, SPDK_DIF_TYPE1,
1145 				0, 22, 0xFFFF, 0x22);
1146 
1147 	dix_generate_and_verify(iovs, 4, &md_iov, 512, 8, num_blocks, false, SPDK_DIF_TYPE1,
1148 				SPDK_DIF_FLAGS_GUARD_CHECK, 22, 0xFFFF, 0x22);
1149 
1150 	dix_generate_and_verify(iovs, 4, &md_iov, 512, 8, num_blocks, false, SPDK_DIF_TYPE1,
1151 				SPDK_DIF_FLAGS_APPTAG_CHECK, 22, 0xFFFF, 0x22);
1152 
1153 	dix_generate_and_verify(iovs, 4, &md_iov, 512, 8, num_blocks, false, SPDK_DIF_TYPE1,
1154 				SPDK_DIF_FLAGS_REFTAG_CHECK, 22, 0xFFFF, 0x22);
1155 
1156 	for (i = 0; i < 4; i++) {
1157 		_iov_free_buf(&iovs[i]);
1158 	}
1159 	_iov_free_buf(&md_iov);
1160 }
1161 
1162 static void
1163 dix_sec_4096_md_128_prchk_7_multi_iovs(void)
1164 {
1165 	struct iovec iovs[4], md_iov;
1166 	uint32_t dif_flags;
1167 	int i, num_blocks;
1168 
1169 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
1170 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
1171 
1172 	num_blocks = 0;
1173 
1174 	for (i = 0; i < 4; i++) {
1175 		_iov_alloc_buf(&iovs[i], 4096 * (i + 1));
1176 		num_blocks += i + 1;
1177 	}
1178 	_iov_alloc_buf(&md_iov, 128 * num_blocks);
1179 
1180 	dix_generate_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, false, SPDK_DIF_TYPE1,
1181 				dif_flags, 22, 0xFFFF, 0x22);
1182 	dix_generate_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, true, SPDK_DIF_TYPE1,
1183 				dif_flags, 22, 0xFFFF, 0x22);
1184 
1185 	for (i = 0; i < 4; i++) {
1186 		_iov_free_buf(&iovs[i]);
1187 	}
1188 	_iov_free_buf(&md_iov);
1189 }
1190 
1191 static void
1192 dix_sec_512_md_8_prchk_7_multi_iovs_split_data(void)
1193 {
1194 	struct iovec iovs[2], md_iov;
1195 	uint32_t dif_flags;
1196 
1197 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
1198 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
1199 
1200 	_iov_alloc_buf(&iovs[0], 256);
1201 	_iov_alloc_buf(&iovs[1], 256);
1202 	_iov_alloc_buf(&md_iov, 8);
1203 
1204 	dix_generate_and_verify(iovs, 2, &md_iov, 512, 8, 1, false, SPDK_DIF_TYPE1,
1205 				dif_flags, 22, 0xFFFF, 0x22);
1206 
1207 	_iov_free_buf(&iovs[0]);
1208 	_iov_free_buf(&iovs[1]);
1209 	_iov_free_buf(&md_iov);
1210 }
1211 
1212 static void
1213 dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits(void)
1214 {
1215 	struct iovec iovs[6], md_iov;
1216 	uint32_t dif_flags;
1217 	int i;
1218 
1219 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
1220 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
1221 
1222 	/* data[0][255:0] */
1223 	_iov_alloc_buf(&iovs[0], 256);
1224 
1225 	/* data[0][511:256], data[1][255:0] */
1226 	_iov_alloc_buf(&iovs[1], 256 + 256);
1227 
1228 	/* data[1][382:256] */
1229 	_iov_alloc_buf(&iovs[2], 128);
1230 
1231 	/* data[1][383] */
1232 	_iov_alloc_buf(&iovs[3], 1);
1233 
1234 	/* data[1][510:384] */
1235 	_iov_alloc_buf(&iovs[4], 126);
1236 
1237 	/* data[1][511], data[2][511:0], data[3][511:0] */
1238 	_iov_alloc_buf(&iovs[5], 1 + 512 * 2);
1239 
1240 	_iov_alloc_buf(&md_iov, 8 * 4);
1241 
1242 	dix_generate_and_verify(iovs, 6, &md_iov, 512, 8, 4, false, SPDK_DIF_TYPE1,
1243 				dif_flags, 22, 0xFFFF, 0x22);
1244 
1245 	for (i = 0; i < 6; i++) {
1246 		_iov_free_buf(&iovs[i]);
1247 	}
1248 	_iov_free_buf(&md_iov);
1249 }
1250 
1251 static void
1252 _dix_inject_error_and_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1253 			     uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
1254 			     uint32_t inject_flags, bool dif_loc)
1255 {
1256 	struct spdk_dif_ctx ctx = {};
1257 	struct spdk_dif_error err_blk = {};
1258 	uint32_t inject_offset = 0, dif_flags;
1259 	int rc;
1260 
1261 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
1262 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
1263 
1264 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, 0, num_blocks);
1265 	CU_ASSERT(rc == 0);
1266 
1267 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, false, dif_loc, SPDK_DIF_TYPE1, dif_flags,
1268 			       88, 0xFFFF, 0x88, GUARD_SEED);
1269 	CU_ASSERT(rc == 0);
1270 
1271 	rc = spdk_dix_generate(iovs, iovcnt, md_iov, num_blocks, &ctx);
1272 	CU_ASSERT(rc == 0);
1273 
1274 	rc = spdk_dix_inject_error(iovs, iovcnt, md_iov, num_blocks, &ctx, inject_flags, &inject_offset);
1275 	CU_ASSERT(rc == 0);
1276 
1277 	rc = spdk_dix_verify(iovs, iovcnt, md_iov, num_blocks, &ctx, &err_blk);
1278 	CU_ASSERT(rc != 0);
1279 
1280 	if (inject_flags == SPDK_DIF_DATA_ERROR) {
1281 		CU_ASSERT(SPDK_DIF_GUARD_ERROR == err_blk.err_type);
1282 	} else {
1283 		CU_ASSERT(inject_flags == err_blk.err_type);
1284 	}
1285 	CU_ASSERT(inject_offset == err_blk.err_offset);
1286 }
1287 
1288 static void
1289 dix_inject_error_and_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1290 			    uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
1291 			    uint32_t inject_flags)
1292 {
1293 	/* The case that DIF is contained in the first 8 bytes of metadata. */
1294 	_dix_inject_error_and_verify(iovs, iovcnt, md_iov, block_size, md_size, num_blocks,
1295 				     inject_flags, true);
1296 
1297 	/* The case that DIF is contained in the last 8 bytes of metadata. */
1298 	_dix_inject_error_and_verify(iovs, iovcnt, md_iov, block_size, md_size, num_blocks,
1299 				     inject_flags, false);
1300 }
1301 
1302 static void
1303 dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test(void)
1304 {
1305 	struct iovec iovs[4], md_iov;
1306 	int i, num_blocks;
1307 
1308 	num_blocks = 0;
1309 
1310 	for (i = 0; i < 4; i++) {
1311 		_iov_alloc_buf(&iovs[i], 4096 * (i + 1));
1312 		num_blocks += i + 1;
1313 	}
1314 
1315 	_iov_alloc_buf(&md_iov, 128 * num_blocks);
1316 
1317 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, SPDK_DIF_GUARD_ERROR);
1318 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, SPDK_DIF_APPTAG_ERROR);
1319 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, SPDK_DIF_REFTAG_ERROR);
1320 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, SPDK_DIF_DATA_ERROR);
1321 
1322 	for (i = 0; i < 4; i++) {
1323 		_iov_free_buf(&iovs[i]);
1324 	}
1325 	_iov_free_buf(&md_iov);
1326 }
1327 
1328 static void
1329 dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test(void)
1330 {
1331 	struct iovec iovs[4], md_iov;
1332 	int i;
1333 
1334 	_iov_alloc_buf(&iovs[0], 2048);
1335 	_iov_alloc_buf(&iovs[1], 2048);
1336 	_iov_alloc_buf(&iovs[2], 1);
1337 	_iov_alloc_buf(&iovs[3], 4095);
1338 
1339 	_iov_alloc_buf(&md_iov, 128 * 2);
1340 
1341 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, 2, SPDK_DIF_GUARD_ERROR);
1342 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, 2, SPDK_DIF_APPTAG_ERROR);
1343 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, 2, SPDK_DIF_REFTAG_ERROR);
1344 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, 2, SPDK_DIF_DATA_ERROR);
1345 
1346 	for (i = 0; i < 4; i++) {
1347 		_iov_free_buf(&iovs[i]);
1348 	}
1349 	_iov_free_buf(&md_iov);
1350 }
1351 
1352 int
1353 main(int argc, char **argv)
1354 {
1355 	CU_pSuite	suite = NULL;
1356 	unsigned int	num_failures;
1357 
1358 	if (CU_initialize_registry() != CUE_SUCCESS) {
1359 		return CU_get_error();
1360 	}
1361 
1362 	suite = CU_add_suite("dif", NULL, NULL);
1363 	if (suite == NULL) {
1364 		CU_cleanup_registry();
1365 		return CU_get_error();
1366 	}
1367 
1368 	if (
1369 		CU_add_test(suite, "dif_generate_and_verify_test", dif_generate_and_verify_test) == NULL ||
1370 		CU_add_test(suite, "dif_disable_check_test", dif_disable_check_test) == NULL ||
1371 		CU_add_test(suite, "dif_sec_512_md_0_error_test", dif_sec_512_md_0_error_test) == NULL ||
1372 		CU_add_test(suite, "dif_guard_seed_test", dif_guard_seed_test) == NULL ||
1373 		CU_add_test(suite, "dif_disable_sec_512_md_8_single_iov_test",
1374 			    dif_disable_sec_512_md_8_single_iov_test) == NULL ||
1375 		CU_add_test(suite, "dif_sec_512_md_8_prchk_0_single_iov_test",
1376 			    dif_sec_512_md_8_prchk_0_single_iov_test) == NULL ||
1377 		CU_add_test(suite, "dif_sec_512_md_8_prchk_0_1_2_4_multi_iovs_test",
1378 			    dif_sec_512_md_8_prchk_0_1_2_4_multi_iovs_test) == NULL ||
1379 		CU_add_test(suite, "dif_sec_4096_md_128_prchk_7_multi_iovs_test",
1380 			    dif_sec_4096_md_128_prchk_7_multi_iovs_test) == NULL ||
1381 		CU_add_test(suite, "dif_sec_512_md_8_prchk_7_multi_iovs_split_data_and_md_test",
1382 			    dif_sec_512_md_8_prchk_7_multi_iovs_split_data_and_md_test) == NULL ||
1383 		CU_add_test(suite, "dif_sec_512_md_8_prchk_7_multi_iovs_split_data_test",
1384 			    dif_sec_512_md_8_prchk_7_multi_iovs_split_data_test) == NULL ||
1385 		CU_add_test(suite, "dif_sec_512_md_8_prchk_7_multi_iovs_split_guard_test",
1386 			    dif_sec_512_md_8_prchk_7_multi_iovs_split_guard_test) == NULL ||
1387 		CU_add_test(suite, "dif_sec_512_md_8_prchk_7_multi_iovs_split_apptag_test",
1388 			    dif_sec_512_md_8_prchk_7_multi_iovs_split_apptag_test) == NULL ||
1389 		CU_add_test(suite, "dif_sec_512_md_8_prchk_7_multi_iovs_split_reftag_test",
1390 			    dif_sec_512_md_8_prchk_7_multi_iovs_split_reftag_test) == NULL ||
1391 		CU_add_test(suite, "dif_sec_512_md_8_prchk_7_multi_iovs_complex_splits_test",
1392 			    dif_sec_512_md_8_prchk_7_multi_iovs_complex_splits_test) == NULL ||
1393 		CU_add_test(suite, "dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_test",
1394 			    dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_test) == NULL ||
1395 		CU_add_test(suite, "dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test",
1396 			    dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test) == NULL ||
1397 		CU_add_test(suite, "dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_data_and_md_test",
1398 			    dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_data_and_md_test) == NULL ||
1399 		CU_add_test(suite, "dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_data_test",
1400 			    dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_data_test) == NULL ||
1401 		CU_add_test(suite, "dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_guard_test",
1402 			    dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_guard_test) == NULL ||
1403 		CU_add_test(suite, "dif_sec_4096_md_128_inject_1_2_4_8__multi_iovs_split_apptag_test",
1404 			    dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_apptag_test) == NULL ||
1405 		CU_add_test(suite, "dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_reftag_test",
1406 			    dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_reftag_test) == NULL ||
1407 		CU_add_test(suite, "dif_copy_sec_512_md_8_prchk_0_single_iov",
1408 			    dif_copy_sec_512_md_8_prchk_0_single_iov) == NULL ||
1409 		CU_add_test(suite, "dif_copy_sec_512_md_8_prchk_0_1_2_4_multi_iovs",
1410 			    dif_copy_sec_512_md_8_prchk_0_1_2_4_multi_iovs) == NULL ||
1411 		CU_add_test(suite, "dif_copy_sec_4096_md_128_prchk_7_multi_iovs",
1412 			    dif_copy_sec_4096_md_128_prchk_7_multi_iovs) == NULL ||
1413 		CU_add_test(suite, "dif_copy_sec_512_md_8_prchk_7_multi_iovs_split_data",
1414 			    dif_copy_sec_512_md_8_prchk_7_multi_iovs_split_data) == NULL ||
1415 		CU_add_test(suite, "dif_copy_sec_512_md_8_prchk_7_multi_iovs_complex_splits",
1416 			    dif_copy_sec_512_md_8_prchk_7_multi_iovs_complex_splits) == NULL ||
1417 		CU_add_test(suite, "dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test",
1418 			    dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test) == NULL ||
1419 		CU_add_test(suite, "dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test",
1420 			    dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test) == NULL ||
1421 		CU_add_test(suite, "dix_sec_512_md_0_error", dix_sec_512_md_0_error) == NULL ||
1422 		CU_add_test(suite, "dix_sec_512_md_8_prchk_0_single_iov",
1423 			    dix_sec_512_md_8_prchk_0_single_iov) == NULL ||
1424 		CU_add_test(suite, "dix_sec_512_md_8_prchk_0_1_2_4_multi_iovs",
1425 			    dix_sec_512_md_8_prchk_0_1_2_4_multi_iovs) == NULL ||
1426 		CU_add_test(suite, "dix_sec_4096_md_128_prchk_7_multi_iovs",
1427 			    dix_sec_4096_md_128_prchk_7_multi_iovs) == NULL ||
1428 		CU_add_test(suite, "dix_sec_512_md_8_prchk_7_multi_iovs_split_data",
1429 			    dix_sec_512_md_8_prchk_7_multi_iovs_split_data) == NULL ||
1430 		CU_add_test(suite, "dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits",
1431 			    dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits) == NULL ||
1432 		CU_add_test(suite, "dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test",
1433 			    dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test) == NULL ||
1434 		CU_add_test(suite, "dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test",
1435 			    dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test) == NULL
1436 	) {
1437 		CU_cleanup_registry();
1438 		return CU_get_error();
1439 	}
1440 
1441 	CU_basic_set_mode(CU_BRM_VERBOSE);
1442 
1443 	CU_basic_run_tests();
1444 
1445 	num_failures = CU_get_number_of_failures();
1446 	CU_cleanup_registry();
1447 
1448 	return num_failures;
1449 }
1450