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