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