xref: /spdk/test/unit/lib/util/dif.c/dif_ut.c (revision 1b1967bdd61daa5ec110e2ca6c73c7b38a60bb89)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2019 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 
8 #include "spdk_cunit.h"
9 
10 #include "util/dif.c"
11 
12 #define DATA_PATTERN(offset)	((uint8_t)(0xAB + (offset)))
13 #define GUARD_SEED		0xCD
14 
15 static int
16 ut_data_pattern_generate(struct iovec *iovs, int iovcnt,
17 			 uint32_t block_size, uint32_t md_size, uint32_t num_blocks)
18 {
19 	struct _dif_sgl sgl;
20 	uint32_t offset_blocks, offset_in_block, buf_len, data_offset, i;
21 	uint8_t *buf;
22 
23 	_dif_sgl_init(&sgl, iovs, iovcnt);
24 
25 	if (!_dif_sgl_is_valid(&sgl, block_size * num_blocks)) {
26 		return -1;
27 	}
28 
29 	offset_blocks = 0;
30 	data_offset = 0;
31 
32 	while (offset_blocks < num_blocks) {
33 		offset_in_block = 0;
34 		while (offset_in_block < block_size) {
35 			_dif_sgl_get_buf(&sgl, (void *)&buf, &buf_len);
36 			if (offset_in_block < block_size - md_size) {
37 				buf_len = spdk_min(buf_len,
38 						   block_size - md_size - offset_in_block);
39 				for (i = 0; i < buf_len; i++) {
40 					buf[i] = DATA_PATTERN(data_offset + i);
41 				}
42 				data_offset += buf_len;
43 			} else {
44 				buf_len = spdk_min(buf_len, block_size - offset_in_block);
45 				memset(buf, 0, buf_len);
46 			}
47 			_dif_sgl_advance(&sgl, buf_len);
48 			offset_in_block += buf_len;
49 		}
50 		offset_blocks++;
51 	}
52 
53 	return 0;
54 }
55 
56 static int
57 ut_data_pattern_verify(struct iovec *iovs, int iovcnt,
58 		       uint32_t block_size, uint32_t md_size, uint32_t num_blocks)
59 {
60 	struct _dif_sgl sgl;
61 	uint32_t offset_blocks, offset_in_block, buf_len, data_offset, i;
62 	uint8_t *buf;
63 
64 	_dif_sgl_init(&sgl, iovs, iovcnt);
65 
66 	if (!_dif_sgl_is_valid(&sgl, block_size * num_blocks)) {
67 		return -1;
68 	}
69 
70 	offset_blocks = 0;
71 	data_offset = 0;
72 
73 	while (offset_blocks < num_blocks) {
74 		offset_in_block = 0;
75 		while (offset_in_block < block_size) {
76 			_dif_sgl_get_buf(&sgl, (void *)&buf, &buf_len);
77 
78 			if (offset_in_block < block_size - md_size) {
79 				buf_len = spdk_min(buf_len,
80 						   block_size - md_size - offset_in_block);
81 				for (i = 0; i < buf_len; i++) {
82 					if (buf[i] != DATA_PATTERN(data_offset + i)) {
83 						return -1;
84 					}
85 				}
86 				data_offset += buf_len;
87 			} else {
88 				buf_len = spdk_min(buf_len, block_size - offset_in_block);
89 			}
90 			_dif_sgl_advance(&sgl, buf_len);
91 			offset_in_block += buf_len;
92 		}
93 		offset_blocks++;
94 	}
95 
96 	return 0;
97 }
98 
99 static void
100 _iov_alloc_buf(struct iovec *iov, uint32_t len)
101 {
102 	iov->iov_base = calloc(1, len);
103 	iov->iov_len = len;
104 	SPDK_CU_ASSERT_FATAL(iov->iov_base != NULL);
105 }
106 
107 static void
108 _iov_free_buf(struct iovec *iov)
109 {
110 	free(iov->iov_base);
111 }
112 
113 static void
114 _iov_set_buf(struct iovec *iov, uint8_t *buf, uint32_t buf_len)
115 {
116 	iov->iov_base = buf;
117 	iov->iov_len = buf_len;
118 }
119 
120 static bool
121 _iov_check(struct iovec *iov, void *iov_base, uint32_t iov_len)
122 {
123 	return (iov->iov_base == iov_base && iov->iov_len == iov_len);
124 }
125 
126 static void
127 _dif_generate_and_verify(struct iovec *iov,
128 			 uint32_t block_size, uint32_t md_size, bool dif_loc,
129 			 enum spdk_dif_type dif_type, uint32_t dif_flags,
130 			 uint32_t ref_tag, uint32_t e_ref_tag,
131 			 uint16_t app_tag, uint16_t apptag_mask, uint16_t e_app_tag,
132 			 bool expect_pass)
133 {
134 	struct spdk_dif_ctx ctx = {};
135 	uint32_t guard_interval;
136 	uint16_t guard = 0;
137 	int rc;
138 
139 	rc = ut_data_pattern_generate(iov, 1, block_size, md_size, 1);
140 	CU_ASSERT(rc == 0);
141 
142 	guard_interval = _get_guard_interval(block_size, md_size, dif_loc, true);
143 
144 	ctx.dif_type = dif_type;
145 	ctx.dif_flags = dif_flags;
146 	ctx.init_ref_tag = ref_tag;
147 	ctx.app_tag = app_tag;
148 
149 	if (dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
150 		guard = spdk_crc16_t10dif(0, iov->iov_base, guard_interval);
151 	}
152 
153 	_dif_generate(iov->iov_base + guard_interval, guard, 0, &ctx);
154 
155 	ctx.init_ref_tag = e_ref_tag;
156 	ctx.apptag_mask = apptag_mask;
157 	ctx.app_tag = e_app_tag;
158 
159 	rc = _dif_verify(iov->iov_base + guard_interval, guard, 0, &ctx, NULL);
160 	CU_ASSERT((expect_pass && rc == 0) || (!expect_pass && rc != 0));
161 
162 	rc = ut_data_pattern_verify(iov, 1, block_size, md_size, 1);
163 	CU_ASSERT(rc == 0);
164 }
165 
166 static void
167 dif_generate_and_verify_test(void)
168 {
169 	struct iovec iov;
170 	uint32_t dif_flags;
171 
172 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
173 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
174 
175 	_iov_alloc_buf(&iov, 4096 + 128);
176 
177 	/* Positive cases */
178 
179 	/* The case that DIF is contained in the first 8 bytes of metadata. */
180 	_dif_generate_and_verify(&iov,
181 				 4096 + 128, 128, true,
182 				 SPDK_DIF_TYPE1, dif_flags,
183 				 22, 22,
184 				 0x22, 0xFFFF, 0x22,
185 				 true);
186 
187 	/* The case that DIF is contained in the last 8 bytes of metadata. */
188 	_dif_generate_and_verify(&iov,
189 				 4096 + 128, 128, false,
190 				 SPDK_DIF_TYPE1, dif_flags,
191 				 22, 22,
192 				 0x22, 0xFFFF, 0x22,
193 				 true);
194 
195 	/* Negative cases */
196 
197 	/* Reference tag doesn't match. */
198 	_dif_generate_and_verify(&iov,
199 				 4096 + 128, 128, false,
200 				 SPDK_DIF_TYPE1, dif_flags,
201 				 22, 23,
202 				 0x22, 0xFFFF, 0x22,
203 				 false);
204 
205 	/* Application tag doesn't match. */
206 	_dif_generate_and_verify(&iov,
207 				 4096 + 128, 128, false,
208 				 SPDK_DIF_TYPE1, dif_flags,
209 				 22, 22,
210 				 0x22, 0xFFFF, 0x23,
211 				 false);
212 
213 	_iov_free_buf(&iov);
214 }
215 
216 static void
217 dif_disable_check_test(void)
218 {
219 	struct iovec iov;
220 	uint32_t dif_flags;
221 
222 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
223 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
224 
225 	_iov_alloc_buf(&iov, 4096 + 128);
226 
227 	/* The case that DIF check is disabled when the Application Tag is 0xFFFF for
228 	 * Type 1. DIF check is disabled and pass is expected.
229 	 */
230 	_dif_generate_and_verify(&iov,
231 				 4096 + 128, 128, false,
232 				 SPDK_DIF_TYPE1, dif_flags,
233 				 22, 22,
234 				 0xFFFF, 0xFFFF, 0x22,
235 				 true);
236 
237 	/* The case that DIF check is not disabled when the Application Tag is 0xFFFF but
238 	 * the Reference Tag is not 0xFFFFFFFF for Type 3. DIF check is not disabled and
239 	 * fail is expected.
240 	 */
241 	_dif_generate_and_verify(&iov,
242 				 4096 + 128, 128, false,
243 				 SPDK_DIF_TYPE3, dif_flags,
244 				 22, 22,
245 				 0xFFFF, 0xFFFF, 0x22,
246 				 false);
247 
248 	/* The case that DIF check is disabled when the Application Tag is 0xFFFF and
249 	 * the Reference Tag is 0xFFFFFFFF for Type 3. DIF check is disabled and
250 	 * pass is expected.
251 	 */
252 	_dif_generate_and_verify(&iov,
253 				 4096 + 128, 128, false,
254 				 SPDK_DIF_TYPE3, dif_flags,
255 				 0xFFFFFFFF, 22,
256 				 0xFFFF, 0xFFFF, 0x22,
257 				 true);
258 
259 	_iov_free_buf(&iov);
260 }
261 
262 static void
263 dif_sec_512_md_0_error_test(void)
264 {
265 	struct spdk_dif_ctx ctx = {};
266 	int rc;
267 	struct spdk_dif_ctx_init_ext_opts dif_opts;
268 
269 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
270 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
271 	/* Metadata size is 0. */
272 	rc = spdk_dif_ctx_init(&ctx, 512, 0, true, false, SPDK_DIF_TYPE1,
273 			       0, 0, 0, 0, 0, 0, &dif_opts);
274 	CU_ASSERT(rc != 0);
275 }
276 
277 static void
278 dif_guard_seed_test(void)
279 {
280 	struct iovec iov;
281 	struct spdk_dif_ctx ctx = {};
282 	struct spdk_dif_error err_blk = {};
283 	struct spdk_dif *dif;
284 	uint16_t guard;
285 	int rc;
286 	struct spdk_dif_ctx_init_ext_opts dif_opts;
287 
288 	_iov_alloc_buf(&iov, 512 + 8);
289 
290 	memset(iov.iov_base, 0, 512 + 8);
291 
292 	dif = (struct spdk_dif *)(iov.iov_base + 512);
293 
294 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
295 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
296 	rc = spdk_dif_ctx_init(&ctx, 512 + 8, 8, true, false, SPDK_DIF_TYPE1,
297 			       SPDK_DIF_FLAGS_GUARD_CHECK, 0, 0, 0, 0, 0, &dif_opts);
298 	CU_ASSERT(rc == 0);
299 
300 	rc = spdk_dif_generate(&iov, 1, 1, &ctx);
301 	CU_ASSERT(rc == 0);
302 
303 	/* Guard should be zero if the block is all zero and seed is not added. */
304 	guard = from_be16(&dif->g16.guard);
305 	CU_ASSERT(guard == 0);
306 
307 	rc = spdk_dif_verify(&iov, 1, 1, &ctx, &err_blk);
308 	CU_ASSERT(rc == 0);
309 
310 	rc = spdk_dif_ctx_init(&ctx, 512 + 8, 8, true, false, SPDK_DIF_TYPE1,
311 			       SPDK_DIF_FLAGS_GUARD_CHECK, 0, 0, 0, 0, GUARD_SEED, &dif_opts);
312 	CU_ASSERT(rc == 0);
313 
314 	rc = spdk_dif_generate(&iov, 1, 1, &ctx);
315 	CU_ASSERT(rc == 0);
316 
317 	/* Guard should not be zero if the block is all zero but seed is added. */
318 	guard = from_be16(&dif->g16.guard);
319 	CU_ASSERT(guard != 0);
320 
321 	rc = spdk_dif_verify(&iov, 1, 1, &ctx, &err_blk);
322 	CU_ASSERT(rc == 0);
323 
324 	_iov_free_buf(&iov);
325 }
326 
327 static void
328 dif_generate_and_verify(struct iovec *iovs, int iovcnt,
329 			uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
330 			bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
331 			uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag)
332 {
333 	struct spdk_dif_ctx ctx = {};
334 	int rc;
335 	struct spdk_dif_ctx_init_ext_opts dif_opts;
336 
337 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, md_size, num_blocks);
338 	CU_ASSERT(rc == 0);
339 
340 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
341 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
342 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc, dif_type, dif_flags,
343 			       init_ref_tag, apptag_mask, app_tag, 0, GUARD_SEED, &dif_opts);
344 	CU_ASSERT(rc == 0);
345 
346 	rc = spdk_dif_generate(iovs, iovcnt, num_blocks, &ctx);
347 	CU_ASSERT(rc == 0);
348 
349 	rc = spdk_dif_verify(iovs, iovcnt, num_blocks, &ctx, NULL);
350 	CU_ASSERT(rc == 0);
351 
352 	rc = ut_data_pattern_verify(iovs, iovcnt, block_size, md_size, num_blocks);
353 	CU_ASSERT(rc == 0);
354 }
355 
356 static void
357 dif_disable_sec_512_md_8_single_iov_test(void)
358 {
359 	struct iovec iov;
360 
361 	_iov_alloc_buf(&iov, 512 + 8);
362 
363 	dif_generate_and_verify(&iov, 1, 512 + 8, 8, 1, false, SPDK_DIF_DISABLE, 0, 0, 0, 0);
364 
365 	_iov_free_buf(&iov);
366 }
367 
368 static void
369 dif_sec_512_md_8_prchk_0_single_iov_test(void)
370 {
371 	struct iovec iov;
372 
373 	_iov_alloc_buf(&iov, 512 + 8);
374 
375 	dif_generate_and_verify(&iov, 1, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1, 0, 0, 0, 0);
376 
377 	_iov_free_buf(&iov);
378 }
379 
380 static void
381 dif_sec_512_md_8_prchk_0_1_2_4_multi_iovs_test(void)
382 {
383 	struct iovec iovs[4];
384 	int i, num_blocks;
385 
386 	num_blocks = 0;
387 
388 	for (i = 0; i < 4; i++) {
389 		_iov_alloc_buf(&iovs[i], (512 + 8) * (i + 1));
390 		num_blocks += i + 1;
391 	}
392 
393 	dif_generate_and_verify(iovs, 4, 512 + 8, 8, num_blocks, false, SPDK_DIF_TYPE1,
394 				0, 22, 0xFFFF, 0x22);
395 
396 	dif_generate_and_verify(iovs, 4, 512 + 8, 8, num_blocks, false, SPDK_DIF_TYPE1,
397 				SPDK_DIF_FLAGS_GUARD_CHECK, 22, 0xFFFF, 0x22);
398 
399 	dif_generate_and_verify(iovs, 4, 512 + 8, 8, num_blocks, false, SPDK_DIF_TYPE1,
400 				SPDK_DIF_FLAGS_APPTAG_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_REFTAG_CHECK, 22, 0xFFFF, 0x22);
404 
405 	for (i = 0; i < 4; i++) {
406 		_iov_free_buf(&iovs[i]);
407 	}
408 }
409 
410 static void
411 dif_sec_4096_md_128_prchk_7_multi_iovs_test(void)
412 {
413 	struct iovec iovs[4];
414 	int i, num_blocks;
415 	uint32_t dif_flags;
416 
417 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
418 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
419 
420 	num_blocks = 0;
421 
422 	for (i = 0; i < 4; i++) {
423 		_iov_alloc_buf(&iovs[i], (4096 + 128) * (i + 1));
424 		num_blocks += i + 1;
425 	}
426 
427 	dif_generate_and_verify(iovs, 4, 4096 + 128, 128, num_blocks, false, SPDK_DIF_TYPE1,
428 				dif_flags, 22, 0xFFFF, 0x22);
429 
430 	dif_generate_and_verify(iovs, 4, 4096 + 128, 128, num_blocks, true, SPDK_DIF_TYPE1,
431 				dif_flags, 22, 0xFFFF, 0x22);
432 
433 	for (i = 0; i < 4; i++) {
434 		_iov_free_buf(&iovs[i]);
435 	}
436 }
437 
438 static void
439 dif_sec_512_md_8_prchk_7_multi_iovs_split_data_and_md_test(void)
440 {
441 	struct iovec iovs[2];
442 	uint32_t dif_flags;
443 
444 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
445 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
446 
447 	_iov_alloc_buf(&iovs[0], 512);
448 	_iov_alloc_buf(&iovs[1], 8);
449 
450 	dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1,
451 				dif_flags, 22, 0xFFFF, 0x22);
452 
453 	_iov_free_buf(&iovs[0]);
454 	_iov_free_buf(&iovs[1]);
455 }
456 
457 static void
458 dif_sec_512_md_8_prchk_7_multi_iovs_split_data_test(void)
459 {
460 	struct iovec iovs[2];
461 	uint32_t dif_flags;
462 
463 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
464 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
465 
466 	_iov_alloc_buf(&iovs[0], 256);
467 	_iov_alloc_buf(&iovs[1], 264);
468 
469 	dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1,
470 				dif_flags, 22, 0xFFFF, 0x22);
471 
472 	_iov_free_buf(&iovs[0]);
473 	_iov_free_buf(&iovs[1]);
474 }
475 
476 static void
477 dif_sec_512_md_8_prchk_7_multi_iovs_split_guard_test(void)
478 {
479 	struct iovec iovs[2];
480 	uint32_t dif_flags;
481 
482 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
483 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
484 
485 	_iov_alloc_buf(&iovs[0], 513);
486 	_iov_alloc_buf(&iovs[1], 7);
487 
488 	dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1,
489 				dif_flags, 22, 0xFFFF, 0x22);
490 
491 	_iov_free_buf(&iovs[0]);
492 	_iov_free_buf(&iovs[1]);
493 }
494 
495 static void
496 dif_sec_512_md_8_prchk_7_multi_iovs_split_apptag_test(void)
497 {
498 	struct iovec iovs[2];
499 	uint32_t dif_flags;
500 
501 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
502 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
503 
504 	_iov_alloc_buf(&iovs[0], 515);
505 	_iov_alloc_buf(&iovs[1], 5);
506 
507 	dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1,
508 				dif_flags, 22, 0xFFFF, 0x22);
509 
510 	_iov_free_buf(&iovs[0]);
511 	_iov_free_buf(&iovs[1]);
512 }
513 
514 static void
515 dif_sec_512_md_8_prchk_7_multi_iovs_split_reftag_test(void)
516 {
517 	struct iovec iovs[2];
518 	uint32_t dif_flags;
519 
520 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
521 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
522 
523 	_iov_alloc_buf(&iovs[0], 518);
524 	_iov_alloc_buf(&iovs[1], 2);
525 
526 	dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1,
527 				dif_flags, 22, 0xFFFF, 0x22);
528 
529 	_iov_free_buf(&iovs[0]);
530 	_iov_free_buf(&iovs[1]);
531 }
532 
533 static void
534 dif_sec_512_md_8_prchk_7_multi_iovs_complex_splits_test(void)
535 {
536 	struct iovec iovs[9];
537 	uint32_t dif_flags;
538 	int i;
539 
540 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
541 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
542 
543 	/* data[0][255:0] */
544 	_iov_alloc_buf(&iovs[0], 256);
545 
546 	/* data[0][511:256], guard[0][0] */
547 	_iov_alloc_buf(&iovs[1], 256 + 1);
548 
549 	/* guard[0][1], apptag[0][0] */
550 	_iov_alloc_buf(&iovs[2], 1 + 1);
551 
552 	/* apptag[0][1], reftag[0][0] */
553 	_iov_alloc_buf(&iovs[3], 1 + 1);
554 
555 	/* reftag[0][3:1], data[1][255:0] */
556 	_iov_alloc_buf(&iovs[4], 3 + 256);
557 
558 	/* data[1][511:256], guard[1][0] */
559 	_iov_alloc_buf(&iovs[5], 256 + 1);
560 
561 	/* guard[1][1], apptag[1][0] */
562 	_iov_alloc_buf(&iovs[6], 1 + 1);
563 
564 	/* apptag[1][1], reftag[1][0] */
565 	_iov_alloc_buf(&iovs[7], 1 + 1);
566 
567 	/* reftag[1][3:1] */
568 	_iov_alloc_buf(&iovs[8], 3);
569 
570 	dif_generate_and_verify(iovs, 9, 512 + 8, 8, 2, false, SPDK_DIF_TYPE1, dif_flags,
571 				22, 0xFFFF, 0x22);
572 
573 	for (i = 0; i < 9; i++) {
574 		_iov_free_buf(&iovs[i]);
575 	}
576 }
577 
578 static void
579 dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_test(void)
580 {
581 	struct iovec iovs[11];
582 	uint32_t dif_flags;
583 	int i;
584 
585 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
586 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
587 
588 	/* data[0][1000:0] */
589 	_iov_alloc_buf(&iovs[0], 1000);
590 
591 	/* data[0][3095:1000], guard[0][0] */
592 	_iov_alloc_buf(&iovs[1], 3096 + 1);
593 
594 	/* guard[0][1], apptag[0][0] */
595 	_iov_alloc_buf(&iovs[2], 1 + 1);
596 
597 	/* apptag[0][1], reftag[0][0] */
598 	_iov_alloc_buf(&iovs[3], 1 + 1);
599 
600 	/* reftag[0][3:1], ignore[0][59:0] */
601 	_iov_alloc_buf(&iovs[4], 3 + 60);
602 
603 	/* ignore[119:60], data[1][3050:0] */
604 	_iov_alloc_buf(&iovs[5], 60 + 3051);
605 
606 	/* data[1][4095:3050], guard[1][0] */
607 	_iov_alloc_buf(&iovs[6], 1045 + 1);
608 
609 	/* guard[1][1], apptag[1][0] */
610 	_iov_alloc_buf(&iovs[7], 1 + 1);
611 
612 	/* apptag[1][1], reftag[1][0] */
613 	_iov_alloc_buf(&iovs[8], 1 + 1);
614 
615 	/* reftag[1][3:1], ignore[1][9:0] */
616 	_iov_alloc_buf(&iovs[9], 3 + 10);
617 
618 	/* ignore[1][127:9] */
619 	_iov_alloc_buf(&iovs[10], 118);
620 
621 	dif_generate_and_verify(iovs, 11, 4096 + 128, 128, 2, false, SPDK_DIF_TYPE1, dif_flags,
622 				22, 0xFFFF, 0x22);
623 	dif_generate_and_verify(iovs, 11, 4096 + 128, 128, 2, true, SPDK_DIF_TYPE1, dif_flags,
624 				22, 0xFFFF, 0x22);
625 
626 	for (i = 0; i < 11; i++) {
627 		_iov_free_buf(&iovs[i]);
628 	}
629 }
630 
631 static void
632 _dif_inject_error_and_verify(struct iovec *iovs, int iovcnt,
633 			     uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
634 			     uint32_t inject_flags, bool dif_loc)
635 {
636 	struct spdk_dif_ctx ctx = {};
637 	struct spdk_dif_error err_blk = {};
638 	uint32_t inject_offset = 0, dif_flags;
639 	int rc;
640 	struct spdk_dif_ctx_init_ext_opts dif_opts;
641 
642 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
643 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
644 
645 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, md_size, num_blocks);
646 	CU_ASSERT(rc == 0);
647 
648 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
649 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
650 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc,
651 			       SPDK_DIF_TYPE1, dif_flags, 88, 0xFFFF, 0x88, 0, GUARD_SEED, &dif_opts);
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 	struct spdk_dif_ctx_init_ext_opts dif_opts;
805 
806 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size - md_size, 0, num_blocks);
807 	CU_ASSERT(rc == 0);
808 
809 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
810 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
811 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc, dif_type, dif_flags,
812 			       init_ref_tag, apptag_mask, app_tag, 0, GUARD_SEED, &dif_opts);
813 	CU_ASSERT(rc == 0);
814 
815 	rc = spdk_dif_generate_copy(iovs, iovcnt, bounce_iov, 1, num_blocks, &ctx);
816 	CU_ASSERT(rc == 0);
817 
818 	rc = spdk_dif_verify_copy(iovs, iovcnt, bounce_iov, 1, num_blocks, &ctx, NULL);
819 	CU_ASSERT(rc == 0);
820 
821 	rc = ut_data_pattern_verify(iovs, iovcnt, block_size - md_size, 0, num_blocks);
822 	CU_ASSERT(rc == 0);
823 }
824 
825 static void
826 dif_copy_sec_512_md_8_prchk_0_single_iov(void)
827 {
828 	struct iovec iov, bounce_iov;
829 
830 	_iov_alloc_buf(&iov, 512 * 4);
831 	_iov_alloc_buf(&bounce_iov, (512 + 8) * 4);
832 
833 	dif_copy_gen_and_verify(&iov, 1, &bounce_iov, 512 + 8, 8, 4,
834 				false, SPDK_DIF_TYPE1, 0, 0, 0, 0);
835 	dif_copy_gen_and_verify(&iov, 1, &bounce_iov, 512 + 8, 8, 4,
836 				true, SPDK_DIF_TYPE1, 0, 0, 0, 0);
837 
838 	_iov_free_buf(&iov);
839 	_iov_free_buf(&bounce_iov);
840 }
841 
842 static void
843 dif_copy_sec_512_md_8_prchk_0_1_2_4_multi_iovs(void)
844 {
845 	struct iovec iovs[4], bounce_iov;
846 	int i, num_blocks;
847 
848 	num_blocks = 0;
849 
850 	for (i = 0; i < 4; i++) {
851 		_iov_alloc_buf(&iovs[i], 512 * (i + 1));
852 		num_blocks += i + 1;
853 	}
854 
855 	_iov_alloc_buf(&bounce_iov, (512 + 8) * num_blocks);
856 
857 	dif_copy_gen_and_verify(iovs, 4, &bounce_iov, 512 + 8, 8, num_blocks,
858 				false, SPDK_DIF_TYPE1, 0, 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_GUARD_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_APPTAG_CHECK, 22, 0xFFFF, 0x22);
865 
866 	dif_copy_gen_and_verify(iovs, 4, &bounce_iov, 512 + 8, 8, num_blocks,
867 				false, SPDK_DIF_TYPE1, SPDK_DIF_FLAGS_REFTAG_CHECK, 22, 0xFFFF, 0x22);
868 
869 	for (i = 0; i < 4; i++) {
870 		_iov_free_buf(&iovs[i]);
871 	}
872 	_iov_free_buf(&bounce_iov);
873 }
874 
875 static void
876 dif_copy_sec_4096_md_128_prchk_7_multi_iovs(void)
877 {
878 	struct iovec iovs[4], bounce_iov;
879 	uint32_t dif_flags;
880 	int i, num_blocks;
881 
882 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
883 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
884 
885 	num_blocks = 0;
886 
887 	for (i = 0; i < 4; i++) {
888 		_iov_alloc_buf(&iovs[i], 4096 * (i + 1));
889 		num_blocks += i + 1;
890 	}
891 
892 	_iov_alloc_buf(&bounce_iov, (4096 + 128) * num_blocks);
893 
894 	dif_copy_gen_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128, num_blocks,
895 				false, SPDK_DIF_TYPE1, dif_flags, 22, 0xFFFF, 0x22);
896 	dif_copy_gen_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128, num_blocks,
897 				true, SPDK_DIF_TYPE1, dif_flags, 22, 0xFFFF, 0x22);
898 
899 	for (i = 0; i < 4; i++) {
900 		_iov_free_buf(&iovs[i]);
901 	}
902 	_iov_free_buf(&bounce_iov);
903 }
904 
905 static void
906 dif_copy_sec_512_md_8_prchk_7_multi_iovs_split_data(void)
907 {
908 	struct iovec iovs[2], bounce_iov;
909 	uint32_t dif_flags;
910 
911 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
912 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
913 
914 	_iov_alloc_buf(&iovs[0], 256);
915 	_iov_alloc_buf(&iovs[1], 256);
916 
917 	_iov_alloc_buf(&bounce_iov, 512 + 8);
918 
919 	dif_copy_gen_and_verify(iovs, 2, &bounce_iov, 512 + 8, 8, 1,
920 				false, SPDK_DIF_TYPE1, dif_flags, 22, 0xFFFF, 0x22);
921 
922 	_iov_free_buf(&iovs[0]);
923 	_iov_free_buf(&iovs[1]);
924 	_iov_free_buf(&bounce_iov);
925 }
926 
927 static void
928 dif_copy_sec_512_md_8_prchk_7_multi_iovs_complex_splits(void)
929 {
930 	struct iovec iovs[6], bounce_iov;
931 	uint32_t dif_flags;
932 	int i;
933 
934 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
935 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
936 
937 	/* data[0][255:0] */
938 	_iov_alloc_buf(&iovs[0], 256);
939 
940 	/* data[0][511:256], data[1][255:0] */
941 	_iov_alloc_buf(&iovs[1], 256 + 256);
942 
943 	/* data[1][382:256] */
944 	_iov_alloc_buf(&iovs[2], 128);
945 
946 	/* data[1][383] */
947 	_iov_alloc_buf(&iovs[3], 1);
948 
949 	/* data[1][510:384] */
950 	_iov_alloc_buf(&iovs[4], 126);
951 
952 	/* data[1][511], data[2][511:0], data[3][511:0] */
953 	_iov_alloc_buf(&iovs[5], 1 + 512 * 2);
954 
955 	_iov_alloc_buf(&bounce_iov, (512 + 8) * 4);
956 
957 	dif_copy_gen_and_verify(iovs, 6, &bounce_iov, 512 + 8, 8, 4,
958 				true, SPDK_DIF_TYPE1, dif_flags, 22, 0xFFFF, 0x22);
959 
960 	for (i = 0; i < 6; i++) {
961 		_iov_free_buf(&iovs[i]);
962 	}
963 	_iov_free_buf(&bounce_iov);
964 }
965 
966 static void
967 _dif_copy_inject_error_and_verify(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov,
968 				  uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
969 				  uint32_t inject_flags, bool dif_loc)
970 {
971 	struct spdk_dif_ctx ctx = {};
972 	struct spdk_dif_error err_blk = {};
973 	uint32_t inject_offset = 0, dif_flags;
974 	int rc;
975 	struct spdk_dif_ctx_init_ext_opts dif_opts;
976 
977 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
978 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
979 
980 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size - md_size, 0, num_blocks);
981 	CU_ASSERT(rc == 0);
982 
983 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
984 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
985 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc, SPDK_DIF_TYPE1, dif_flags,
986 			       88, 0xFFFF, 0x88, 0, GUARD_SEED, &dif_opts);
987 	SPDK_CU_ASSERT_FATAL(rc == 0);
988 
989 	rc = spdk_dif_generate_copy(iovs, iovcnt, bounce_iov, 1, num_blocks, &ctx);
990 	CU_ASSERT(rc == 0);
991 
992 	rc = spdk_dif_inject_error(bounce_iov, 1, num_blocks, &ctx, inject_flags, &inject_offset);
993 	CU_ASSERT(rc == 0);
994 
995 	rc = spdk_dif_verify_copy(iovs, iovcnt, bounce_iov, 1, num_blocks, &ctx, &err_blk);
996 	CU_ASSERT(rc != 0);
997 	if (inject_flags == SPDK_DIF_DATA_ERROR) {
998 		CU_ASSERT(SPDK_DIF_GUARD_ERROR == err_blk.err_type);
999 	} else {
1000 		CU_ASSERT(inject_flags == err_blk.err_type);
1001 	}
1002 	CU_ASSERT(inject_offset == err_blk.err_offset);
1003 }
1004 
1005 static void
1006 dif_copy_inject_error_and_verify(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov,
1007 				 uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
1008 				 uint32_t inject_flags)
1009 {
1010 	/* The case that DIF is contained in the first 8 bytes of metadata. */
1011 	_dif_copy_inject_error_and_verify(iovs, iovcnt, bounce_iov,
1012 					  block_size, md_size, num_blocks,
1013 					  inject_flags, true);
1014 
1015 	/* The case that DIF is contained in the last 8 bytes of metadata. */
1016 	_dif_copy_inject_error_and_verify(iovs, iovcnt, bounce_iov,
1017 					  block_size, md_size, num_blocks,
1018 					  inject_flags, false);
1019 }
1020 
1021 static void
1022 dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test(void)
1023 {
1024 	struct iovec iovs[4], bounce_iov;
1025 	int i, num_blocks;
1026 
1027 	num_blocks = 0;
1028 
1029 	for (i = 0; i < 4; i++) {
1030 		_iov_alloc_buf(&iovs[i], 4096 * (i + 1));
1031 		num_blocks += i + 1;
1032 	}
1033 
1034 	_iov_alloc_buf(&bounce_iov, (4096 + 128) * num_blocks);
1035 
1036 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1037 					 num_blocks, SPDK_DIF_GUARD_ERROR);
1038 
1039 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1040 					 num_blocks, SPDK_DIF_APPTAG_ERROR);
1041 
1042 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1043 					 num_blocks, SPDK_DIF_REFTAG_ERROR);
1044 
1045 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1046 					 num_blocks, SPDK_DIF_DATA_ERROR);
1047 
1048 	for (i = 0; i < 4; i++) {
1049 		_iov_free_buf(&iovs[i]);
1050 	}
1051 	_iov_free_buf(&bounce_iov);
1052 }
1053 
1054 static void
1055 dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test(void)
1056 {
1057 	struct iovec iovs[4], bounce_iov;
1058 	int i;
1059 
1060 	_iov_alloc_buf(&iovs[0], 2048);
1061 	_iov_alloc_buf(&iovs[1], 2048);
1062 	_iov_alloc_buf(&iovs[2], 1);
1063 	_iov_alloc_buf(&iovs[3], 4095);
1064 
1065 	_iov_alloc_buf(&bounce_iov, (4096 + 128) * 2);
1066 
1067 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1068 					 2, SPDK_DIF_GUARD_ERROR);
1069 
1070 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1071 					 2, SPDK_DIF_APPTAG_ERROR);
1072 
1073 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1074 					 2, SPDK_DIF_REFTAG_ERROR);
1075 
1076 	dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128,
1077 					 2, SPDK_DIF_DATA_ERROR);
1078 
1079 	for (i = 0; i < 4; i++) {
1080 		_iov_free_buf(&iovs[i]);
1081 	}
1082 	_iov_free_buf(&bounce_iov);
1083 }
1084 
1085 static void
1086 dix_sec_512_md_0_error(void)
1087 {
1088 	struct spdk_dif_ctx ctx;
1089 	int rc;
1090 	struct spdk_dif_ctx_init_ext_opts dif_opts;
1091 
1092 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
1093 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
1094 	rc = spdk_dif_ctx_init(&ctx, 512, 0, false, false, SPDK_DIF_TYPE1,
1095 			       0, 0, 0, 0, 0, 0, &dif_opts);
1096 	CU_ASSERT(rc != 0);
1097 }
1098 
1099 static void
1100 dix_generate_and_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1101 			uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
1102 			bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
1103 			uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag)
1104 {
1105 	struct spdk_dif_ctx ctx;
1106 	int rc;
1107 	struct spdk_dif_ctx_init_ext_opts dif_opts;
1108 
1109 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, 0, num_blocks);
1110 	CU_ASSERT(rc == 0);
1111 
1112 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
1113 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
1114 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, false, dif_loc, dif_type, dif_flags,
1115 			       init_ref_tag, apptag_mask, app_tag, 0, GUARD_SEED, &dif_opts);
1116 	CU_ASSERT(rc == 0);
1117 
1118 	rc = spdk_dix_generate(iovs, iovcnt, md_iov, num_blocks, &ctx);
1119 	CU_ASSERT(rc == 0);
1120 
1121 	rc = spdk_dix_verify(iovs, iovcnt, md_iov, num_blocks, &ctx, NULL);
1122 	CU_ASSERT(rc == 0);
1123 
1124 	rc = ut_data_pattern_verify(iovs, iovcnt, block_size, 0, num_blocks);
1125 	CU_ASSERT(rc == 0);
1126 }
1127 
1128 static void
1129 dix_sec_512_md_8_prchk_0_single_iov(void)
1130 {
1131 	struct iovec iov, md_iov;
1132 
1133 	_iov_alloc_buf(&iov, 512 * 4);
1134 	_iov_alloc_buf(&md_iov, 8 * 4);
1135 
1136 	dix_generate_and_verify(&iov, 1, &md_iov, 512, 8, 4, false, SPDK_DIF_TYPE1, 0, 0, 0, 0);
1137 	dix_generate_and_verify(&iov, 1, &md_iov, 512, 8, 4, true, SPDK_DIF_TYPE1, 0, 0, 0, 0);
1138 
1139 	_iov_free_buf(&iov);
1140 	_iov_free_buf(&md_iov);
1141 }
1142 
1143 static void
1144 dix_sec_512_md_8_prchk_0_1_2_4_multi_iovs(void)
1145 {
1146 	struct iovec iovs[4], md_iov;
1147 	int i, num_blocks;
1148 
1149 	num_blocks = 0;
1150 
1151 	for (i = 0; i < 4; i++) {
1152 		_iov_alloc_buf(&iovs[i], 512 * (i + 1));
1153 		num_blocks += i + 1;
1154 	}
1155 	_iov_alloc_buf(&md_iov, 8 * num_blocks);
1156 
1157 	dix_generate_and_verify(iovs, 4, &md_iov, 512, 8, num_blocks, false, SPDK_DIF_TYPE1,
1158 				0, 22, 0xFFFF, 0x22);
1159 
1160 	dix_generate_and_verify(iovs, 4, &md_iov, 512, 8, num_blocks, false, SPDK_DIF_TYPE1,
1161 				SPDK_DIF_FLAGS_GUARD_CHECK, 22, 0xFFFF, 0x22);
1162 
1163 	dix_generate_and_verify(iovs, 4, &md_iov, 512, 8, num_blocks, false, SPDK_DIF_TYPE1,
1164 				SPDK_DIF_FLAGS_APPTAG_CHECK, 22, 0xFFFF, 0x22);
1165 
1166 	dix_generate_and_verify(iovs, 4, &md_iov, 512, 8, num_blocks, false, SPDK_DIF_TYPE1,
1167 				SPDK_DIF_FLAGS_REFTAG_CHECK, 22, 0xFFFF, 0x22);
1168 
1169 	for (i = 0; i < 4; i++) {
1170 		_iov_free_buf(&iovs[i]);
1171 	}
1172 	_iov_free_buf(&md_iov);
1173 }
1174 
1175 static void
1176 dix_sec_4096_md_128_prchk_7_multi_iovs(void)
1177 {
1178 	struct iovec iovs[4], md_iov;
1179 	uint32_t dif_flags;
1180 	int i, num_blocks;
1181 
1182 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
1183 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
1184 
1185 	num_blocks = 0;
1186 
1187 	for (i = 0; i < 4; i++) {
1188 		_iov_alloc_buf(&iovs[i], 4096 * (i + 1));
1189 		num_blocks += i + 1;
1190 	}
1191 	_iov_alloc_buf(&md_iov, 128 * num_blocks);
1192 
1193 	dix_generate_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, false, SPDK_DIF_TYPE1,
1194 				dif_flags, 22, 0xFFFF, 0x22);
1195 	dix_generate_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, true, SPDK_DIF_TYPE1,
1196 				dif_flags, 22, 0xFFFF, 0x22);
1197 
1198 	for (i = 0; i < 4; i++) {
1199 		_iov_free_buf(&iovs[i]);
1200 	}
1201 	_iov_free_buf(&md_iov);
1202 }
1203 
1204 static void
1205 dix_sec_512_md_8_prchk_7_multi_iovs_split_data(void)
1206 {
1207 	struct iovec iovs[2], md_iov;
1208 	uint32_t dif_flags;
1209 
1210 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
1211 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
1212 
1213 	_iov_alloc_buf(&iovs[0], 256);
1214 	_iov_alloc_buf(&iovs[1], 256);
1215 	_iov_alloc_buf(&md_iov, 8);
1216 
1217 	dix_generate_and_verify(iovs, 2, &md_iov, 512, 8, 1, false, SPDK_DIF_TYPE1,
1218 				dif_flags, 22, 0xFFFF, 0x22);
1219 
1220 	_iov_free_buf(&iovs[0]);
1221 	_iov_free_buf(&iovs[1]);
1222 	_iov_free_buf(&md_iov);
1223 }
1224 
1225 static void
1226 dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits(void)
1227 {
1228 	struct iovec iovs[6], md_iov;
1229 	uint32_t dif_flags;
1230 	int i;
1231 
1232 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
1233 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
1234 
1235 	/* data[0][255:0] */
1236 	_iov_alloc_buf(&iovs[0], 256);
1237 
1238 	/* data[0][511:256], data[1][255:0] */
1239 	_iov_alloc_buf(&iovs[1], 256 + 256);
1240 
1241 	/* data[1][382:256] */
1242 	_iov_alloc_buf(&iovs[2], 128);
1243 
1244 	/* data[1][383] */
1245 	_iov_alloc_buf(&iovs[3], 1);
1246 
1247 	/* data[1][510:384] */
1248 	_iov_alloc_buf(&iovs[4], 126);
1249 
1250 	/* data[1][511], data[2][511:0], data[3][511:0] */
1251 	_iov_alloc_buf(&iovs[5], 1 + 512 * 2);
1252 
1253 	_iov_alloc_buf(&md_iov, 8 * 4);
1254 
1255 	dix_generate_and_verify(iovs, 6, &md_iov, 512, 8, 4, false, SPDK_DIF_TYPE1,
1256 				dif_flags, 22, 0xFFFF, 0x22);
1257 
1258 	for (i = 0; i < 6; i++) {
1259 		_iov_free_buf(&iovs[i]);
1260 	}
1261 	_iov_free_buf(&md_iov);
1262 }
1263 
1264 static void
1265 _dix_inject_error_and_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1266 			     uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
1267 			     uint32_t inject_flags, bool dif_loc)
1268 {
1269 	struct spdk_dif_ctx ctx = {};
1270 	struct spdk_dif_error err_blk = {};
1271 	uint32_t inject_offset = 0, dif_flags;
1272 	int rc;
1273 	struct spdk_dif_ctx_init_ext_opts dif_opts;
1274 
1275 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
1276 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
1277 
1278 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, 0, num_blocks);
1279 	CU_ASSERT(rc == 0);
1280 
1281 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
1282 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
1283 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, false, dif_loc, SPDK_DIF_TYPE1, dif_flags,
1284 			       88, 0xFFFF, 0x88, 0, GUARD_SEED, &dif_opts);
1285 	CU_ASSERT(rc == 0);
1286 
1287 	rc = spdk_dix_generate(iovs, iovcnt, md_iov, num_blocks, &ctx);
1288 	CU_ASSERT(rc == 0);
1289 
1290 	rc = spdk_dix_inject_error(iovs, iovcnt, md_iov, num_blocks, &ctx, inject_flags, &inject_offset);
1291 	CU_ASSERT(rc == 0);
1292 
1293 	rc = spdk_dix_verify(iovs, iovcnt, md_iov, num_blocks, &ctx, &err_blk);
1294 	CU_ASSERT(rc != 0);
1295 
1296 	if (inject_flags == SPDK_DIF_DATA_ERROR) {
1297 		CU_ASSERT(SPDK_DIF_GUARD_ERROR == err_blk.err_type);
1298 	} else {
1299 		CU_ASSERT(inject_flags == err_blk.err_type);
1300 	}
1301 	CU_ASSERT(inject_offset == err_blk.err_offset);
1302 }
1303 
1304 static void
1305 dix_inject_error_and_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
1306 			    uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
1307 			    uint32_t inject_flags)
1308 {
1309 	/* The case that DIF is contained in the first 8 bytes of metadata. */
1310 	_dix_inject_error_and_verify(iovs, iovcnt, md_iov, block_size, md_size, num_blocks,
1311 				     inject_flags, true);
1312 
1313 	/* The case that DIF is contained in the last 8 bytes of metadata. */
1314 	_dix_inject_error_and_verify(iovs, iovcnt, md_iov, block_size, md_size, num_blocks,
1315 				     inject_flags, false);
1316 }
1317 
1318 static void
1319 dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test(void)
1320 {
1321 	struct iovec iovs[4], md_iov;
1322 	int i, num_blocks;
1323 
1324 	num_blocks = 0;
1325 
1326 	for (i = 0; i < 4; i++) {
1327 		_iov_alloc_buf(&iovs[i], 4096 * (i + 1));
1328 		num_blocks += i + 1;
1329 	}
1330 
1331 	_iov_alloc_buf(&md_iov, 128 * num_blocks);
1332 
1333 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, SPDK_DIF_GUARD_ERROR);
1334 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, SPDK_DIF_APPTAG_ERROR);
1335 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, SPDK_DIF_REFTAG_ERROR);
1336 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, SPDK_DIF_DATA_ERROR);
1337 
1338 	for (i = 0; i < 4; i++) {
1339 		_iov_free_buf(&iovs[i]);
1340 	}
1341 	_iov_free_buf(&md_iov);
1342 }
1343 
1344 static void
1345 dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test(void)
1346 {
1347 	struct iovec iovs[4], md_iov;
1348 	int i;
1349 
1350 	_iov_alloc_buf(&iovs[0], 2048);
1351 	_iov_alloc_buf(&iovs[1], 2048);
1352 	_iov_alloc_buf(&iovs[2], 1);
1353 	_iov_alloc_buf(&iovs[3], 4095);
1354 
1355 	_iov_alloc_buf(&md_iov, 128 * 2);
1356 
1357 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, 2, SPDK_DIF_GUARD_ERROR);
1358 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, 2, SPDK_DIF_APPTAG_ERROR);
1359 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, 2, SPDK_DIF_REFTAG_ERROR);
1360 	dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, 2, SPDK_DIF_DATA_ERROR);
1361 
1362 	for (i = 0; i < 4; i++) {
1363 		_iov_free_buf(&iovs[i]);
1364 	}
1365 	_iov_free_buf(&md_iov);
1366 }
1367 
1368 static int
1369 ut_readv(uint32_t read_base, uint32_t read_len, struct iovec *iovs, int iovcnt)
1370 {
1371 	int i;
1372 	uint32_t j, offset;
1373 	uint8_t *buf;
1374 
1375 	offset = 0;
1376 	for (i = 0; i < iovcnt; i++) {
1377 		buf = iovs[i].iov_base;
1378 		for (j = 0; j < iovs[i].iov_len; j++, offset++) {
1379 			if (offset >= read_len) {
1380 				return offset;
1381 			}
1382 			buf[j] = DATA_PATTERN(read_base + offset);
1383 		}
1384 	}
1385 
1386 	return offset;
1387 }
1388 
1389 static void
1390 set_md_interleave_iovs_test(void)
1391 {
1392 	struct spdk_dif_ctx ctx = {};
1393 	struct spdk_dif_error err_blk = {};
1394 	struct iovec iov1, iov2, dif_iovs[4] = {};
1395 	uint32_t dif_check_flags, data_len, read_len, data_offset, mapped_len = 0;
1396 	uint8_t *buf1, *buf2;
1397 	int rc;
1398 	struct spdk_dif_ctx_init_ext_opts dif_opts;
1399 
1400 	dif_check_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
1401 			  SPDK_DIF_FLAGS_REFTAG_CHECK;
1402 
1403 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
1404 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
1405 	rc = spdk_dif_ctx_init(&ctx, 4096 + 128, 128, true, false, SPDK_DIF_TYPE1,
1406 			       dif_check_flags, 22, 0xFFFF, 0x22, 0, GUARD_SEED, &dif_opts);
1407 	CU_ASSERT(rc == 0);
1408 
1409 	/* The first data buffer:
1410 	 * - Create iovec array to Leave a space for metadata for each block
1411 	 * - Split vectored read and so creating iovec array is done before every vectored read.
1412 	 */
1413 	buf1 = calloc(1, (4096 + 128) * 4);
1414 	SPDK_CU_ASSERT_FATAL(buf1 != NULL);
1415 	_iov_set_buf(&iov1, buf1, (4096 + 128) * 4);
1416 
1417 	data_offset = 0;
1418 	data_len = 4096 * 4;
1419 
1420 	/* 1st read */
1421 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 4, &iov1, 1,
1422 					     data_offset, data_len, &mapped_len, &ctx);
1423 	CU_ASSERT(rc == 4);
1424 	CU_ASSERT(mapped_len == 4096 * 4);
1425 	CU_ASSERT(_iov_check(&dif_iovs[0], buf1, 4096) == true);
1426 	CU_ASSERT(_iov_check(&dif_iovs[1], buf1 + 4096 + 128, 4096) == true);
1427 	CU_ASSERT(_iov_check(&dif_iovs[2], buf1 + (4096 + 128) * 2, 4096) == true);
1428 	CU_ASSERT(_iov_check(&dif_iovs[3], buf1 + (4096 + 128) * 3, 4096) == true);
1429 
1430 	read_len = ut_readv(data_offset, 1024, dif_iovs, 4);
1431 	CU_ASSERT(read_len == 1024);
1432 
1433 	rc = spdk_dif_generate_stream(&iov1, 1, data_offset, read_len, &ctx);
1434 	CU_ASSERT(rc == 0);
1435 
1436 	data_offset += read_len;
1437 	data_len -= read_len;
1438 
1439 	/* 2nd read */
1440 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 4, &iov1, 1,
1441 					     data_offset, data_len, &mapped_len, &ctx);
1442 	CU_ASSERT(rc == 4);
1443 	CU_ASSERT(mapped_len == 3072 + 4096 * 3);
1444 	CU_ASSERT(_iov_check(&dif_iovs[0], buf1 + 1024, 3072) == true);
1445 	CU_ASSERT(_iov_check(&dif_iovs[1], buf1 + 4096 + 128, 4096) == true);
1446 	CU_ASSERT(_iov_check(&dif_iovs[2], buf1 + (4096 + 128) * 2, 4096) == true);
1447 	CU_ASSERT(_iov_check(&dif_iovs[3], buf1 + (4096 + 128) * 3, 4096) == true);
1448 
1449 	read_len = ut_readv(data_offset, 3071, dif_iovs, 4);
1450 	CU_ASSERT(read_len == 3071);
1451 
1452 	rc = spdk_dif_generate_stream(&iov1, 1, data_offset, read_len, &ctx);
1453 	CU_ASSERT(rc == 0);
1454 
1455 	data_offset += read_len;
1456 	data_len -= read_len;
1457 
1458 	/* 3rd read */
1459 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 4, &iov1, 1,
1460 					     data_offset, data_len, &mapped_len, &ctx);
1461 	CU_ASSERT(rc == 4);
1462 	CU_ASSERT(mapped_len == 1 + 4096 * 3);
1463 	CU_ASSERT(_iov_check(&dif_iovs[0], buf1 + 4095, 1) == true);
1464 	CU_ASSERT(_iov_check(&dif_iovs[1], buf1 + 4096 + 128, 4096) == true);
1465 	CU_ASSERT(_iov_check(&dif_iovs[2], buf1 + (4096 + 128) * 2, 4096) == true);
1466 	CU_ASSERT(_iov_check(&dif_iovs[3], buf1 + (4096 + 128) * 3, 4096) == true);
1467 
1468 	read_len = ut_readv(data_offset, 1 + 4096 * 2 + 512, dif_iovs, 4);
1469 	CU_ASSERT(read_len == 1 + 4096 * 2 + 512);
1470 
1471 	rc = spdk_dif_generate_stream(&iov1, 1, data_offset, read_len, &ctx);
1472 	CU_ASSERT(rc == 0);
1473 
1474 	data_offset += read_len;
1475 	data_len -= read_len;
1476 
1477 	/* 4th read */
1478 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 4, &iov1, 1,
1479 					     data_offset, data_len, &mapped_len, &ctx);
1480 	CU_ASSERT(rc == 1);
1481 	CU_ASSERT(mapped_len == 3584);
1482 	CU_ASSERT(_iov_check(&dif_iovs[0], buf1 + (4096 + 128) * 3 + 512, 3584) == true);
1483 
1484 	read_len = ut_readv(data_offset, 3584, dif_iovs, 1);
1485 	CU_ASSERT(read_len == 3584);
1486 
1487 	rc = spdk_dif_generate_stream(&iov1, 1, data_offset, read_len, &ctx);
1488 	CU_ASSERT(rc == 0);
1489 
1490 	data_offset += read_len;
1491 	CU_ASSERT(data_offset == 4096 * 4);
1492 	data_len -= read_len;
1493 	CU_ASSERT(data_len == 0);
1494 
1495 	/* The second data buffer:
1496 	 * - Set data pattern with a space for metadata for each block.
1497 	 */
1498 	buf2 = calloc(1, (4096 + 128) * 4);
1499 	SPDK_CU_ASSERT_FATAL(buf2 != NULL);
1500 	_iov_set_buf(&iov2, buf2, (4096 + 128) * 4);
1501 
1502 	rc = ut_data_pattern_generate(&iov2, 1, 4096 + 128, 128, 4);
1503 	CU_ASSERT(rc == 0);
1504 	rc = spdk_dif_generate(&iov2, 1, 4, &ctx);
1505 	CU_ASSERT(rc == 0);
1506 
1507 	rc = spdk_dif_verify(&iov1, 1, 4, &ctx, &err_blk);
1508 	CU_ASSERT(rc == 0);
1509 
1510 	rc = spdk_dif_verify(&iov2, 1, 4, &ctx, &err_blk);
1511 	CU_ASSERT(rc == 0);
1512 
1513 	/* Compare the first and the second data buffer by byte. */
1514 	rc = memcmp(buf1, buf2, (4096 + 128) * 4);
1515 	CU_ASSERT(rc == 0);
1516 
1517 	free(buf1);
1518 	free(buf2);
1519 }
1520 
1521 static void
1522 set_md_interleave_iovs_split_test(void)
1523 {
1524 	struct spdk_dif_ctx ctx = {};
1525 	struct spdk_dif_error err_blk = {};
1526 	struct iovec iovs1[7], iovs2[7], dif_iovs[8] = {};
1527 	uint32_t dif_check_flags, data_len, read_len, data_offset, mapped_len = 0;
1528 	int rc, i;
1529 	struct spdk_dif_ctx_init_ext_opts dif_opts;
1530 
1531 	dif_check_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
1532 			  SPDK_DIF_FLAGS_REFTAG_CHECK;
1533 
1534 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
1535 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
1536 	rc = spdk_dif_ctx_init(&ctx, 512 + 8, 8, true, false, SPDK_DIF_TYPE1,
1537 			       dif_check_flags, 22, 0xFFFF, 0x22, 0, GUARD_SEED, &dif_opts);
1538 	CU_ASSERT(rc == 0);
1539 
1540 	/* The first SGL data buffer:
1541 	 * - Create iovec array to leave a space for metadata for each block
1542 	 * - Split vectored read and so creating iovec array is done before every vectored read.
1543 	 */
1544 	_iov_alloc_buf(&iovs1[0], 512 + 8 + 128);
1545 	_iov_alloc_buf(&iovs1[1], 128);
1546 	_iov_alloc_buf(&iovs1[2], 256 + 8);
1547 	_iov_alloc_buf(&iovs1[3], 100);
1548 	_iov_alloc_buf(&iovs1[4], 412 + 5);
1549 	_iov_alloc_buf(&iovs1[5], 3 + 300);
1550 	_iov_alloc_buf(&iovs1[6], 212 + 8);
1551 
1552 	data_offset = 0;
1553 	data_len = 512 * 4;
1554 
1555 	/* 1st read */
1556 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 8, iovs1, 7,
1557 					     data_offset, data_len, &mapped_len, &ctx);
1558 	CU_ASSERT(rc == 8);
1559 	CU_ASSERT(mapped_len == 512 * 4);
1560 	CU_ASSERT(_iov_check(&dif_iovs[0], iovs1[0].iov_base, 512) == true);
1561 	CU_ASSERT(_iov_check(&dif_iovs[1], iovs1[0].iov_base + 512 + 8, 128) == true);
1562 	CU_ASSERT(_iov_check(&dif_iovs[2], iovs1[1].iov_base, 128) == true);
1563 	CU_ASSERT(_iov_check(&dif_iovs[3], iovs1[2].iov_base, 256) == true);
1564 	CU_ASSERT(_iov_check(&dif_iovs[4], iovs1[3].iov_base, 100) == true);
1565 	CU_ASSERT(_iov_check(&dif_iovs[5], iovs1[4].iov_base, 412) == true);
1566 	CU_ASSERT(_iov_check(&dif_iovs[6], iovs1[5].iov_base + 3, 300) == true);
1567 	CU_ASSERT(_iov_check(&dif_iovs[7], iovs1[6].iov_base, 212) == true);
1568 
1569 	read_len = ut_readv(data_offset, 128, dif_iovs, 8);
1570 	CU_ASSERT(read_len == 128);
1571 
1572 	rc = spdk_dif_generate_stream(iovs1, 7, data_offset, read_len, &ctx);
1573 	CU_ASSERT(rc == 0);
1574 
1575 	data_offset += read_len;
1576 	data_len -= read_len;
1577 
1578 	/* 2nd read */
1579 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 8, iovs1, 7,
1580 					     data_offset, data_len, &mapped_len, &ctx);
1581 	CU_ASSERT(rc == 8);
1582 	CU_ASSERT(mapped_len == 384 + 512 * 3);
1583 	CU_ASSERT(_iov_check(&dif_iovs[0], iovs1[0].iov_base + 128, 384) == true);
1584 	CU_ASSERT(_iov_check(&dif_iovs[1], iovs1[0].iov_base + 512 + 8, 128) == true);
1585 	CU_ASSERT(_iov_check(&dif_iovs[2], iovs1[1].iov_base, 128) == true);
1586 	CU_ASSERT(_iov_check(&dif_iovs[3], iovs1[2].iov_base, 256) == true);
1587 	CU_ASSERT(_iov_check(&dif_iovs[4], iovs1[3].iov_base, 100) == true);
1588 	CU_ASSERT(_iov_check(&dif_iovs[5], iovs1[4].iov_base, 412) == true);
1589 	CU_ASSERT(_iov_check(&dif_iovs[6], iovs1[5].iov_base + 3, 300) == true);
1590 	CU_ASSERT(_iov_check(&dif_iovs[7], iovs1[6].iov_base, 212) == true);
1591 
1592 	read_len = ut_readv(data_offset, 383, dif_iovs, 8);
1593 	CU_ASSERT(read_len == 383);
1594 
1595 	rc = spdk_dif_generate_stream(iovs1, 7, data_offset, read_len, &ctx);
1596 	CU_ASSERT(rc == 0);
1597 
1598 	data_offset += read_len;
1599 	data_len -= read_len;
1600 
1601 	/* 3rd read */
1602 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 8, iovs1, 7,
1603 					     data_offset, data_len, &mapped_len, &ctx);
1604 	CU_ASSERT(rc == 8);
1605 	CU_ASSERT(mapped_len == 1 + 512 * 3);
1606 	CU_ASSERT(_iov_check(&dif_iovs[0], iovs1[0].iov_base + 511, 1) == true);
1607 	CU_ASSERT(_iov_check(&dif_iovs[1], iovs1[0].iov_base + 512 + 8, 128) == true);
1608 	CU_ASSERT(_iov_check(&dif_iovs[2], iovs1[1].iov_base, 128) == true);
1609 	CU_ASSERT(_iov_check(&dif_iovs[3], iovs1[2].iov_base, 256) == true);
1610 	CU_ASSERT(_iov_check(&dif_iovs[4], iovs1[3].iov_base, 100) == true);
1611 	CU_ASSERT(_iov_check(&dif_iovs[5], iovs1[4].iov_base, 412) == true);
1612 	CU_ASSERT(_iov_check(&dif_iovs[6], iovs1[5].iov_base + 3, 300) == true);
1613 	CU_ASSERT(_iov_check(&dif_iovs[7], iovs1[6].iov_base, 212) == true);
1614 
1615 	read_len = ut_readv(data_offset, 1 + 512 * 2 + 128, dif_iovs, 8);
1616 	CU_ASSERT(read_len == 1 + 512 * 2 + 128);
1617 
1618 	rc = spdk_dif_generate_stream(iovs1, 7, data_offset, read_len, &ctx);
1619 	CU_ASSERT(rc == 0);
1620 
1621 	data_offset += read_len;
1622 	data_len -= read_len;
1623 
1624 	/* 4th read */
1625 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 8, iovs1, 7,
1626 					     data_offset, data_len, &mapped_len, &ctx);
1627 	CU_ASSERT(rc == 2);
1628 	CU_ASSERT(mapped_len == 384);
1629 	CU_ASSERT(_iov_check(&dif_iovs[0], iovs1[5].iov_base + 3 + 128, 172) == true);
1630 	CU_ASSERT(_iov_check(&dif_iovs[1], iovs1[6].iov_base, 212) == true);
1631 
1632 	read_len = ut_readv(data_offset, 384, dif_iovs, 8);
1633 	CU_ASSERT(read_len == 384);
1634 
1635 	rc = spdk_dif_generate_stream(iovs1, 7, data_offset, read_len, &ctx);
1636 	CU_ASSERT(rc == 0);
1637 
1638 	data_offset += read_len;
1639 	CU_ASSERT(data_offset == 512 * 4);
1640 	data_len -= read_len;
1641 	CU_ASSERT(data_len == 0);
1642 
1643 	/* The second SGL data buffer:
1644 	 * - Set data pattern with a space for metadata for each block.
1645 	 */
1646 	_iov_alloc_buf(&iovs2[0], 512 + 8 + 128);
1647 	_iov_alloc_buf(&iovs2[1], 128);
1648 	_iov_alloc_buf(&iovs2[2], 256 + 8);
1649 	_iov_alloc_buf(&iovs2[3], 100);
1650 	_iov_alloc_buf(&iovs2[4], 412 + 5);
1651 	_iov_alloc_buf(&iovs2[5], 3 + 300);
1652 	_iov_alloc_buf(&iovs2[6], 212 + 8);
1653 
1654 	rc = ut_data_pattern_generate(iovs2, 7, 512 + 8, 8, 4);
1655 	CU_ASSERT(rc == 0);
1656 	rc = spdk_dif_generate(iovs2, 7, 4, &ctx);
1657 	CU_ASSERT(rc == 0);
1658 
1659 	rc = spdk_dif_verify(iovs1, 7, 4, &ctx, &err_blk);
1660 	CU_ASSERT(rc == 0);
1661 
1662 	rc = spdk_dif_verify(iovs2, 7, 4, &ctx, &err_blk);
1663 	CU_ASSERT(rc == 0);
1664 
1665 	/* Compare the first and the second SGL data buffer by byte. */
1666 	for (i = 0; i < 7; i++) {
1667 		rc = memcmp(iovs1[i].iov_base, iovs2[i].iov_base,
1668 			    iovs1[i].iov_len);
1669 		CU_ASSERT(rc == 0);
1670 	}
1671 
1672 	for (i = 0; i < 7; i++) {
1673 		_iov_free_buf(&iovs1[i]);
1674 		_iov_free_buf(&iovs2[i]);
1675 	}
1676 }
1677 
1678 static void
1679 dif_generate_stream_test(void)
1680 {
1681 	struct iovec iov;
1682 	struct spdk_dif_ctx ctx;
1683 	struct spdk_dif_error err_blk;
1684 	uint32_t dif_flags;
1685 	int rc;
1686 	struct spdk_dif_ctx_init_ext_opts dif_opts;
1687 
1688 	_iov_alloc_buf(&iov, (512 + 8) * 5);
1689 
1690 	rc = ut_data_pattern_generate(&iov, 1, 512 + 8, 8, 5);
1691 	CU_ASSERT(rc == 0);
1692 
1693 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
1694 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
1695 
1696 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
1697 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
1698 	rc = spdk_dif_ctx_init(&ctx, 512 + 8, 8, true, false, SPDK_DIF_TYPE1, dif_flags,
1699 			       22, 0xFFFF, 0x22, 0, GUARD_SEED, &dif_opts);
1700 	CU_ASSERT(rc == 0);
1701 
1702 	rc = spdk_dif_generate_stream(&iov, 1, 0, 511, &ctx);
1703 	CU_ASSERT(rc == 0);
1704 
1705 	rc = spdk_dif_generate_stream(&iov, 1, 511, 1, &ctx);
1706 	CU_ASSERT(rc == 0);
1707 
1708 	rc = spdk_dif_generate_stream(&iov, 1, 512, 256, &ctx);
1709 	CU_ASSERT(rc == 0);
1710 
1711 	rc = spdk_dif_generate_stream(&iov, 1, 768, 512, &ctx);
1712 	CU_ASSERT(rc == 0);
1713 
1714 	rc = spdk_dif_generate_stream(&iov, 1, 1280, 1024, &ctx);
1715 	CU_ASSERT(rc == 0);
1716 
1717 	rc = spdk_dif_generate_stream(&iov, 1, 2304, 256, &ctx);
1718 	CU_ASSERT(rc == 0);
1719 
1720 	rc = spdk_dif_generate_stream(&iov, 1, 2560, 512, &ctx);
1721 	CU_ASSERT(rc == -ERANGE);
1722 
1723 	rc = spdk_dif_verify(&iov, 1, 5, &ctx, &err_blk);
1724 	CU_ASSERT(rc == 0);
1725 
1726 	rc = ut_data_pattern_verify(&iov, 1, 512 + 8, 8, 5);
1727 	CU_ASSERT(rc == 0);
1728 
1729 	_iov_free_buf(&iov);
1730 }
1731 
1732 static void
1733 set_md_interleave_iovs_alignment_test(void)
1734 {
1735 	struct iovec iovs[3], dif_iovs[5] = {};
1736 	uint32_t mapped_len = 0;
1737 	int rc;
1738 	struct spdk_dif_ctx ctx;
1739 	struct spdk_dif_ctx_init_ext_opts dif_opts;
1740 
1741 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
1742 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
1743 	rc = spdk_dif_ctx_init(&ctx, 512 + 8, 8, true, false, SPDK_DIF_TYPE1,
1744 			       0, 0, 0, 0, 0, 0, &dif_opts);
1745 	CU_ASSERT(rc == 0);
1746 
1747 	/* The case that buffer size is smaller than necessary. */
1748 	_iov_set_buf(&iovs[0], (uint8_t *)0xDEADBEEF, 1024);
1749 	_iov_set_buf(&iovs[1], (uint8_t *)0xFEEDBEEF, 1024);
1750 	_iov_set_buf(&iovs[2], (uint8_t *)0xC0FFEE, 24);
1751 
1752 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 5, iovs, 3, 0, 2048, &mapped_len, &ctx);
1753 	CU_ASSERT(rc == -ERANGE);
1754 
1755 	/* The following are the normal cases. */
1756 	_iov_set_buf(&iovs[2], (uint8_t *)0xC0FFEE, 32);
1757 
1758 	/* data length is less than a data block size. */
1759 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 5, iovs, 3, 0, 500, &mapped_len, &ctx);
1760 	CU_ASSERT(rc == 1);
1761 	CU_ASSERT(mapped_len == 500);
1762 	CU_ASSERT(_iov_check(&dif_iovs[0], (void *)0xDEADBEEF, 500) == true);
1763 
1764 	/* Pass enough number of iovecs */
1765 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 5, iovs, 3, 500, 1000, &mapped_len, &ctx);
1766 	CU_ASSERT(rc == 4);
1767 	CU_ASSERT(mapped_len == 1000);
1768 	CU_ASSERT(_iov_check(&dif_iovs[0], (void *)(0xDEADBEEF + 500), 12) == true);
1769 	CU_ASSERT(_iov_check(&dif_iovs[1], (void *)(0xDEADBEEF + 520), 504) == true);
1770 	CU_ASSERT(_iov_check(&dif_iovs[2], (void *)0xFEEDBEEF, 8) == true);
1771 	CU_ASSERT(_iov_check(&dif_iovs[3], (void *)(0xFEEDBEEF + 16), 476) == true);
1772 
1773 	/* Pass iovecs smaller than necessary */
1774 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 3, iovs, 3, 500, 1000, &mapped_len, &ctx);
1775 	CU_ASSERT(rc == 3);
1776 	CU_ASSERT(mapped_len == 524);
1777 	CU_ASSERT(_iov_check(&dif_iovs[0], (void *)(0xDEADBEEF + 500), 12) == true);
1778 	CU_ASSERT(_iov_check(&dif_iovs[1], (void *)(0xDEADBEEF + 520), 504) == true);
1779 	CU_ASSERT(_iov_check(&dif_iovs[2], (void *)0xFEEDBEEF, 8) == true);
1780 
1781 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 5, iovs, 3, 1500, 500, &mapped_len, &ctx);
1782 	CU_ASSERT(rc == 2);
1783 	CU_ASSERT(mapped_len == 500);
1784 	CU_ASSERT(_iov_check(&dif_iovs[0], (void *)(0xFEEDBEEF + 492), 36) == true);
1785 	CU_ASSERT(_iov_check(&dif_iovs[1], (void *)(0xFEEDBEEF + 536), 464) == true);
1786 
1787 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 5, iovs, 3, 2000, 48, &mapped_len, &ctx);
1788 	CU_ASSERT(rc == 2);
1789 	CU_ASSERT(mapped_len == 48);
1790 	CU_ASSERT(_iov_check(&dif_iovs[0], (void *)0xFEEDBEEF + 1000, 24) == true);
1791 	CU_ASSERT(_iov_check(&dif_iovs[1], (void *)0xC0FFEE, 24) ==  true);
1792 }
1793 
1794 static void
1795 _dif_generate_split_test(void)
1796 {
1797 	struct spdk_dif_ctx ctx = {};
1798 	struct iovec iov;
1799 	uint8_t *buf1, *buf2;
1800 	struct _dif_sgl sgl;
1801 	uint16_t guard = 0, prev_guard;
1802 	uint32_t dif_flags;
1803 	int rc;
1804 	struct spdk_dif_ctx_init_ext_opts dif_opts;
1805 
1806 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
1807 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
1808 
1809 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
1810 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
1811 	rc = spdk_dif_ctx_init(&ctx, 4096 + 128, 128, true, false, SPDK_DIF_TYPE1,
1812 			       dif_flags, 0, 0, 0, 0, GUARD_SEED, &dif_opts);
1813 	CU_ASSERT(rc == 0);
1814 
1815 	buf1 = calloc(1, 4096 + 128);
1816 	SPDK_CU_ASSERT_FATAL(buf1 != NULL);
1817 	_iov_set_buf(&iov, buf1, 4096 + 128);
1818 
1819 	rc = ut_data_pattern_generate(&iov, 1, 4096 + 128, 128, 1);
1820 	CU_ASSERT(rc == 0);
1821 
1822 	_dif_sgl_init(&sgl, &iov, 1);
1823 
1824 	guard = GUARD_SEED;
1825 	prev_guard = GUARD_SEED;
1826 
1827 	guard = _dif_generate_split(&sgl, 0, 1000, guard, 0, &ctx);
1828 	CU_ASSERT(sgl.iov_offset == 1000);
1829 	CU_ASSERT(guard == spdk_crc16_t10dif(prev_guard, buf1, 1000));
1830 
1831 	prev_guard = guard;
1832 
1833 	guard = _dif_generate_split(&sgl, 1000, 3000, guard, 0, &ctx);
1834 	CU_ASSERT(sgl.iov_offset == 4000);
1835 	CU_ASSERT(guard == spdk_crc16_t10dif(prev_guard, buf1 + 1000, 3000));
1836 
1837 	guard = _dif_generate_split(&sgl, 4000, 96 + 128, guard, 0, &ctx);
1838 	CU_ASSERT(guard == GUARD_SEED);
1839 	CU_ASSERT(sgl.iov_offset == 0);
1840 	CU_ASSERT(sgl.iovcnt == 0);
1841 
1842 	rc = ut_data_pattern_verify(&iov, 1, 4096 + 128, 128, 1);
1843 	CU_ASSERT(rc == 0);
1844 
1845 	_dif_sgl_init(&sgl, &iov, 1);
1846 
1847 	rc = dif_verify(&sgl, 1, &ctx, NULL);
1848 	CU_ASSERT(rc == 0);
1849 
1850 	buf2 = calloc(1, 4096 + 128);
1851 	SPDK_CU_ASSERT_FATAL(buf2 != NULL);
1852 	_iov_set_buf(&iov, buf2, 4096 + 128);
1853 
1854 	rc = ut_data_pattern_generate(&iov, 1, 4096 + 128, 128, 1);
1855 	CU_ASSERT(rc == 0);
1856 
1857 	_dif_sgl_init(&sgl, &iov, 1);
1858 
1859 	dif_generate(&sgl, 1, &ctx);
1860 
1861 	rc = ut_data_pattern_verify(&iov, 1, 4096 + 128, 128, 1);
1862 	CU_ASSERT(rc == 0);
1863 
1864 	_dif_sgl_init(&sgl, &iov, 1);
1865 
1866 	rc = dif_verify(&sgl, 1, &ctx, NULL);
1867 	CU_ASSERT(rc == 0);
1868 
1869 	rc = memcmp(buf1, buf2, 4096 + 128);
1870 	CU_ASSERT(rc == 0);
1871 
1872 	free(buf1);
1873 	free(buf2);
1874 }
1875 
1876 static void
1877 set_md_interleave_iovs_multi_segments_test(void)
1878 {
1879 	struct spdk_dif_ctx ctx = {};
1880 	struct spdk_dif_error err_blk = {};
1881 	struct iovec iov1 = {}, iov2 = {}, dif_iovs[4] = {};
1882 	uint32_t dif_check_flags, data_len, read_len, data_offset, read_offset, mapped_len = 0;
1883 	uint8_t *buf1, *buf2;
1884 	int rc;
1885 	struct spdk_dif_ctx_init_ext_opts dif_opts;
1886 
1887 	dif_check_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
1888 			  SPDK_DIF_FLAGS_REFTAG_CHECK;
1889 
1890 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
1891 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
1892 	rc = spdk_dif_ctx_init(&ctx, 4096 + 128, 128, true, false, SPDK_DIF_TYPE1,
1893 			       dif_check_flags, 22, 0xFFFF, 0x22, 0, GUARD_SEED, &dif_opts);
1894 	CU_ASSERT(rc == 0);
1895 
1896 	/* The first data buffer:
1897 	 * - Data buffer is split into multi data segments
1898 	 * - For each data segment,
1899 	 *  - Create iovec array to Leave a space for metadata for each block
1900 	 *  - Split vectored read and so creating iovec array is done before every vectored read.
1901 	 */
1902 	buf1 = calloc(1, (4096 + 128) * 4);
1903 	SPDK_CU_ASSERT_FATAL(buf1 != NULL);
1904 	_iov_set_buf(&iov1, buf1, (4096 + 128) * 4);
1905 
1906 	/* 1st data segment */
1907 	data_offset = 0;
1908 	data_len = 1024;
1909 
1910 	spdk_dif_ctx_set_data_offset(&ctx, data_offset);
1911 
1912 	read_offset = 0;
1913 
1914 	/* 1st read in 1st data segment */
1915 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 4, &iov1, 1,
1916 					     read_offset, data_len - read_offset,
1917 					     &mapped_len, &ctx);
1918 	CU_ASSERT(rc == 1);
1919 	CU_ASSERT(mapped_len == 1024);
1920 	CU_ASSERT(_iov_check(&dif_iovs[0], buf1, 1024) == true);
1921 
1922 	read_len = ut_readv(data_offset + read_offset, 1024, dif_iovs, 4);
1923 	CU_ASSERT(read_len == 1024);
1924 
1925 	rc = spdk_dif_generate_stream(&iov1, 1, read_offset, read_len, &ctx);
1926 	CU_ASSERT(rc == 0);
1927 
1928 	read_offset += read_len;
1929 	CU_ASSERT(read_offset == data_len);
1930 
1931 	/* 2nd data segment */
1932 	data_offset += data_len;
1933 	data_len = 3072 + 4096 * 2 + 512;
1934 
1935 	spdk_dif_ctx_set_data_offset(&ctx, data_offset);
1936 	_iov_set_buf(&iov1, buf1 + 1024, 3072 + 128 + (4096 + 128) * 3 + 512);
1937 
1938 	read_offset = 0;
1939 
1940 	/* 1st read in 2nd data segment */
1941 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 4, &iov1, 1,
1942 					     read_offset, data_len - read_offset,
1943 					     &mapped_len, &ctx);
1944 	CU_ASSERT(rc == 4);
1945 	CU_ASSERT(mapped_len == 3072 + 4096 * 2 + 512);
1946 	CU_ASSERT(_iov_check(&dif_iovs[0], buf1 + 1024, 3072) == true);
1947 	CU_ASSERT(_iov_check(&dif_iovs[1], buf1 + 4096 + 128, 4096) == true);
1948 	CU_ASSERT(_iov_check(&dif_iovs[2], buf1 + (4096 + 128) * 2, 4096) == true);
1949 	CU_ASSERT(_iov_check(&dif_iovs[3], buf1 + (4096 + 128) * 3, 512) == true);
1950 
1951 	read_len = ut_readv(data_offset + read_offset, 3071, dif_iovs, 4);
1952 	CU_ASSERT(read_len == 3071);
1953 
1954 	rc = spdk_dif_generate_stream(&iov1, 1, read_offset, read_len, &ctx);
1955 	CU_ASSERT(rc == 0);
1956 
1957 	read_offset += read_len;
1958 
1959 	/* 2nd read in 2nd data segment */
1960 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 4, &iov1, 1,
1961 					     read_offset, data_len - read_offset,
1962 					     &mapped_len, &ctx);
1963 	CU_ASSERT(rc == 4);
1964 	CU_ASSERT(mapped_len == 1 + 4096 * 2 + 512);
1965 	CU_ASSERT(_iov_check(&dif_iovs[0], buf1 + 4095, 1) == true);
1966 	CU_ASSERT(_iov_check(&dif_iovs[1], buf1 + 4096 + 128, 4096) == true);
1967 	CU_ASSERT(_iov_check(&dif_iovs[2], buf1 + (4096 + 128) * 2, 4096) == true);
1968 	CU_ASSERT(_iov_check(&dif_iovs[3], buf1 + (4096 + 128) * 3, 512) == true);
1969 
1970 	read_len = ut_readv(data_offset + read_offset, 1 + 4096 * 2 + 512, dif_iovs, 4);
1971 	CU_ASSERT(read_len == 1 + 4096 * 2 + 512);
1972 
1973 	rc = spdk_dif_generate_stream(&iov1, 1, read_offset, read_len, &ctx);
1974 	CU_ASSERT(rc == 0);
1975 
1976 	read_offset += read_len;
1977 	CU_ASSERT(read_offset == data_len);
1978 
1979 	/* 3rd data segment */
1980 	data_offset += data_len;
1981 	data_len = 3584;
1982 
1983 	spdk_dif_ctx_set_data_offset(&ctx, data_offset);
1984 	_iov_set_buf(&iov1, buf1 + (4096 + 128) * 3 + 512, 3584 + 128);
1985 
1986 	read_offset = 0;
1987 
1988 	/* 1st read in 3rd data segment */
1989 	rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 4, &iov1, 1,
1990 					     read_offset, data_len - read_offset,
1991 					     &mapped_len, &ctx);
1992 	CU_ASSERT(rc == 1);
1993 	CU_ASSERT(mapped_len == 3584);
1994 	CU_ASSERT(_iov_check(&dif_iovs[0], buf1 + (4096 + 128) * 3 + 512, 3584) == true);
1995 
1996 	read_len = ut_readv(data_offset + read_offset, 3584, dif_iovs, 1);
1997 	CU_ASSERT(read_len == 3584);
1998 
1999 	rc = spdk_dif_generate_stream(&iov1, 1, read_offset, read_len, &ctx);
2000 	CU_ASSERT(rc == 0);
2001 
2002 	read_offset += read_len;
2003 	CU_ASSERT(read_offset == data_len);
2004 	data_offset += data_len;
2005 	CU_ASSERT(data_offset == 4096 * 4);
2006 
2007 	spdk_dif_ctx_set_data_offset(&ctx, 0);
2008 	_iov_set_buf(&iov1, buf1, (4096 + 128) * 4);
2009 
2010 	/* The second data buffer:
2011 	 * - Set data pattern with a space for metadata for each block.
2012 	 */
2013 	buf2 = calloc(1, (4096 + 128) * 4);
2014 	SPDK_CU_ASSERT_FATAL(buf2 != NULL);
2015 	_iov_set_buf(&iov2, buf2, (4096 + 128) * 4);
2016 
2017 	rc = ut_data_pattern_generate(&iov2, 1, 4096 + 128, 128, 4);
2018 	CU_ASSERT(rc == 0);
2019 
2020 	rc = spdk_dif_generate(&iov2, 1, 4, &ctx);
2021 	CU_ASSERT(rc == 0);
2022 
2023 	rc = spdk_dif_verify(&iov1, 1, 4, &ctx, &err_blk);
2024 	CU_ASSERT(rc == 0);
2025 
2026 	rc = spdk_dif_verify(&iov2, 1, 4, &ctx, &err_blk);
2027 	CU_ASSERT(rc == 0);
2028 
2029 	/* Compare the first and the second data buffer by byte. */
2030 	rc = memcmp(buf1, buf2, (4096 + 128) * 4);
2031 	CU_ASSERT(rc == 0);
2032 
2033 	free(buf1);
2034 	free(buf2);
2035 }
2036 
2037 static void
2038 _dif_verify_split_test(void)
2039 {
2040 	struct spdk_dif_ctx ctx = {};
2041 	struct spdk_dif_error err_blk = {};
2042 	struct iovec iov;
2043 	uint8_t *buf;
2044 	struct _dif_sgl sgl;
2045 	uint16_t guard = 0, prev_guard = 0;
2046 	uint32_t dif_flags;
2047 	int rc;
2048 	struct spdk_dif_ctx_init_ext_opts dif_opts;
2049 
2050 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
2051 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
2052 
2053 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
2054 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
2055 	rc = spdk_dif_ctx_init(&ctx, 4096 + 128, 128, true, false, SPDK_DIF_TYPE1,
2056 			       dif_flags, 0, 0, 0, 0, GUARD_SEED, &dif_opts);
2057 	CU_ASSERT(rc == 0);
2058 
2059 	buf = calloc(1, 4096 + 128);
2060 	SPDK_CU_ASSERT_FATAL(buf != NULL);
2061 	_iov_set_buf(&iov, buf, 4096 + 128);
2062 
2063 	rc = ut_data_pattern_generate(&iov, 1, 4096 + 128, 128, 1);
2064 	CU_ASSERT(rc == 0);
2065 
2066 	_dif_sgl_init(&sgl, &iov, 1);
2067 
2068 	dif_generate(&sgl, 1, &ctx);
2069 
2070 	_dif_sgl_init(&sgl, &iov, 1);
2071 
2072 	guard = GUARD_SEED;
2073 	prev_guard = GUARD_SEED;
2074 
2075 	rc = _dif_verify_split(&sgl, 0, 1000, &guard, 0, &ctx, &err_blk);
2076 	CU_ASSERT(rc == 0);
2077 	CU_ASSERT(guard == spdk_crc16_t10dif(prev_guard, buf, 1000));
2078 	CU_ASSERT(sgl.iov_offset == 1000);
2079 
2080 	prev_guard = guard;
2081 
2082 	rc = _dif_verify_split(&sgl, 1000, 3000, &guard, 0, &ctx, &err_blk);
2083 	CU_ASSERT(rc == 0);
2084 	CU_ASSERT(guard == spdk_crc16_t10dif(prev_guard, buf + 1000, 3000));
2085 	CU_ASSERT(sgl.iov_offset == 4000);
2086 
2087 	rc = _dif_verify_split(&sgl, 4000, 96 + 128, &guard, 0, &ctx, &err_blk);
2088 	CU_ASSERT(rc == 0);
2089 	CU_ASSERT(guard == GUARD_SEED);
2090 	CU_ASSERT(sgl.iov_offset == 0);
2091 	CU_ASSERT(sgl.iovcnt == 0);
2092 
2093 	_dif_sgl_init(&sgl, &iov, 1);
2094 
2095 	rc = dif_verify(&sgl, 1, &ctx, &err_blk);
2096 	CU_ASSERT(rc == 0);
2097 
2098 	rc = ut_data_pattern_verify(&iov, 1, 4096 + 128, 128, 1);
2099 	CU_ASSERT(rc == 0);
2100 
2101 	free(buf);
2102 }
2103 
2104 static void
2105 dif_verify_stream_multi_segments_test(void)
2106 {
2107 	struct spdk_dif_ctx ctx = {};
2108 	struct spdk_dif_error err_blk = {};
2109 	struct iovec iov = {};
2110 	uint8_t *buf;
2111 	uint32_t dif_flags;
2112 	int rc;
2113 	struct spdk_dif_ctx_init_ext_opts dif_opts;
2114 
2115 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
2116 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
2117 
2118 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
2119 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
2120 	rc = spdk_dif_ctx_init(&ctx, 4096 + 128, 128, true, false, SPDK_DIF_TYPE1,
2121 			       dif_flags, 22, 0xFFFF, 0x22, 0, GUARD_SEED, &dif_opts);
2122 	CU_ASSERT(rc == 0);
2123 
2124 	buf = calloc(1, (4096 + 128) * 4);
2125 	SPDK_CU_ASSERT_FATAL(buf != NULL);
2126 	_iov_set_buf(&iov, buf, (4096 + 128) * 4);
2127 
2128 	rc = ut_data_pattern_generate(&iov, 1, 4096 + 128, 128, 4);
2129 	CU_ASSERT(rc == 0);
2130 
2131 	rc = spdk_dif_generate(&iov, 1, 4, &ctx);
2132 	CU_ASSERT(rc == 0);
2133 
2134 	/* 1st data segment */
2135 	_iov_set_buf(&iov, buf, 1024);
2136 	spdk_dif_ctx_set_data_offset(&ctx, 0);
2137 
2138 	rc = spdk_dif_verify_stream(&iov, 1, 0, 1024, &ctx, &err_blk);
2139 	CU_ASSERT(rc == 0);
2140 
2141 	/* 2nd data segment */
2142 	_iov_set_buf(&iov, buf + 1024, (3072 + 128) + (4096 + 128) * 2 + 512);
2143 	spdk_dif_ctx_set_data_offset(&ctx, 1024);
2144 
2145 	rc = spdk_dif_verify_stream(&iov, 1, 0, 3072 + 4096 * 2 + 512, &ctx, &err_blk);
2146 	CU_ASSERT(rc == 0);
2147 
2148 	/* 3rd data segment */
2149 	_iov_set_buf(&iov, buf + (4096 + 128) * 3 + 512, 3584 + 128);
2150 	spdk_dif_ctx_set_data_offset(&ctx, 4096 * 3);
2151 
2152 	rc = spdk_dif_verify_stream(&iov, 1, 0, 3584, &ctx, &err_blk);
2153 	CU_ASSERT(rc == 0);
2154 
2155 	/* verify all data segments once */
2156 	_iov_set_buf(&iov, buf, (4096 + 128) * 4);
2157 	spdk_dif_ctx_set_data_offset(&ctx, 0);
2158 
2159 	rc = spdk_dif_verify(&iov, 1, 4, &ctx, &err_blk);
2160 	CU_ASSERT(rc == 0);
2161 
2162 	rc = ut_data_pattern_verify(&iov, 1, 4096 + 128, 128, 4);
2163 	CU_ASSERT(rc == 0);
2164 
2165 	free(buf);
2166 }
2167 
2168 #define UT_CRC32C_XOR	0xffffffffUL
2169 
2170 static void
2171 update_crc32c_test(void)
2172 {
2173 	struct spdk_dif_ctx ctx = {};
2174 	struct iovec iovs[7];
2175 	uint32_t crc32c1, crc32c2, crc32c3, crc32c4;
2176 	uint32_t dif_flags;
2177 	int i, rc;
2178 	struct spdk_dif_ctx_init_ext_opts dif_opts;
2179 
2180 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
2181 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
2182 
2183 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
2184 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
2185 	rc = spdk_dif_ctx_init(&ctx, 512 + 8, 8, true, false, SPDK_DIF_TYPE1,
2186 			       dif_flags, 0, 0, 0, 0, 0, &dif_opts);
2187 	CU_ASSERT(rc == 0);
2188 
2189 	/* data[0][255:0] */
2190 	_iov_alloc_buf(&iovs[0], 256);
2191 
2192 	/* data[0][511:256], md[0][0] */
2193 	_iov_alloc_buf(&iovs[1], 256 + 1);
2194 
2195 	/* md[0][4:1] */
2196 	_iov_alloc_buf(&iovs[2], 4);
2197 
2198 	/* md[0][7:5], data[1][122:0] */
2199 	_iov_alloc_buf(&iovs[3], 3 + 123);
2200 
2201 	/* data[1][511:123], md[1][5:0] */
2202 	_iov_alloc_buf(&iovs[4], 389 + 6);
2203 
2204 	/* md[1][7:6], data[2][511:0], md[2][7:0], data[3][431:0] */
2205 	_iov_alloc_buf(&iovs[5], 2 + 512 + 8 + 432);
2206 
2207 	/* data[3][511:432], md[3][7:0] */
2208 	_iov_alloc_buf(&iovs[6], 80 + 8);
2209 
2210 	rc = ut_data_pattern_generate(iovs, 7, 512 + 8, 8, 4);
2211 	CU_ASSERT(rc == 0);
2212 
2213 	crc32c1 = UT_CRC32C_XOR;
2214 
2215 	rc = spdk_dif_update_crc32c(iovs, 7, 4, &crc32c1, &ctx);
2216 	CU_ASSERT(rc == 0);
2217 
2218 	/* Test if DIF doesn't affect CRC for split case. */
2219 	rc = spdk_dif_generate(iovs, 7, 4, &ctx);
2220 	CU_ASSERT(rc == 0);
2221 
2222 	crc32c2 = UT_CRC32C_XOR;
2223 
2224 	rc = spdk_dif_update_crc32c(iovs, 7, 4, &crc32c2, &ctx);
2225 	CU_ASSERT(rc == 0);
2226 
2227 	CU_ASSERT(crc32c1 == crc32c2);
2228 
2229 	for (i = 0; i < 7; i++) {
2230 		_iov_free_buf(&iovs[i]);
2231 	}
2232 
2233 	/* Test if CRC is same regardless of splitting. */
2234 	for (i = 0; i < 4; i++) {
2235 		_iov_alloc_buf(&iovs[i], 512 + 8);
2236 	}
2237 
2238 	rc = ut_data_pattern_generate(iovs, 4, 512 + 8, 8, 4);
2239 	CU_ASSERT(rc == 0);
2240 
2241 	crc32c3 = UT_CRC32C_XOR;
2242 
2243 	rc = spdk_dif_update_crc32c(iovs, 4, 4, &crc32c3, &ctx);
2244 	CU_ASSERT(rc == 0);
2245 
2246 	CU_ASSERT(crc32c1 == crc32c3);
2247 
2248 	/* Test if DIF doesn't affect CRC for non-split case. */
2249 	rc = spdk_dif_generate(iovs, 4, 4, &ctx);
2250 	CU_ASSERT(rc == 0);
2251 
2252 	crc32c4 = UT_CRC32C_XOR;
2253 
2254 	rc = spdk_dif_update_crc32c(iovs, 4, 4, &crc32c4, &ctx);
2255 	CU_ASSERT(rc == 0);
2256 
2257 	CU_ASSERT(crc32c1 == crc32c4);
2258 
2259 	for (i = 0; i < 4; i++) {
2260 		_iov_free_buf(&iovs[i]);
2261 	}
2262 }
2263 
2264 static void
2265 _dif_update_crc32c_split_test(void)
2266 {
2267 	struct spdk_dif_ctx ctx = {};
2268 	struct iovec iov;
2269 	uint8_t *buf;
2270 	struct _dif_sgl sgl;
2271 	uint32_t dif_flags, crc32c, prev_crc32c;
2272 	int rc;
2273 	struct spdk_dif_ctx_init_ext_opts dif_opts;
2274 
2275 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
2276 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
2277 
2278 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
2279 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
2280 	rc = spdk_dif_ctx_init(&ctx, 4096 + 128, 128, true, false, SPDK_DIF_TYPE1,
2281 			       dif_flags, 0, 0, 0, 0, GUARD_SEED, &dif_opts);
2282 	CU_ASSERT(rc == 0);
2283 
2284 	buf = calloc(1, 4096 + 128);
2285 	SPDK_CU_ASSERT_FATAL(buf != NULL);
2286 	_iov_set_buf(&iov, buf, 4096 + 128);
2287 
2288 	rc = ut_data_pattern_generate(&iov, 1, 4096 + 128, 128, 1);
2289 	CU_ASSERT(rc == 0);
2290 
2291 	_dif_sgl_init(&sgl, &iov, 1);
2292 
2293 	dif_generate(&sgl, 1, &ctx);
2294 
2295 	_dif_sgl_init(&sgl, &iov, 1);
2296 
2297 	crc32c = _dif_update_crc32c_split(&sgl, 0, 1000, UT_CRC32C_XOR, &ctx);
2298 	CU_ASSERT(crc32c == spdk_crc32c_update(buf, 1000, UT_CRC32C_XOR));
2299 
2300 	prev_crc32c = crc32c;
2301 
2302 	crc32c = _dif_update_crc32c_split(&sgl, 1000, 3000, prev_crc32c, &ctx);
2303 	CU_ASSERT(crc32c == spdk_crc32c_update(buf + 1000, 3000, prev_crc32c));
2304 
2305 	prev_crc32c = crc32c;
2306 
2307 	crc32c = _dif_update_crc32c_split(&sgl, 4000, 96 + 128, prev_crc32c, &ctx);
2308 	CU_ASSERT(crc32c == spdk_crc32c_update(buf + 4000, 96, prev_crc32c));
2309 
2310 	CU_ASSERT(crc32c == spdk_crc32c_update(buf, 4096, UT_CRC32C_XOR));
2311 
2312 	free(buf);
2313 }
2314 
2315 static void
2316 dif_update_crc32c_stream_multi_segments_test(void)
2317 {
2318 	struct spdk_dif_ctx ctx = {};
2319 	struct iovec iov = {};
2320 	uint8_t *buf;
2321 	uint32_t dif_flags, crc32c1, crc32c2;
2322 	int rc;
2323 	struct spdk_dif_ctx_init_ext_opts dif_opts;
2324 
2325 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
2326 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
2327 
2328 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
2329 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
2330 	rc = spdk_dif_ctx_init(&ctx, 4096 + 128, 128, true, false, SPDK_DIF_TYPE1,
2331 			       dif_flags, 22, 0xFFFF, 0x22, 0, GUARD_SEED, &dif_opts);
2332 	CU_ASSERT(rc == 0);
2333 
2334 	buf = calloc(1, (4096 + 128) * 4);
2335 	SPDK_CU_ASSERT_FATAL(buf != NULL);
2336 	_iov_set_buf(&iov, buf, (4096 + 128) * 4);
2337 
2338 	rc = ut_data_pattern_generate(&iov, 1, 4096 + 128, 128, 4);
2339 	CU_ASSERT(rc == 0);
2340 
2341 	rc = spdk_dif_generate(&iov, 1, 4, &ctx);
2342 	CU_ASSERT(rc == 0);
2343 
2344 	crc32c1 = UT_CRC32C_XOR;
2345 	crc32c2 = UT_CRC32C_XOR;
2346 
2347 	/* 1st data segment */
2348 	_iov_set_buf(&iov, buf, 1024);
2349 	spdk_dif_ctx_set_data_offset(&ctx, 0);
2350 
2351 	rc = spdk_dif_update_crc32c_stream(&iov, 1, 0, 1024, &crc32c1, &ctx);
2352 	CU_ASSERT(rc == 0);
2353 
2354 	/* 2nd data segment */
2355 	_iov_set_buf(&iov, buf + 1024, (3072 + 128) + (4096 + 128) * 2 + 512);
2356 	spdk_dif_ctx_set_data_offset(&ctx, 1024);
2357 
2358 	rc = spdk_dif_update_crc32c_stream(&iov, 1, 0, 3072 + 4096 * 2 + 512, &crc32c1, &ctx);
2359 	CU_ASSERT(rc == 0);
2360 
2361 	/* 3rd data segment */
2362 	_iov_set_buf(&iov, buf + (4096 + 128) * 3 + 512, 3584 + 128);
2363 	spdk_dif_ctx_set_data_offset(&ctx, 4096 * 3);
2364 
2365 	rc = spdk_dif_update_crc32c_stream(&iov, 1, 0, 3584, &crc32c1, &ctx);
2366 	CU_ASSERT(rc == 0);
2367 
2368 	/* Update CRC32C for all data segments once */
2369 	_iov_set_buf(&iov, buf, (4096 + 128) * 4);
2370 	spdk_dif_ctx_set_data_offset(&ctx, 0);
2371 
2372 	rc = spdk_dif_update_crc32c(&iov, 1, 4, &crc32c2, &ctx);
2373 	CU_ASSERT(rc == 0);
2374 
2375 	CU_ASSERT(crc32c1 == crc32c2);
2376 
2377 	free(buf);
2378 }
2379 
2380 static void
2381 get_range_with_md_test(void)
2382 {
2383 	struct spdk_dif_ctx ctx = {};
2384 	uint32_t buf_offset, buf_len;
2385 	int rc;
2386 	struct spdk_dif_ctx_init_ext_opts dif_opts;
2387 
2388 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
2389 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
2390 	rc = spdk_dif_ctx_init(&ctx, 4096 + 128, 128, true, false,
2391 			       0, 0, 0, 0, 0, 0, 0, &dif_opts);
2392 	CU_ASSERT(rc == 0);
2393 
2394 	spdk_dif_get_range_with_md(0, 2048, &buf_offset, &buf_len, &ctx);
2395 	CU_ASSERT(buf_offset == 0);
2396 	CU_ASSERT(buf_len == 2048);
2397 
2398 	spdk_dif_get_range_with_md(2048, 4096, &buf_offset, &buf_len, &ctx);
2399 	CU_ASSERT(buf_offset == 2048);
2400 	CU_ASSERT(buf_len == 4096 + 128);
2401 
2402 	spdk_dif_get_range_with_md(4096, 10240, &buf_offset, &buf_len, &ctx);
2403 	CU_ASSERT(buf_offset == 4096 + 128);
2404 	CU_ASSERT(buf_len == 10240 + 256);
2405 
2406 	spdk_dif_get_range_with_md(10240, 2048, &buf_offset, &buf_len, &ctx);
2407 	CU_ASSERT(buf_offset == 10240 + 256);
2408 	CU_ASSERT(buf_len == 2048 + 128);
2409 
2410 	buf_len = spdk_dif_get_length_with_md(6144, &ctx);
2411 	CU_ASSERT(buf_len == 6144 + 128);
2412 }
2413 
2414 static void
2415 dif_generate_remap_and_verify(struct iovec *iovs, int iovcnt,
2416 			      uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
2417 			      bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
2418 			      uint32_t init_ref_tag, uint32_t remapped_init_ref_tag,
2419 			      uint16_t apptag_mask, uint16_t app_tag)
2420 {
2421 	struct spdk_dif_ctx ctx = {};
2422 	int rc;
2423 	struct spdk_dif_ctx_init_ext_opts dif_opts;
2424 
2425 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, md_size, num_blocks);
2426 	CU_ASSERT(rc == 0);
2427 
2428 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
2429 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
2430 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc, dif_type, dif_flags,
2431 			       init_ref_tag, apptag_mask, app_tag, 0, GUARD_SEED, &dif_opts);
2432 	CU_ASSERT(rc == 0);
2433 
2434 	rc = spdk_dif_generate(iovs, iovcnt, num_blocks, &ctx);
2435 	CU_ASSERT(rc == 0);
2436 
2437 	spdk_dif_ctx_set_remapped_init_ref_tag(&ctx, remapped_init_ref_tag);
2438 
2439 	rc = spdk_dif_remap_ref_tag(iovs, iovcnt, num_blocks, &ctx, NULL);
2440 	CU_ASSERT(rc == 0);
2441 
2442 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, true, dif_loc, dif_type, dif_flags,
2443 			       remapped_init_ref_tag, apptag_mask, app_tag, 0, GUARD_SEED, &dif_opts);
2444 	CU_ASSERT(rc == 0);
2445 
2446 	rc = spdk_dif_verify(iovs, iovcnt, num_blocks, &ctx, NULL);
2447 	CU_ASSERT(rc == 0);
2448 
2449 	rc = ut_data_pattern_verify(iovs, iovcnt, block_size, md_size, num_blocks);
2450 	CU_ASSERT(rc == 0);
2451 }
2452 
2453 static void
2454 dif_sec_4096_md_128_prchk_7_multi_iovs_remap_test(void)
2455 {
2456 	struct iovec iovs[4];
2457 	int i, num_blocks;
2458 	uint32_t dif_flags;
2459 
2460 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
2461 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
2462 
2463 	num_blocks = 0;
2464 
2465 	for (i = 0; i < 4; i++) {
2466 		_iov_alloc_buf(&iovs[i], (512 + 8) * (i + 1));
2467 		num_blocks += i + 1;
2468 	}
2469 
2470 	dif_generate_remap_and_verify(iovs, 4, 512 + 8, 8, num_blocks, false, SPDK_DIF_TYPE1,
2471 				      dif_flags, 22, 99, 0xFFFF, 0x22);
2472 
2473 	dif_generate_remap_and_verify(iovs, 4, 512 + 8, 8, num_blocks, true, SPDK_DIF_TYPE1,
2474 				      dif_flags, 22, 99, 0xFFFF, 0x22);
2475 
2476 	for (i = 0; i < 4; i++) {
2477 		_iov_free_buf(&iovs[i]);
2478 	}
2479 }
2480 
2481 static void
2482 dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_remap_test(void)
2483 {
2484 	struct iovec iovs[11];
2485 	uint32_t dif_flags;
2486 	int i;
2487 
2488 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
2489 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
2490 
2491 	/* data[0][1000:0] */
2492 	_iov_alloc_buf(&iovs[0], 1000);
2493 
2494 	/* data[0][3095:1000], guard[0][0] */
2495 	_iov_alloc_buf(&iovs[1], 3096 + 1);
2496 
2497 	/* guard[0][1], apptag[0][0] */
2498 	_iov_alloc_buf(&iovs[2], 1 + 1);
2499 
2500 	/* apptag[0][1], reftag[0][0] */
2501 	_iov_alloc_buf(&iovs[3], 1 + 1);
2502 
2503 	/* reftag[0][3:1], ignore[0][59:0] */
2504 	_iov_alloc_buf(&iovs[4], 3 + 60);
2505 
2506 	/* ignore[119:60], data[1][3050:0] */
2507 	_iov_alloc_buf(&iovs[5], 60 + 3051);
2508 
2509 	/* data[1][4095:3050], guard[1][0] */
2510 	_iov_alloc_buf(&iovs[6], 1045 + 1);
2511 
2512 	/* guard[1][1], apptag[1][0] */
2513 	_iov_alloc_buf(&iovs[7], 1 + 1);
2514 
2515 	/* apptag[1][1], reftag[1][0] */
2516 	_iov_alloc_buf(&iovs[8], 1 + 1);
2517 
2518 	/* reftag[1][3:1], ignore[1][9:0] */
2519 	_iov_alloc_buf(&iovs[9], 3 + 10);
2520 
2521 	/* ignore[1][127:9] */
2522 	_iov_alloc_buf(&iovs[10], 118);
2523 
2524 	dif_generate_remap_and_verify(iovs, 11, 4096 + 128, 128, 2, false, SPDK_DIF_TYPE1, dif_flags,
2525 				      22, 99, 0xFFFF, 0x22);
2526 	dif_generate_remap_and_verify(iovs, 11, 4096 + 128, 128, 2, true, SPDK_DIF_TYPE1, dif_flags,
2527 				      22, 99, 0xFFFF, 0x22);
2528 
2529 	for (i = 0; i < 11; i++) {
2530 		_iov_free_buf(&iovs[i]);
2531 	}
2532 }
2533 
2534 static void
2535 dix_generate_remap_and_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
2536 			      uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
2537 			      bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
2538 			      uint32_t init_ref_tag, uint32_t remapped_init_ref_tag,
2539 			      uint16_t apptag_mask, uint16_t app_tag)
2540 {
2541 	struct spdk_dif_ctx ctx;
2542 	int rc;
2543 	struct spdk_dif_ctx_init_ext_opts dif_opts;
2544 
2545 	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, 0, num_blocks);
2546 	CU_ASSERT(rc == 0);
2547 
2548 	dif_opts.size = sizeof(struct spdk_dif_ctx_init_ext_opts);
2549 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
2550 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, false, dif_loc, dif_type, dif_flags,
2551 			       init_ref_tag, apptag_mask, app_tag, 0, GUARD_SEED, &dif_opts);
2552 	CU_ASSERT(rc == 0);
2553 
2554 	rc = spdk_dix_generate(iovs, iovcnt, md_iov, num_blocks, &ctx);
2555 	CU_ASSERT(rc == 0);
2556 
2557 	spdk_dif_ctx_set_remapped_init_ref_tag(&ctx, remapped_init_ref_tag);
2558 
2559 	rc = spdk_dix_remap_ref_tag(md_iov, num_blocks, &ctx, NULL);
2560 	CU_ASSERT(rc == 0);
2561 
2562 	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, false, dif_loc, dif_type, dif_flags,
2563 			       remapped_init_ref_tag, apptag_mask, app_tag, 0, GUARD_SEED, &dif_opts);
2564 	CU_ASSERT(rc == 0);
2565 
2566 	rc = spdk_dix_verify(iovs, iovcnt, md_iov, num_blocks, &ctx, NULL);
2567 	CU_ASSERT(rc == 0);
2568 
2569 	rc = ut_data_pattern_verify(iovs, iovcnt, block_size, 0, num_blocks);
2570 	CU_ASSERT(rc == 0);
2571 }
2572 
2573 static void
2574 dix_sec_4096_md_128_prchk_7_multi_iovs_remap(void)
2575 {
2576 	struct iovec iovs[4], md_iov;
2577 	uint32_t dif_flags;
2578 	int i, num_blocks;
2579 
2580 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
2581 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
2582 
2583 	num_blocks = 0;
2584 
2585 	for (i = 0; i < 4; i++) {
2586 		_iov_alloc_buf(&iovs[i], 4096 * (i + 1));
2587 		num_blocks += i + 1;
2588 	}
2589 	_iov_alloc_buf(&md_iov, 128 * num_blocks);
2590 
2591 	dix_generate_remap_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, false, SPDK_DIF_TYPE1,
2592 				      dif_flags, 22, 99, 0xFFFF, 0x22);
2593 	dix_generate_remap_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, true, SPDK_DIF_TYPE1,
2594 				      dif_flags, 22, 99, 0xFFFF, 0x22);
2595 
2596 	for (i = 0; i < 4; i++) {
2597 		_iov_free_buf(&iovs[i]);
2598 	}
2599 	_iov_free_buf(&md_iov);
2600 }
2601 
2602 static void
2603 dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits_remap(void)
2604 {
2605 	struct iovec iovs[6], md_iov;
2606 	uint32_t dif_flags;
2607 	int i;
2608 
2609 	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
2610 		    SPDK_DIF_FLAGS_REFTAG_CHECK;
2611 
2612 	/* data[0][255:0] */
2613 	_iov_alloc_buf(&iovs[0], 256);
2614 
2615 	/* data[0][511:256], data[1][255:0] */
2616 	_iov_alloc_buf(&iovs[1], 256 + 256);
2617 
2618 	/* data[1][382:256] */
2619 	_iov_alloc_buf(&iovs[2], 128);
2620 
2621 	/* data[1][383] */
2622 	_iov_alloc_buf(&iovs[3], 1);
2623 
2624 	/* data[1][510:384] */
2625 	_iov_alloc_buf(&iovs[4], 126);
2626 
2627 	/* data[1][511], data[2][511:0], data[3][511:0] */
2628 	_iov_alloc_buf(&iovs[5], 1 + 512 * 2);
2629 
2630 	_iov_alloc_buf(&md_iov, 8 * 4);
2631 
2632 	dix_generate_remap_and_verify(iovs, 6, &md_iov, 512, 8, 4, false, SPDK_DIF_TYPE1,
2633 				      dif_flags, 22, 99, 0xFFFF, 0x22);
2634 
2635 	for (i = 0; i < 6; i++) {
2636 		_iov_free_buf(&iovs[i]);
2637 	}
2638 	_iov_free_buf(&md_iov);
2639 }
2640 
2641 int
2642 main(int argc, char **argv)
2643 {
2644 	CU_pSuite	suite = NULL;
2645 	unsigned int	num_failures;
2646 
2647 	CU_set_error_action(CUEA_ABORT);
2648 	CU_initialize_registry();
2649 
2650 	suite = CU_add_suite("dif", NULL, NULL);
2651 
2652 	CU_ADD_TEST(suite, dif_generate_and_verify_test);
2653 	CU_ADD_TEST(suite, dif_disable_check_test);
2654 	CU_ADD_TEST(suite, dif_sec_512_md_0_error_test);
2655 	CU_ADD_TEST(suite, dif_guard_seed_test);
2656 	CU_ADD_TEST(suite, dif_disable_sec_512_md_8_single_iov_test);
2657 	CU_ADD_TEST(suite, dif_sec_512_md_8_prchk_0_single_iov_test);
2658 	CU_ADD_TEST(suite, dif_sec_512_md_8_prchk_0_1_2_4_multi_iovs_test);
2659 	CU_ADD_TEST(suite, dif_sec_4096_md_128_prchk_7_multi_iovs_test);
2660 	CU_ADD_TEST(suite, dif_sec_512_md_8_prchk_7_multi_iovs_split_data_and_md_test);
2661 	CU_ADD_TEST(suite, dif_sec_512_md_8_prchk_7_multi_iovs_split_data_test);
2662 	CU_ADD_TEST(suite, dif_sec_512_md_8_prchk_7_multi_iovs_split_guard_test);
2663 	CU_ADD_TEST(suite, dif_sec_512_md_8_prchk_7_multi_iovs_split_apptag_test);
2664 	CU_ADD_TEST(suite, dif_sec_512_md_8_prchk_7_multi_iovs_split_reftag_test);
2665 	CU_ADD_TEST(suite, dif_sec_512_md_8_prchk_7_multi_iovs_complex_splits_test);
2666 	CU_ADD_TEST(suite, dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_test);
2667 	CU_ADD_TEST(suite, dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test);
2668 	CU_ADD_TEST(suite, dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_data_and_md_test);
2669 	CU_ADD_TEST(suite, dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_data_test);
2670 	CU_ADD_TEST(suite, dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_guard_test);
2671 	CU_ADD_TEST(suite, dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_apptag_test);
2672 	CU_ADD_TEST(suite, dif_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_reftag_test);
2673 	CU_ADD_TEST(suite, dif_copy_sec_512_md_8_prchk_0_single_iov);
2674 	CU_ADD_TEST(suite, dif_copy_sec_512_md_8_prchk_0_1_2_4_multi_iovs);
2675 	CU_ADD_TEST(suite, dif_copy_sec_4096_md_128_prchk_7_multi_iovs);
2676 	CU_ADD_TEST(suite, dif_copy_sec_512_md_8_prchk_7_multi_iovs_split_data);
2677 	CU_ADD_TEST(suite, dif_copy_sec_512_md_8_prchk_7_multi_iovs_complex_splits);
2678 	CU_ADD_TEST(suite, dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test);
2679 	CU_ADD_TEST(suite, dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test);
2680 	CU_ADD_TEST(suite, dix_sec_512_md_0_error);
2681 	CU_ADD_TEST(suite, dix_sec_512_md_8_prchk_0_single_iov);
2682 	CU_ADD_TEST(suite, dix_sec_512_md_8_prchk_0_1_2_4_multi_iovs);
2683 	CU_ADD_TEST(suite, dix_sec_4096_md_128_prchk_7_multi_iovs);
2684 	CU_ADD_TEST(suite, dix_sec_512_md_8_prchk_7_multi_iovs_split_data);
2685 	CU_ADD_TEST(suite, dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits);
2686 	CU_ADD_TEST(suite, dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test);
2687 	CU_ADD_TEST(suite, dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test);
2688 	CU_ADD_TEST(suite, set_md_interleave_iovs_test);
2689 	CU_ADD_TEST(suite, set_md_interleave_iovs_split_test);
2690 	CU_ADD_TEST(suite, dif_generate_stream_test);
2691 	CU_ADD_TEST(suite, set_md_interleave_iovs_alignment_test);
2692 	CU_ADD_TEST(suite, _dif_generate_split_test);
2693 	CU_ADD_TEST(suite, set_md_interleave_iovs_multi_segments_test);
2694 	CU_ADD_TEST(suite, _dif_verify_split_test);
2695 	CU_ADD_TEST(suite, dif_verify_stream_multi_segments_test);
2696 	CU_ADD_TEST(suite, update_crc32c_test);
2697 	CU_ADD_TEST(suite, _dif_update_crc32c_split_test);
2698 	CU_ADD_TEST(suite, dif_update_crc32c_stream_multi_segments_test);
2699 	CU_ADD_TEST(suite, get_range_with_md_test);
2700 	CU_ADD_TEST(suite, dif_sec_4096_md_128_prchk_7_multi_iovs_remap_test);
2701 	CU_ADD_TEST(suite, dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_remap_test);
2702 	CU_ADD_TEST(suite, dix_sec_4096_md_128_prchk_7_multi_iovs_remap);
2703 	CU_ADD_TEST(suite, dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits_remap);
2704 
2705 	CU_basic_set_mode(CU_BRM_VERBOSE);
2706 
2707 	CU_basic_run_tests();
2708 
2709 	num_failures = CU_get_number_of_failures();
2710 	CU_cleanup_registry();
2711 
2712 	return num_failures;
2713 }
2714