xref: /spdk/test/accel/dif/dif.c (revision 91fcde065a5883d85ca1034a9a1b254e1eadbcad)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2023 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 
8 #include "spdk/accel.h"
9 #include "spdk/env.h"
10 #include "spdk/log.h"
11 #include "spdk/thread.h"
12 #include "spdk/event.h"
13 #include "spdk/rpc.h"
14 #include "spdk/util.h"
15 #include "spdk/string.h"
16 #include "spdk_internal/cunit.h"
17 
18 #include "CUnit/Basic.h"
19 
20 pthread_mutex_t g_test_mutex;
21 pthread_cond_t g_test_cond;
22 
23 #define WORKER_COUNT 2
24 #define WORKER_IO 0
25 #define WORKER_UT 1
26 
27 static struct spdk_thread *g_thread[WORKER_COUNT];
28 static int g_num_failures = 0;
29 static bool g_shutdown = false;
30 static bool g_completion_success;
31 struct spdk_io_channel	*g_channel = NULL;
32 
33 struct dif_task {
34 	struct iovec		*dst_iovs;
35 	uint32_t		dst_iovcnt;
36 	struct iovec		*src_iovs;
37 	uint32_t		src_iovcnt;
38 	uint32_t		num_blocks; /* used for the DIF related operations */
39 	struct spdk_dif_ctx	dif_ctx;
40 	struct spdk_dif_error	dif_err;
41 };
42 
43 static void
44 execute_spdk_function(spdk_msg_fn fn, void *arg)
45 {
46 	pthread_mutex_lock(&g_test_mutex);
47 	spdk_thread_send_msg(g_thread[WORKER_IO], fn, arg);
48 	pthread_cond_wait(&g_test_cond, &g_test_mutex);
49 	pthread_mutex_unlock(&g_test_mutex);
50 }
51 
52 static void
53 wake_ut_thread(void)
54 {
55 	pthread_mutex_lock(&g_test_mutex);
56 	pthread_cond_signal(&g_test_cond);
57 	pthread_mutex_unlock(&g_test_mutex);
58 }
59 
60 static void
61 exit_io_thread(void *arg)
62 {
63 	assert(spdk_get_thread() == g_thread[WORKER_IO]);
64 	spdk_thread_exit(g_thread[WORKER_IO]);
65 	wake_ut_thread();
66 }
67 
68 #define DATA_PATTERN 0x5A
69 
70 static int g_xfer_size_bytes = 4096;
71 static int g_block_size_bytes = 512;
72 static int g_md_size_bytes = 8;
73 struct dif_task g_dif_task;
74 
75 struct accel_dif_request {
76 	struct spdk_io_channel *channel;
77 	struct iovec *dst_iovs;
78 	size_t dst_iovcnt;
79 	struct iovec *src_iovs;
80 	size_t src_iovcnt;
81 	uint32_t num_blocks;
82 	const struct spdk_dif_ctx *ctx;
83 	struct spdk_dif_error *err;
84 	spdk_accel_completion_cb cb_fn;
85 	void *cb_arg;
86 };
87 
88 static void
89 accel_dif_oper_done(void *arg1, int status)
90 {
91 	if (status == 0) {
92 		g_completion_success = true;
93 	}
94 	wake_ut_thread();
95 }
96 
97 static bool
98 accel_dif_error_validate(const uint32_t dif_flags,
99 			 const struct spdk_dif_error *err)
100 {
101 	switch (dif_flags) {
102 	case SPDK_DIF_FLAGS_GUARD_CHECK:
103 		return err->err_type == SPDK_DIF_GUARD_ERROR;
104 	case SPDK_DIF_FLAGS_APPTAG_CHECK:
105 		return err->err_type == SPDK_DIF_APPTAG_ERROR;
106 	case SPDK_DIF_FLAGS_REFTAG_CHECK:
107 		return err->err_type == SPDK_DIF_REFTAG_ERROR;
108 	default:
109 		return false;
110 	}
111 }
112 
113 static int
114 alloc_dif_verify_bufs(struct dif_task *task, uint32_t chained_count)
115 {
116 	int src_buff_len = g_xfer_size_bytes;
117 	uint32_t i = 0;
118 
119 	assert(chained_count > 0);
120 	task->src_iovcnt = chained_count;
121 	task->src_iovs = calloc(task->src_iovcnt, sizeof(struct iovec));
122 	if (spdk_unlikely(task->src_iovs == NULL)) {
123 		return -ENOMEM;
124 	}
125 
126 	src_buff_len += (g_xfer_size_bytes / g_block_size_bytes) * g_md_size_bytes;
127 
128 	for (i = 0; i < task->src_iovcnt; i++) {
129 		task->src_iovs[i].iov_base = spdk_dma_zmalloc(src_buff_len, 0, NULL);
130 		if (spdk_unlikely(task->src_iovs[i].iov_base == NULL)) {
131 			return -ENOMEM;
132 		}
133 
134 		memset(task->src_iovs[i].iov_base, DATA_PATTERN, src_buff_len);
135 		task->src_iovs[i].iov_len = src_buff_len;
136 	}
137 
138 	task->num_blocks = (g_xfer_size_bytes * chained_count) / g_block_size_bytes;
139 
140 	return 0;
141 }
142 
143 static void
144 free_dif_verify_bufs(struct dif_task *task)
145 {
146 	uint32_t i = 0;
147 
148 	if (task->src_iovs != NULL) {
149 		for (i = 0; i < task->src_iovcnt; i++) {
150 			if (task->src_iovs[i].iov_base != NULL) {
151 				spdk_dma_free(task->src_iovs[i].iov_base);
152 			}
153 		}
154 		free(task->src_iovs);
155 	}
156 }
157 
158 static int
159 alloc_dif_verify_copy_bufs(struct dif_task *task, uint32_t chained_count)
160 {
161 	int dst_buff_len = g_xfer_size_bytes;
162 	uint32_t data_size_with_md;
163 	uint32_t i = 0;
164 
165 	assert(chained_count > 0);
166 	task->src_iovcnt = chained_count;
167 	task->src_iovs = calloc(task->src_iovcnt, sizeof(struct iovec));
168 	if (spdk_unlikely(task->src_iovs == NULL)) {
169 		return -ENOMEM;
170 	}
171 
172 	task->num_blocks = g_xfer_size_bytes / g_block_size_bytes;
173 
174 	/* Add bytes for each block for metadata */
175 	data_size_with_md = g_xfer_size_bytes + (task->num_blocks * g_md_size_bytes);
176 
177 	for (i = 0; i < task->src_iovcnt; i++) {
178 		task->src_iovs[i].iov_base = spdk_dma_zmalloc(data_size_with_md, 0, NULL);
179 		if (spdk_unlikely(task->src_iovs[i].iov_base == NULL)) {
180 			return -ENOMEM;
181 		}
182 
183 		memset(task->src_iovs[i].iov_base, DATA_PATTERN, data_size_with_md);
184 		task->src_iovs[i].iov_len = data_size_with_md;
185 	}
186 
187 	task->dst_iovcnt = chained_count;
188 	task->dst_iovs = calloc(task->dst_iovcnt, sizeof(struct iovec));
189 	if (spdk_unlikely(task->dst_iovs == NULL)) {
190 		return -ENOMEM;
191 	}
192 
193 	for (i = 0; i < task->dst_iovcnt; i++) {
194 		task->dst_iovs[i].iov_base = spdk_dma_zmalloc(dst_buff_len, 0, NULL);
195 		if (spdk_unlikely(task->dst_iovs[i].iov_base == NULL)) {
196 			return -ENOMEM;
197 		}
198 
199 		memset(task->dst_iovs[i].iov_base, 0, dst_buff_len);
200 		task->dst_iovs[i].iov_len = dst_buff_len;
201 	}
202 
203 	return 0;
204 }
205 
206 static void
207 free_dif_verify_copy_bufs(struct dif_task *task)
208 {
209 	uint32_t i = 0;
210 
211 	if (task->dst_iovs != NULL) {
212 		for (i = 0; i < task->dst_iovcnt; i++) {
213 			if (task->dst_iovs[i].iov_base != NULL) {
214 				spdk_dma_free(task->dst_iovs[i].iov_base);
215 			}
216 		}
217 		free(task->dst_iovs);
218 	}
219 
220 	if (task->src_iovs != NULL) {
221 		for (i = 0; i < task->src_iovcnt; i++) {
222 			if (task->src_iovs[i].iov_base != NULL) {
223 				spdk_dma_free(task->src_iovs[i].iov_base);
224 			}
225 		}
226 		free(task->src_iovs);
227 	}
228 }
229 
230 static int
231 alloc_dif_generate_copy_bufs(struct dif_task *task, uint32_t chained_count)
232 {
233 	int src_buff_len = g_xfer_size_bytes;
234 	uint32_t transfer_size_with_md;
235 	uint32_t i = 0;
236 
237 	assert(chained_count > 0);
238 	task->dst_iovcnt = chained_count;
239 	task->dst_iovs = calloc(task->dst_iovcnt, sizeof(struct iovec));
240 	if (spdk_unlikely(task->dst_iovs == NULL)) {
241 		return -ENOMEM;
242 	}
243 
244 	task->num_blocks = g_xfer_size_bytes / g_block_size_bytes;
245 
246 	/* Add bytes for each block for metadata */
247 	transfer_size_with_md = g_xfer_size_bytes + (task->num_blocks * g_md_size_bytes);
248 
249 	for (i = 0; i < task->dst_iovcnt; i++) {
250 		task->dst_iovs[i].iov_base = spdk_dma_zmalloc(transfer_size_with_md, 0, NULL);
251 		if (spdk_unlikely(task->dst_iovs[i].iov_base == NULL)) {
252 			return -ENOMEM;
253 		}
254 
255 		memset(task->dst_iovs[i].iov_base, 0, transfer_size_with_md);
256 		task->dst_iovs[i].iov_len = transfer_size_with_md;
257 	}
258 
259 	task->src_iovcnt = chained_count;
260 	task->src_iovs = calloc(task->src_iovcnt, sizeof(struct iovec));
261 	if (spdk_unlikely(task->src_iovs == NULL)) {
262 		return -ENOMEM;
263 	}
264 
265 	for (i = 0; i < task->src_iovcnt; i++) {
266 		task->src_iovs[i].iov_base = spdk_dma_zmalloc(src_buff_len, 0, NULL);
267 		if (spdk_unlikely(task->src_iovs[i].iov_base == NULL)) {
268 			return -ENOMEM;
269 		}
270 
271 		memset(task->src_iovs[i].iov_base, DATA_PATTERN, src_buff_len);
272 		task->src_iovs[i].iov_len = src_buff_len;
273 	}
274 
275 	return 0;
276 }
277 
278 static void
279 free_dif_generate_copy_bufs(struct dif_task *task)
280 {
281 	uint32_t i = 0;
282 
283 	if (task->dst_iovs != NULL) {
284 		for (i = 0; i < task->dst_iovcnt; i++) {
285 			if (task->dst_iovs[i].iov_base != NULL) {
286 				spdk_dma_free(task->dst_iovs[i].iov_base);
287 			}
288 		}
289 		free(task->dst_iovs);
290 	}
291 
292 	if (task->src_iovs != NULL) {
293 		for (i = 0; i < task->src_iovcnt; i++) {
294 			if (task->src_iovs[i].iov_base != NULL) {
295 				spdk_dma_free(task->src_iovs[i].iov_base);
296 			}
297 		}
298 		free(task->src_iovs);
299 	}
300 }
301 
302 static void
303 accel_dif_verify_test(void *arg)
304 {
305 	int rc;
306 	struct accel_dif_request *req = arg;
307 
308 	g_completion_success = false;
309 	rc = spdk_accel_submit_dif_verify(req->channel, req->src_iovs, req->src_iovcnt,
310 					  req->num_blocks, req->ctx, req->err,
311 					  req->cb_fn, req->cb_arg);
312 	if (rc) {
313 		wake_ut_thread();
314 	}
315 }
316 
317 static void
318 accel_dif_verify_copy_test(void *arg)
319 {
320 	int rc;
321 	struct accel_dif_request *req = arg;
322 
323 	g_completion_success = false;
324 	rc = spdk_accel_submit_dif_verify_copy(req->channel, req->dst_iovs, req->dst_iovcnt,
325 					       req->src_iovs, req->src_iovcnt,
326 					       req->num_blocks, req->ctx, req->err,
327 					       req->cb_fn, req->cb_arg);
328 	if (rc) {
329 		wake_ut_thread();
330 	}
331 }
332 
333 static void
334 accel_dif_generate_copy_test(void *arg)
335 {
336 	int rc;
337 	struct accel_dif_request *req = arg;
338 
339 	g_completion_success = false;
340 	rc = spdk_accel_submit_dif_generate_copy(req->channel, req->dst_iovs, req->dst_iovcnt,
341 			req->src_iovs, req->src_iovcnt, req->num_blocks, req->ctx,
342 			req->cb_fn, req->cb_arg);
343 	if (rc) {
344 		wake_ut_thread();
345 	}
346 }
347 
348 static void
349 accel_dif_verify_op_dif_generated_do_check(uint32_t dif_flags)
350 {
351 	struct spdk_dif_ctx_init_ext_opts dif_opts;
352 	struct accel_dif_request req;
353 	struct dif_task *task = &g_dif_task;
354 	int rc;
355 
356 	rc = alloc_dif_verify_bufs(task, 1);
357 	SPDK_CU_ASSERT_FATAL(rc == 0);
358 
359 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
360 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
361 
362 	rc = spdk_dif_ctx_init(&task->dif_ctx,
363 			       g_block_size_bytes + g_md_size_bytes,
364 			       g_md_size_bytes, true, true,
365 			       SPDK_DIF_TYPE1,
366 			       SPDK_DIF_FLAGS_GUARD_CHECK |
367 			       SPDK_DIF_FLAGS_APPTAG_CHECK |
368 			       SPDK_DIF_FLAGS_REFTAG_CHECK,
369 			       10, 0xFFFF, 20, 0, 0, &dif_opts);
370 	SPDK_CU_ASSERT_FATAL(rc == 0);
371 
372 	rc = spdk_dif_generate(task->src_iovs, task->src_iovcnt, task->num_blocks, &task->dif_ctx);
373 	SPDK_CU_ASSERT_FATAL(rc == 0);
374 
375 	rc = spdk_dif_ctx_init(&task->dif_ctx,
376 			       g_block_size_bytes + g_md_size_bytes,
377 			       g_md_size_bytes, true, true,
378 			       SPDK_DIF_TYPE1,
379 			       dif_flags,
380 			       10, 0xFFFF, 20, 0, 0, &dif_opts);
381 	SPDK_CU_ASSERT_FATAL(rc == 0);
382 
383 	req.channel = g_channel;
384 	req.src_iovs = task->src_iovs;
385 	req.src_iovcnt = task->src_iovcnt;
386 	req.num_blocks = task->num_blocks;
387 	req.ctx = &task->dif_ctx;
388 	req.err = &task->dif_err;
389 	req.cb_fn = accel_dif_oper_done;
390 	req.cb_arg = task;
391 
392 	execute_spdk_function(accel_dif_verify_test, &req);
393 	CU_ASSERT_EQUAL(g_completion_success, true);
394 
395 	free_dif_verify_bufs(task);
396 }
397 
398 static void
399 accel_dif_verify_op_dif_generated_guard_check(void)
400 {
401 	accel_dif_verify_op_dif_generated_do_check(SPDK_DIF_FLAGS_GUARD_CHECK);
402 }
403 
404 static void
405 accel_dif_verify_op_dif_generated_apptag_check(void)
406 {
407 	accel_dif_verify_op_dif_generated_do_check(SPDK_DIF_FLAGS_APPTAG_CHECK);
408 }
409 
410 static void
411 accel_dif_verify_op_dif_generated_reftag_check(void)
412 {
413 	accel_dif_verify_op_dif_generated_do_check(SPDK_DIF_FLAGS_REFTAG_CHECK);
414 }
415 
416 static void
417 accel_dif_verify_op_dif_not_generated_do_check(uint32_t dif_flags)
418 {
419 	struct spdk_dif_ctx_init_ext_opts dif_opts;
420 	struct accel_dif_request req;
421 	struct dif_task *task = &g_dif_task;
422 	int rc;
423 
424 	rc = alloc_dif_verify_bufs(task, 1);
425 	SPDK_CU_ASSERT_FATAL(rc == 0);
426 
427 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
428 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
429 
430 	rc = spdk_dif_ctx_init(&task->dif_ctx,
431 			       g_block_size_bytes + g_md_size_bytes,
432 			       g_md_size_bytes, true, true,
433 			       SPDK_DIF_TYPE1,
434 			       dif_flags,
435 			       10, 0xFFFF, 20, 0, 0, &dif_opts);
436 	SPDK_CU_ASSERT_FATAL(rc == 0);
437 
438 	req.channel = g_channel;
439 	req.src_iovs = task->src_iovs;
440 	req.src_iovcnt = task->src_iovcnt;
441 	req.num_blocks = task->num_blocks;
442 	req.ctx = &task->dif_ctx;
443 	req.err = &task->dif_err;
444 	req.cb_fn = accel_dif_oper_done;
445 	req.cb_arg = task;
446 
447 	execute_spdk_function(accel_dif_verify_test, &req);
448 	CU_ASSERT_EQUAL(g_completion_success, false);
449 	CU_ASSERT_EQUAL(accel_dif_error_validate(dif_flags, req.err), true);
450 
451 	free_dif_verify_bufs(task);
452 }
453 
454 static void
455 accel_dif_verify_op_dif_not_generated_guard_check(void)
456 {
457 	accel_dif_verify_op_dif_not_generated_do_check(SPDK_DIF_FLAGS_GUARD_CHECK);
458 }
459 
460 static void
461 accel_dif_verify_op_dif_not_generated_apptag_check(void)
462 {
463 	accel_dif_verify_op_dif_not_generated_do_check(SPDK_DIF_FLAGS_APPTAG_CHECK);
464 }
465 
466 static void
467 accel_dif_verify_op_dif_not_generated_reftag_check(void)
468 {
469 	accel_dif_verify_op_dif_not_generated_do_check(SPDK_DIF_FLAGS_REFTAG_CHECK);
470 }
471 
472 static void
473 accel_dif_verify_op_apptag_correct_apptag_check(void)
474 {
475 	struct spdk_dif_ctx_init_ext_opts dif_opts;
476 	struct accel_dif_request req;
477 	struct dif_task *task = &g_dif_task;
478 	int rc;
479 
480 	rc = alloc_dif_verify_bufs(task, 1);
481 	SPDK_CU_ASSERT_FATAL(rc == 0);
482 
483 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
484 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
485 
486 	rc = spdk_dif_ctx_init(&task->dif_ctx,
487 			       g_block_size_bytes + g_md_size_bytes,
488 			       g_md_size_bytes, true, true,
489 			       SPDK_DIF_TYPE1,
490 			       SPDK_DIF_FLAGS_APPTAG_CHECK,
491 			       10, 0xFFFF, 20, 0, 0, &dif_opts);
492 	SPDK_CU_ASSERT_FATAL(rc == 0);
493 
494 	rc = spdk_dif_generate(task->src_iovs, task->src_iovcnt, task->num_blocks, &task->dif_ctx);
495 	SPDK_CU_ASSERT_FATAL(rc == 0);
496 
497 	req.channel = g_channel;
498 	req.src_iovs = task->src_iovs;
499 	req.src_iovcnt = task->src_iovcnt;
500 	req.num_blocks = task->num_blocks;
501 	req.ctx = &task->dif_ctx;
502 	req.err = &task->dif_err;
503 	req.cb_fn = accel_dif_oper_done;
504 	req.cb_arg = task;
505 
506 	execute_spdk_function(accel_dif_verify_test, &req);
507 	CU_ASSERT_EQUAL(g_completion_success, true);
508 
509 	free_dif_verify_bufs(task);
510 }
511 
512 static void
513 accel_dif_verify_op_apptag_incorrect_apptag_check(void)
514 {
515 	struct spdk_dif_ctx_init_ext_opts dif_opts;
516 	struct accel_dif_request req;
517 	struct dif_task *task = &g_dif_task;
518 	int rc;
519 
520 	rc = alloc_dif_verify_bufs(task, 1);
521 	SPDK_CU_ASSERT_FATAL(rc == 0);
522 
523 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
524 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
525 
526 	rc = spdk_dif_ctx_init(&task->dif_ctx,
527 			       g_block_size_bytes + g_md_size_bytes,
528 			       g_md_size_bytes, true, true,
529 			       SPDK_DIF_TYPE1,
530 			       SPDK_DIF_FLAGS_APPTAG_CHECK,
531 			       10, 0xFFFF, 20, 0, 0, &dif_opts);
532 	SPDK_CU_ASSERT_FATAL(rc == 0);
533 
534 	rc = spdk_dif_generate(task->src_iovs, task->src_iovcnt, task->num_blocks, &task->dif_ctx);
535 	SPDK_CU_ASSERT_FATAL(rc == 0);
536 
537 	rc = spdk_dif_ctx_init(&task->dif_ctx,
538 			       g_block_size_bytes + g_md_size_bytes,
539 			       g_md_size_bytes, true, true,
540 			       SPDK_DIF_TYPE1,
541 			       SPDK_DIF_FLAGS_APPTAG_CHECK,
542 			       30, 0xFFFF, 40, 0, 0, &dif_opts);
543 	SPDK_CU_ASSERT_FATAL(rc == 0);
544 
545 	req.channel = g_channel;
546 	req.src_iovs = task->src_iovs;
547 	req.src_iovcnt = task->src_iovcnt;
548 	req.num_blocks = task->num_blocks;
549 	req.ctx = &task->dif_ctx;
550 	req.err = &task->dif_err;
551 	req.cb_fn = accel_dif_oper_done;
552 	req.cb_arg = task;
553 
554 	execute_spdk_function(accel_dif_verify_test, &req);
555 	CU_ASSERT_EQUAL(g_completion_success, false);
556 
557 	free_dif_verify_bufs(task);
558 }
559 
560 static void
561 accel_dif_verify_op_tag_incorrect_no_check_or_ignore(uint32_t dif_flags)
562 {
563 	struct spdk_dif_ctx_init_ext_opts dif_opts;
564 	struct accel_dif_request req;
565 	struct dif_task *task = &g_dif_task;
566 	int rc;
567 
568 	rc = alloc_dif_verify_bufs(task, 1);
569 	SPDK_CU_ASSERT_FATAL(rc == 0);
570 
571 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
572 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
573 
574 	/* For set 'Application Tag F Detect' (Source DIF Flags)
575 	 * When all bits of the Application Tag field of the source Data Integrity Field
576 	 * are equal to 1, the Application Tag check is not done and the Guard field and
577 	 * Reference Tag field are ignored. */
578 	rc = spdk_dif_ctx_init(&task->dif_ctx,
579 			       g_block_size_bytes + g_md_size_bytes,
580 			       g_md_size_bytes, true, true,
581 			       SPDK_DIF_TYPE1,
582 			       SPDK_DIF_FLAGS_GUARD_CHECK |
583 			       SPDK_DIF_FLAGS_APPTAG_CHECK |
584 			       SPDK_DIF_FLAGS_REFTAG_CHECK,
585 			       10, 0xFFFF, 0xFFFF, 0, 0, &dif_opts);
586 	SPDK_CU_ASSERT_FATAL(rc == 0);
587 
588 	rc = spdk_dif_generate(task->src_iovs, task->src_iovcnt, task->num_blocks, &task->dif_ctx);
589 	SPDK_CU_ASSERT_FATAL(rc == 0);
590 
591 	rc = spdk_dif_ctx_init(&task->dif_ctx,
592 			       g_block_size_bytes + g_md_size_bytes,
593 			       g_md_size_bytes, true, true,
594 			       SPDK_DIF_TYPE1,
595 			       dif_flags,
596 			       30, 0xFFFF, 40, 0, 0, &dif_opts);
597 	SPDK_CU_ASSERT_FATAL(rc == 0);
598 
599 	req.channel = g_channel;
600 	req.src_iovs = task->src_iovs;
601 	req.src_iovcnt = task->src_iovcnt;
602 	req.num_blocks = task->num_blocks;
603 	req.ctx = &task->dif_ctx;
604 	req.err = &task->dif_err;
605 	req.cb_fn = accel_dif_oper_done;
606 	req.cb_arg = task;
607 
608 	execute_spdk_function(accel_dif_verify_test, &req);
609 	CU_ASSERT_EQUAL(g_completion_success, true);
610 
611 	free_dif_verify_bufs(task);
612 }
613 
614 static void
615 accel_dif_verify_op_apptag_incorrect_no_apptag_check(void)
616 {
617 	accel_dif_verify_op_tag_incorrect_no_check_or_ignore(SPDK_DIF_FLAGS_APPTAG_CHECK);
618 }
619 
620 static void
621 accel_dif_verify_op_reftag_incorrect_reftag_ignore(void)
622 {
623 	accel_dif_verify_op_tag_incorrect_no_check_or_ignore(SPDK_DIF_FLAGS_REFTAG_CHECK);
624 }
625 
626 static void
627 accel_dif_verify_op_reftag_init_correct_reftag_check(void)
628 {
629 	struct spdk_dif_ctx_init_ext_opts dif_opts;
630 	struct accel_dif_request req;
631 	struct dif_task *task = &g_dif_task;
632 	int rc;
633 
634 	rc = alloc_dif_verify_bufs(task, 2);
635 	SPDK_CU_ASSERT_FATAL(rc == 0);
636 
637 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
638 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
639 
640 	rc = spdk_dif_ctx_init(&task->dif_ctx,
641 			       g_block_size_bytes + g_md_size_bytes,
642 			       g_md_size_bytes, true, true,
643 			       SPDK_DIF_TYPE1,
644 			       SPDK_DIF_FLAGS_REFTAG_CHECK,
645 			       10, 0xFFFF, 20, 0, 0, &dif_opts);
646 	SPDK_CU_ASSERT_FATAL(rc == 0);
647 
648 	rc = spdk_dif_generate(task->src_iovs, task->src_iovcnt, task->num_blocks, &task->dif_ctx);
649 	SPDK_CU_ASSERT_FATAL(rc == 0);
650 
651 	req.channel = g_channel;
652 	req.src_iovs = task->src_iovs;
653 	req.src_iovcnt = task->src_iovcnt;
654 	req.num_blocks = task->num_blocks;
655 	req.ctx = &task->dif_ctx;
656 	req.err = &task->dif_err;
657 	req.cb_fn = accel_dif_oper_done;
658 	req.cb_arg = task;
659 
660 	execute_spdk_function(accel_dif_verify_test, &req);
661 	CU_ASSERT_EQUAL(g_completion_success, true);
662 
663 	free_dif_verify_bufs(task);
664 }
665 
666 static void
667 accel_dif_verify_op_reftag_init_incorrect_reftag_check(void)
668 {
669 	struct spdk_dif_ctx_init_ext_opts dif_opts;
670 	struct accel_dif_request req;
671 	struct dif_task *task = &g_dif_task;
672 	int rc;
673 
674 	rc = alloc_dif_verify_bufs(task, 2);
675 	SPDK_CU_ASSERT_FATAL(rc == 0);
676 
677 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
678 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
679 
680 	rc = spdk_dif_ctx_init(&task->dif_ctx,
681 			       g_block_size_bytes + g_md_size_bytes,
682 			       g_md_size_bytes, true, true,
683 			       SPDK_DIF_TYPE1,
684 			       SPDK_DIF_FLAGS_REFTAG_CHECK,
685 			       16, 0xFFFF, 20, 0, 0, &dif_opts);
686 	SPDK_CU_ASSERT_FATAL(rc == 0);
687 
688 	rc = spdk_dif_generate(task->src_iovs, task->src_iovcnt, task->num_blocks, &task->dif_ctx);
689 	SPDK_CU_ASSERT_FATAL(rc == 0);
690 
691 	rc = spdk_dif_ctx_init(&task->dif_ctx,
692 			       g_block_size_bytes + g_md_size_bytes,
693 			       g_md_size_bytes, true, true,
694 			       SPDK_DIF_TYPE1,
695 			       SPDK_DIF_FLAGS_REFTAG_CHECK,
696 			       10, 0xFFFF, 20, 0, 0, &dif_opts);
697 	SPDK_CU_ASSERT_FATAL(rc == 0);
698 
699 	req.channel = g_channel;
700 	req.src_iovs = task->src_iovs;
701 	req.src_iovcnt = task->src_iovcnt;
702 	req.num_blocks = task->num_blocks;
703 	req.ctx = &task->dif_ctx;
704 	req.err = &task->dif_err;
705 	req.cb_fn = accel_dif_oper_done;
706 	req.cb_arg = task;
707 
708 	execute_spdk_function(accel_dif_verify_test, &req);
709 	CU_ASSERT_EQUAL(g_completion_success, false);
710 
711 	free_dif_verify_bufs(task);
712 }
713 
714 static void
715 accel_dif_verify_copy_op_dif_generated_do_check(uint32_t dif_flags)
716 {
717 	struct spdk_dif_ctx_init_ext_opts dif_opts;
718 	struct accel_dif_request req;
719 	struct dif_task *task = &g_dif_task;
720 	int rc;
721 
722 	rc = alloc_dif_verify_copy_bufs(task, 1);
723 	SPDK_CU_ASSERT_FATAL(rc == 0);
724 
725 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
726 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
727 
728 	rc = spdk_dif_ctx_init(&task->dif_ctx,
729 			       g_block_size_bytes + g_md_size_bytes,
730 			       g_md_size_bytes, true, true,
731 			       SPDK_DIF_TYPE1,
732 			       SPDK_DIF_FLAGS_GUARD_CHECK |
733 			       SPDK_DIF_FLAGS_APPTAG_CHECK |
734 			       SPDK_DIF_FLAGS_REFTAG_CHECK,
735 			       10, 0xFFFF, 20, 0, 0, &dif_opts);
736 	SPDK_CU_ASSERT_FATAL(rc == 0);
737 
738 	rc = spdk_dif_generate(task->src_iovs, task->src_iovcnt, task->num_blocks, &task->dif_ctx);
739 	SPDK_CU_ASSERT_FATAL(rc == 0);
740 
741 	rc = spdk_dif_ctx_init(&task->dif_ctx,
742 			       g_block_size_bytes + g_md_size_bytes,
743 			       g_md_size_bytes, true, true,
744 			       SPDK_DIF_TYPE1,
745 			       dif_flags,
746 			       10, 0xFFFF, 20, 0, 0, &dif_opts);
747 	SPDK_CU_ASSERT_FATAL(rc == 0);
748 
749 	req.channel = g_channel;
750 	req.dst_iovs = task->dst_iovs;
751 	req.dst_iovcnt = task->dst_iovcnt;
752 	req.src_iovs = task->src_iovs;
753 	req.src_iovcnt = task->src_iovcnt;
754 	req.num_blocks = task->num_blocks;
755 	req.ctx = &task->dif_ctx;
756 	req.err = &task->dif_err;
757 	req.cb_fn = accel_dif_oper_done;
758 	req.cb_arg = task;
759 
760 	execute_spdk_function(accel_dif_verify_copy_test, &req);
761 	CU_ASSERT_EQUAL(g_completion_success, true);
762 
763 	free_dif_verify_copy_bufs(task);
764 }
765 
766 static void
767 accel_dif_verify_copy_op_dif_generated_guard_check(void)
768 {
769 	accel_dif_verify_copy_op_dif_generated_do_check(SPDK_DIF_FLAGS_GUARD_CHECK);
770 }
771 
772 static void
773 accel_dif_verify_copy_op_dif_generated_apptag_check(void)
774 {
775 	accel_dif_verify_copy_op_dif_generated_do_check(SPDK_DIF_FLAGS_APPTAG_CHECK);
776 }
777 
778 static void
779 accel_dif_verify_copy_op_dif_generated_reftag_check(void)
780 {
781 	accel_dif_verify_copy_op_dif_generated_do_check(SPDK_DIF_FLAGS_REFTAG_CHECK);
782 }
783 
784 static void
785 accel_dif_verify_copy_op_dif_not_generated_do_check(uint32_t dif_flags)
786 {
787 	struct spdk_dif_ctx_init_ext_opts dif_opts;
788 	struct accel_dif_request req;
789 	struct dif_task *task = &g_dif_task;
790 	int rc;
791 
792 	rc = alloc_dif_verify_copy_bufs(task, 1);
793 	SPDK_CU_ASSERT_FATAL(rc == 0);
794 
795 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
796 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
797 
798 	rc = spdk_dif_ctx_init(&task->dif_ctx,
799 			       g_block_size_bytes + g_md_size_bytes,
800 			       g_md_size_bytes, true, true,
801 			       SPDK_DIF_TYPE1,
802 			       dif_flags,
803 			       10, 0xFFFF, 20, 0, 0, &dif_opts);
804 	SPDK_CU_ASSERT_FATAL(rc == 0);
805 
806 	req.channel = g_channel;
807 	req.dst_iovs = task->dst_iovs;
808 	req.dst_iovcnt = task->dst_iovcnt;
809 	req.src_iovs = task->src_iovs;
810 	req.src_iovcnt = task->src_iovcnt;
811 	req.num_blocks = task->num_blocks;
812 	req.ctx = &task->dif_ctx;
813 	req.err = &task->dif_err;
814 	req.cb_fn = accel_dif_oper_done;
815 	req.cb_arg = task;
816 
817 	execute_spdk_function(accel_dif_verify_copy_test, &req);
818 	CU_ASSERT_EQUAL(g_completion_success, false);
819 	CU_ASSERT_EQUAL(accel_dif_error_validate(dif_flags, req.err), true);
820 
821 	free_dif_verify_copy_bufs(task);
822 }
823 
824 static void
825 accel_dif_verify_copy_op_dif_not_generated_guard_check(void)
826 {
827 	accel_dif_verify_copy_op_dif_not_generated_do_check(SPDK_DIF_FLAGS_GUARD_CHECK);
828 }
829 
830 static void
831 accel_dif_verify_copy_op_dif_not_generated_apptag_check(void)
832 {
833 	accel_dif_verify_copy_op_dif_not_generated_do_check(SPDK_DIF_FLAGS_APPTAG_CHECK);
834 }
835 
836 static void
837 accel_dif_verify_copy_op_dif_not_generated_reftag_check(void)
838 {
839 	accel_dif_verify_copy_op_dif_not_generated_do_check(SPDK_DIF_FLAGS_REFTAG_CHECK);
840 }
841 
842 static void
843 accel_dif_generate_copy_op_dif_generated_do_check(uint32_t dif_flags)
844 {
845 	struct spdk_dif_ctx_init_ext_opts dif_opts;
846 	struct accel_dif_request req;
847 	struct dif_task *task = &g_dif_task;
848 	struct spdk_dif_error err_blk;
849 	int rc;
850 
851 	rc = alloc_dif_generate_copy_bufs(task, 1);
852 	SPDK_CU_ASSERT_FATAL(rc == 0);
853 
854 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
855 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
856 
857 	rc = spdk_dif_ctx_init(&task->dif_ctx,
858 			       g_block_size_bytes + g_md_size_bytes,
859 			       g_md_size_bytes, true, true,
860 			       SPDK_DIF_TYPE1,
861 			       SPDK_DIF_FLAGS_GUARD_CHECK |
862 			       SPDK_DIF_FLAGS_APPTAG_CHECK |
863 			       SPDK_DIF_FLAGS_REFTAG_CHECK,
864 			       16, 0xFFFF, 10, 0, 0, &dif_opts);
865 	SPDK_CU_ASSERT_FATAL(rc == 0);
866 
867 	req.channel = g_channel;
868 	req.dst_iovs = task->dst_iovs;
869 	req.dst_iovcnt = task->dst_iovcnt;
870 	req.src_iovs = task->src_iovs;
871 	req.src_iovcnt = task->src_iovcnt;
872 	req.num_blocks = task->num_blocks;
873 	req.ctx = &task->dif_ctx;
874 	req.err = &task->dif_err;
875 	req.cb_fn = accel_dif_oper_done;
876 	req.cb_arg = task;
877 
878 	execute_spdk_function(accel_dif_generate_copy_test, &req);
879 	CU_ASSERT_EQUAL(g_completion_success, true);
880 
881 	rc = spdk_dif_ctx_init(&task->dif_ctx,
882 			       g_block_size_bytes + g_md_size_bytes,
883 			       g_md_size_bytes, true, true,
884 			       SPDK_DIF_TYPE1,
885 			       dif_flags,
886 			       16, 0xFFFF, 10, 0, 0, &dif_opts);
887 	SPDK_CU_ASSERT_FATAL(rc == 0);
888 
889 	rc = spdk_dif_verify(req.dst_iovs, req.dst_iovcnt, req.num_blocks,
890 			     &task->dif_ctx, &err_blk);
891 	SPDK_CU_ASSERT_FATAL(rc == 0);
892 
893 	free_dif_generate_copy_bufs(task);
894 }
895 
896 static void
897 accel_dif_generate_copy_op_dif_generated_guard_check(void)
898 {
899 	accel_dif_generate_copy_op_dif_generated_do_check(SPDK_DIF_FLAGS_GUARD_CHECK);
900 }
901 
902 static void
903 accel_dif_generate_copy_op_dif_generated_apptag_check(void)
904 {
905 	accel_dif_generate_copy_op_dif_generated_do_check(SPDK_DIF_FLAGS_APPTAG_CHECK);
906 }
907 
908 static void
909 accel_dif_generate_copy_op_dif_generated_reftag_check(void)
910 {
911 	accel_dif_generate_copy_op_dif_generated_do_check(SPDK_DIF_FLAGS_REFTAG_CHECK);
912 }
913 
914 static void
915 accel_dif_generate_copy_op_dif_generated_no_guard_check_flag_set(void)
916 {
917 	const char *module_name = NULL;
918 	struct spdk_dif_ctx_init_ext_opts dif_opts;
919 	struct accel_dif_request req;
920 	struct dif_task *task = &g_dif_task;
921 	int rc;
922 
923 	rc = spdk_accel_get_opc_module_name(SPDK_ACCEL_OPC_DIF_GENERATE_COPY, &module_name);
924 	SPDK_CU_ASSERT_FATAL(rc == 0);
925 
926 	rc = alloc_dif_generate_copy_bufs(task, 1);
927 	SPDK_CU_ASSERT_FATAL(rc == 0);
928 
929 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
930 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
931 
932 	rc = spdk_dif_ctx_init(&task->dif_ctx,
933 			       g_block_size_bytes + g_md_size_bytes,
934 			       g_md_size_bytes, true, true,
935 			       SPDK_DIF_TYPE1,
936 			       SPDK_DIF_FLAGS_APPTAG_CHECK |
937 			       SPDK_DIF_FLAGS_REFTAG_CHECK,
938 			       16, 0xFFFF, 10, 0, 0, &dif_opts);
939 	SPDK_CU_ASSERT_FATAL(rc == 0);
940 
941 	req.channel = g_channel;
942 	req.dst_iovs = task->dst_iovs;
943 	req.dst_iovcnt = task->dst_iovcnt;
944 	req.src_iovs = task->src_iovs;
945 	req.src_iovcnt = task->src_iovcnt;
946 	req.num_blocks = task->num_blocks;
947 	req.ctx = &task->dif_ctx;
948 	req.err = &task->dif_err;
949 	req.cb_fn = accel_dif_oper_done;
950 	req.cb_arg = task;
951 
952 	execute_spdk_function(accel_dif_generate_copy_test, &req);
953 
954 	/* Intel DSA does not allow for selective DIF fields generation */
955 	if (!strcmp(module_name, "dsa")) {
956 		CU_ASSERT_EQUAL(g_completion_success, false);
957 	} else if (!strcmp(module_name, "software")) {
958 		CU_ASSERT_EQUAL(g_completion_success, true);
959 	} else {
960 		SPDK_CU_ASSERT_FATAL(false);
961 	}
962 
963 	free_dif_generate_copy_bufs(task);
964 }
965 
966 static void
967 accel_dif_generate_copy_op_dif_generated_no_apptag_check_flag_set(void)
968 {
969 	const char *module_name = NULL;
970 	struct spdk_dif_ctx_init_ext_opts dif_opts;
971 	struct accel_dif_request req;
972 	struct dif_task *task = &g_dif_task;
973 	int rc;
974 
975 	rc = spdk_accel_get_opc_module_name(SPDK_ACCEL_OPC_DIF_GENERATE_COPY, &module_name);
976 	SPDK_CU_ASSERT_FATAL(rc == 0);
977 
978 	rc = alloc_dif_generate_copy_bufs(task, 1);
979 	SPDK_CU_ASSERT_FATAL(rc == 0);
980 
981 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
982 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
983 
984 	rc = spdk_dif_ctx_init(&task->dif_ctx,
985 			       g_block_size_bytes + g_md_size_bytes,
986 			       g_md_size_bytes, true, true,
987 			       SPDK_DIF_TYPE1,
988 			       SPDK_DIF_FLAGS_GUARD_CHECK |
989 			       SPDK_DIF_FLAGS_REFTAG_CHECK,
990 			       16, 0xFFFF, 10, 0, 0, &dif_opts);
991 	SPDK_CU_ASSERT_FATAL(rc == 0);
992 
993 	req.channel = g_channel;
994 	req.dst_iovs = task->dst_iovs;
995 	req.dst_iovcnt = task->dst_iovcnt;
996 	req.src_iovs = task->src_iovs;
997 	req.src_iovcnt = task->src_iovcnt;
998 	req.num_blocks = task->num_blocks;
999 	req.ctx = &task->dif_ctx;
1000 	req.err = &task->dif_err;
1001 	req.cb_fn = accel_dif_oper_done;
1002 	req.cb_arg = task;
1003 
1004 	execute_spdk_function(accel_dif_generate_copy_test, &req);
1005 
1006 	/* Intel DSA does not allow for selective DIF fields generation */
1007 	if (!strcmp(module_name, "dsa")) {
1008 		CU_ASSERT_EQUAL(g_completion_success, false);
1009 	} else if (!strcmp(module_name, "software")) {
1010 		CU_ASSERT_EQUAL(g_completion_success, true);
1011 	} else {
1012 		SPDK_CU_ASSERT_FATAL(false);
1013 	}
1014 
1015 	free_dif_generate_copy_bufs(task);
1016 }
1017 
1018 static void
1019 accel_dif_generate_copy_op_dif_generated_no_reftag_check_flag_set(void)
1020 {
1021 	const char *module_name = NULL;
1022 	struct spdk_dif_ctx_init_ext_opts dif_opts;
1023 	struct accel_dif_request req;
1024 	struct dif_task *task = &g_dif_task;
1025 	int rc;
1026 
1027 	rc = spdk_accel_get_opc_module_name(SPDK_ACCEL_OPC_DIF_GENERATE_COPY, &module_name);
1028 	SPDK_CU_ASSERT_FATAL(rc == 0);
1029 
1030 	rc = alloc_dif_generate_copy_bufs(task, 1);
1031 	SPDK_CU_ASSERT_FATAL(rc == 0);
1032 
1033 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
1034 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
1035 
1036 	rc = spdk_dif_ctx_init(&task->dif_ctx,
1037 			       g_block_size_bytes + g_md_size_bytes,
1038 			       g_md_size_bytes, true, true,
1039 			       SPDK_DIF_TYPE1,
1040 			       SPDK_DIF_FLAGS_GUARD_CHECK |
1041 			       SPDK_DIF_FLAGS_APPTAG_CHECK,
1042 			       16, 0xFFFF, 10, 0, 0, &dif_opts);
1043 	SPDK_CU_ASSERT_FATAL(rc == 0);
1044 
1045 	req.channel = g_channel;
1046 	req.dst_iovs = task->dst_iovs;
1047 	req.dst_iovcnt = task->dst_iovcnt;
1048 	req.src_iovs = task->src_iovs;
1049 	req.src_iovcnt = task->src_iovcnt;
1050 	req.num_blocks = task->num_blocks;
1051 	req.ctx = &task->dif_ctx;
1052 	req.err = &task->dif_err;
1053 	req.cb_fn = accel_dif_oper_done;
1054 	req.cb_arg = task;
1055 
1056 	execute_spdk_function(accel_dif_generate_copy_test, &req);
1057 
1058 	/* Intel DSA does not allow for selective DIF fields generation */
1059 	if (!strcmp(module_name, "dsa")) {
1060 		CU_ASSERT_EQUAL(g_completion_success, false);
1061 	} else if (!strcmp(module_name, "software")) {
1062 		CU_ASSERT_EQUAL(g_completion_success, true);
1063 	} else {
1064 		SPDK_CU_ASSERT_FATAL(false);
1065 	}
1066 
1067 	free_dif_generate_copy_bufs(task);
1068 }
1069 
1070 static void
1071 accel_dif_generate_copy_op_iovecs_len_validate(void)
1072 {
1073 	struct spdk_dif_ctx_init_ext_opts dif_opts;
1074 	struct accel_dif_request req;
1075 	struct dif_task *task = &g_dif_task;
1076 	int rc;
1077 
1078 	rc = alloc_dif_generate_copy_bufs(task, 1);
1079 	SPDK_CU_ASSERT_FATAL(rc == 0);
1080 
1081 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
1082 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
1083 
1084 	rc = spdk_dif_ctx_init(&task->dif_ctx,
1085 			       g_block_size_bytes + g_md_size_bytes,
1086 			       g_md_size_bytes, true, true,
1087 			       SPDK_DIF_TYPE1,
1088 			       SPDK_DIF_FLAGS_GUARD_CHECK |
1089 			       SPDK_DIF_FLAGS_APPTAG_CHECK |
1090 			       SPDK_DIF_FLAGS_REFTAG_CHECK,
1091 			       16, 0xFFFF, 10, 0, 0, &dif_opts);
1092 	SPDK_CU_ASSERT_FATAL(rc == 0);
1093 
1094 	req.channel = g_channel;
1095 	req.dst_iovs = task->dst_iovs;
1096 	/* Make iov_len param incorrect */
1097 	req.dst_iovs->iov_len += 16;
1098 	req.dst_iovcnt = task->dst_iovcnt;
1099 	req.src_iovs = task->src_iovs;
1100 	req.src_iovcnt = task->src_iovcnt;
1101 	req.num_blocks = task->num_blocks;
1102 	req.ctx = &task->dif_ctx;
1103 	req.err = &task->dif_err;
1104 	req.cb_fn = accel_dif_oper_done;
1105 	req.cb_arg = task;
1106 
1107 	execute_spdk_function(accel_dif_generate_copy_test, &req);
1108 	CU_ASSERT_EQUAL(g_completion_success, false);
1109 
1110 	free_dif_generate_copy_bufs(task);
1111 }
1112 
1113 static void
1114 accel_dif_generate_copy_op_buf_align_validate(void)
1115 {
1116 	struct spdk_dif_ctx_init_ext_opts dif_opts;
1117 	struct accel_dif_request req;
1118 	struct dif_task *task = &g_dif_task;
1119 	int rc;
1120 
1121 	rc = alloc_dif_generate_copy_bufs(task, 1);
1122 	SPDK_CU_ASSERT_FATAL(rc == 0);
1123 
1124 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
1125 	dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
1126 
1127 	rc = spdk_dif_ctx_init(&task->dif_ctx,
1128 			       g_block_size_bytes + g_md_size_bytes,
1129 			       g_md_size_bytes, true, true,
1130 			       SPDK_DIF_TYPE1,
1131 			       SPDK_DIF_FLAGS_GUARD_CHECK |
1132 			       SPDK_DIF_FLAGS_APPTAG_CHECK |
1133 			       SPDK_DIF_FLAGS_REFTAG_CHECK,
1134 			       16, 0xFFFF, 10, 0, 0, &dif_opts);
1135 	SPDK_CU_ASSERT_FATAL(rc == 0);
1136 
1137 	req.channel = g_channel;
1138 	req.dst_iovs = task->dst_iovs;
1139 	req.dst_iovcnt = task->dst_iovcnt;
1140 	req.src_iovs = task->src_iovs;
1141 	req.src_iovcnt = task->src_iovcnt;
1142 	req.num_blocks = task->num_blocks;
1143 	req.ctx = &task->dif_ctx;
1144 	req.err = &task->dif_err;
1145 	req.cb_fn = accel_dif_oper_done;
1146 	req.cb_arg = task;
1147 
1148 	execute_spdk_function(accel_dif_generate_copy_test, &req);
1149 	CU_ASSERT_EQUAL(g_completion_success, true);
1150 
1151 	free_dif_generate_copy_bufs(task);
1152 }
1153 
1154 static void
1155 _stop_init_thread(void *arg)
1156 {
1157 	unsigned num_failures = g_num_failures;
1158 
1159 	g_num_failures = 0;
1160 
1161 	assert(spdk_get_thread() == g_thread[WORKER_UT]);
1162 	assert(spdk_thread_is_app_thread(NULL));
1163 	execute_spdk_function(exit_io_thread, NULL);
1164 	spdk_app_stop(num_failures);
1165 }
1166 
1167 static void
1168 stop_init_thread(unsigned num_failures, struct spdk_jsonrpc_request *request)
1169 {
1170 	g_num_failures = num_failures;
1171 
1172 	spdk_thread_send_msg(g_thread[WORKER_UT], _stop_init_thread, request);
1173 }
1174 
1175 static int
1176 setup_accel_tests(void)
1177 {
1178 	unsigned rc = 0;
1179 	CU_pSuite suite = NULL;
1180 
1181 	suite = CU_add_suite("accel_dif", NULL, NULL);
1182 	if (suite == NULL) {
1183 		CU_cleanup_registry();
1184 		rc = CU_get_error();
1185 		return -rc;
1186 	}
1187 
1188 	if (CU_add_test(suite, "verify: DIF generated, GUARD check",
1189 			accel_dif_verify_op_dif_generated_guard_check) == NULL ||
1190 	    CU_add_test(suite, "verify: DIF generated, APPTAG check",
1191 			accel_dif_verify_op_dif_generated_apptag_check) == NULL ||
1192 	    CU_add_test(suite, "verify: DIF generated, REFTAG check",
1193 			accel_dif_verify_op_dif_generated_reftag_check) == NULL ||
1194 
1195 	    CU_add_test(suite, "verify: DIF not generated, GUARD check",
1196 			accel_dif_verify_op_dif_not_generated_guard_check) == NULL ||
1197 	    CU_add_test(suite, "verify: DIF not generated, APPTAG check",
1198 			accel_dif_verify_op_dif_not_generated_apptag_check) == NULL ||
1199 	    CU_add_test(suite, "verify: DIF not generated, REFTAG check",
1200 			accel_dif_verify_op_dif_not_generated_reftag_check) == NULL ||
1201 
1202 	    CU_add_test(suite, "verify: APPTAG correct, APPTAG check",
1203 			accel_dif_verify_op_apptag_correct_apptag_check) == NULL ||
1204 	    CU_add_test(suite, "verify: APPTAG incorrect, APPTAG check",
1205 			accel_dif_verify_op_apptag_incorrect_apptag_check) == NULL ||
1206 	    CU_add_test(suite, "verify: APPTAG incorrect, no APPTAG check",
1207 			accel_dif_verify_op_apptag_incorrect_no_apptag_check) == NULL ||
1208 	    CU_add_test(suite, "verify: REFTAG incorrect, REFTAG ignore",
1209 			accel_dif_verify_op_reftag_incorrect_reftag_ignore) == NULL ||
1210 
1211 	    CU_add_test(suite, "verify: REFTAG_INIT correct, REFTAG check",
1212 			accel_dif_verify_op_reftag_init_correct_reftag_check) == NULL ||
1213 	    CU_add_test(suite, "verify: REFTAG_INIT incorrect, REFTAG check",
1214 			accel_dif_verify_op_reftag_init_incorrect_reftag_check) == NULL ||
1215 
1216 	    CU_add_test(suite, "verify copy: DIF generated, GUARD check",
1217 			accel_dif_verify_copy_op_dif_generated_guard_check) == NULL ||
1218 	    CU_add_test(suite, "verify copy: DIF generated, APPTAG check",
1219 			accel_dif_verify_copy_op_dif_generated_apptag_check) == NULL ||
1220 	    CU_add_test(suite, "verify copy: DIF generated, REFTAG check",
1221 			accel_dif_verify_copy_op_dif_generated_reftag_check) == NULL ||
1222 
1223 	    CU_add_test(suite, "verify copy: DIF not generated, GUARD check",
1224 			accel_dif_verify_copy_op_dif_not_generated_guard_check) == NULL ||
1225 	    CU_add_test(suite, "verify copy: DIF not generated, APPTAG check",
1226 			accel_dif_verify_copy_op_dif_not_generated_apptag_check) == NULL ||
1227 	    CU_add_test(suite, "verify copy: DIF not generated, REFTAG check",
1228 			accel_dif_verify_copy_op_dif_not_generated_reftag_check) == NULL ||
1229 
1230 	    CU_add_test(suite, "generate copy: DIF generated, GUARD check",
1231 			accel_dif_generate_copy_op_dif_generated_guard_check) == NULL ||
1232 	    CU_add_test(suite, "generate copy: DIF generated, APTTAG check",
1233 			accel_dif_generate_copy_op_dif_generated_apptag_check) == NULL ||
1234 	    CU_add_test(suite, "generate copy: DIF generated, REFTAG check",
1235 			accel_dif_generate_copy_op_dif_generated_reftag_check) == NULL ||
1236 
1237 	    CU_add_test(suite, "generate copy: DIF generated, no GUARD check flag set",
1238 			accel_dif_generate_copy_op_dif_generated_no_guard_check_flag_set) == NULL ||
1239 	    CU_add_test(suite, "generate copy: DIF generated, no APPTAG check flag set",
1240 			accel_dif_generate_copy_op_dif_generated_no_apptag_check_flag_set) == NULL ||
1241 	    CU_add_test(suite, "generate copy: DIF generated, no REFTAG check flag set",
1242 			accel_dif_generate_copy_op_dif_generated_no_reftag_check_flag_set) == NULL ||
1243 
1244 	    CU_add_test(suite, "generate copy: iovecs-len validate",
1245 			accel_dif_generate_copy_op_iovecs_len_validate) == NULL ||
1246 	    CU_add_test(suite, "generate copy: buffer alignment validate",
1247 			accel_dif_generate_copy_op_buf_align_validate) == NULL) {
1248 		CU_cleanup_registry();
1249 		rc = CU_get_error();
1250 		return -rc;
1251 	}
1252 	return 0;
1253 }
1254 
1255 static void
1256 get_io_channel(void *arg)
1257 {
1258 	g_channel = spdk_accel_get_io_channel();
1259 	assert(g_channel);
1260 	wake_ut_thread();
1261 }
1262 
1263 static void
1264 put_io_channel(void *arg)
1265 {
1266 	assert(g_channel);
1267 	spdk_put_io_channel(g_channel);
1268 	wake_ut_thread();
1269 }
1270 
1271 static void
1272 run_accel_test_thread(void *arg)
1273 {
1274 	struct spdk_jsonrpc_request *request = arg;
1275 	int rc = 0;
1276 
1277 	execute_spdk_function(get_io_channel, NULL);
1278 	if (g_channel == NULL) {
1279 		fprintf(stderr, "Unable to get an accel channel\n");
1280 		goto ret;
1281 	}
1282 
1283 	if (CU_initialize_registry() != CUE_SUCCESS) {
1284 		/* CUnit error, probably won't recover */
1285 		rc = CU_get_error();
1286 		rc = -rc;
1287 		goto ret;
1288 	}
1289 
1290 	rc = setup_accel_tests();
1291 	if (rc < 0) {
1292 		/* CUnit error, probably won't recover */
1293 		rc = -rc;
1294 		goto ret;
1295 	}
1296 	CU_basic_set_mode(CU_BRM_VERBOSE);
1297 	CU_basic_run_tests();
1298 	rc = CU_get_number_of_failures();
1299 	CU_cleanup_registry();
1300 
1301 ret:
1302 	if (g_channel != NULL) {
1303 		execute_spdk_function(put_io_channel, NULL);
1304 	}
1305 	stop_init_thread(rc, request);
1306 }
1307 
1308 static void
1309 accel_dif_test_main(void *arg1)
1310 {
1311 	struct spdk_cpuset tmpmask = {};
1312 	uint32_t i;
1313 
1314 	pthread_mutex_init(&g_test_mutex, NULL);
1315 	pthread_cond_init(&g_test_cond, NULL);
1316 
1317 	/* This test runs specifically on at least two cores.
1318 	 * g_thread[WORKER_UT] is the app_thread on main core from event framework.
1319 	 * Next one is only for the tests and should always be on separate CPU cores. */
1320 	if (spdk_env_get_core_count() < 3) {
1321 		spdk_app_stop(-1);
1322 		return;
1323 	}
1324 
1325 	SPDK_ENV_FOREACH_CORE(i) {
1326 		if (i == spdk_env_get_current_core()) {
1327 			g_thread[WORKER_UT] = spdk_get_thread();
1328 			continue;
1329 		}
1330 		spdk_cpuset_zero(&tmpmask);
1331 		spdk_cpuset_set_cpu(&tmpmask, i, true);
1332 		if (g_thread[WORKER_IO] == NULL) {
1333 			g_thread[WORKER_IO] = spdk_thread_create("io_thread", &tmpmask);
1334 		}
1335 
1336 	}
1337 
1338 	spdk_thread_send_msg(g_thread[WORKER_UT], run_accel_test_thread, NULL);
1339 }
1340 
1341 static void
1342 accel_dif_usage(void)
1343 {
1344 }
1345 
1346 static int
1347 accel_dif_parse_arg(int ch, char *arg)
1348 {
1349 	return 0;
1350 }
1351 
1352 static void
1353 spdk_dif_shutdown_cb(void)
1354 {
1355 	g_shutdown = true;
1356 	spdk_thread_send_msg(g_thread[WORKER_UT], _stop_init_thread, NULL);
1357 }
1358 
1359 int
1360 main(int argc, char **argv)
1361 {
1362 	struct spdk_app_opts opts = {};
1363 	char reactor_mask[8];
1364 	int rc;
1365 
1366 	spdk_app_opts_init(&opts, sizeof(opts));
1367 	opts.name = "DIF";
1368 	snprintf(reactor_mask, sizeof(reactor_mask), "0x%x", (1 << (SPDK_COUNTOF(g_thread) + 1)) - 1);
1369 	opts.reactor_mask = reactor_mask;
1370 	opts.shutdown_cb = spdk_dif_shutdown_cb;
1371 	opts.rpc_addr = NULL;
1372 
1373 	if ((rc = spdk_app_parse_args(argc, argv, &opts, "", NULL,
1374 				      accel_dif_parse_arg, accel_dif_usage)) !=
1375 	    SPDK_APP_PARSE_ARGS_SUCCESS) {
1376 		return rc;
1377 	}
1378 
1379 	rc = spdk_app_start(&opts, accel_dif_test_main, NULL);
1380 	spdk_app_fini();
1381 
1382 	return rc;
1383 }
1384