[Accel-config] Re: [PATCH v2 6/7] accel-config/test: add 4 dif operations support

Dave Jiang <dave.jiang at intel.com> Thu, 17 Feb 2022 14:46:21 -0700
Newsgroups dev.linux.lists.accel-config
Message-ID <[email protected]>
On 2/16/2022 5:26 AM, Tony Zhu wrote:
> Add Data Integrity Field (DIF) check, insert, strip, and update
> operation support while transferring data.
>
> Signed-off-by: Tony Zhu <tony.zhu(a)intel.com>
> ---
>   test/dsa.c      | 729 ++++++++++++++++++++++++++++++++++++++++++++++++
>   test/dsa.h      |  44 +++
>   test/dsa_test.c | 104 +++++++
>   test/prep.c     | 189 +++++++++++++
>   4 files changed, 1066 insertions(+)
>
> diff --git a/test/dsa.c b/test/dsa.c
> index 9a10267..cc8cb2c 100644
> --- a/test/dsa.c
> +++ b/test/dsa.c
> @@ -23,6 +23,37 @@ unsigned int ms_timeout = 5000;
>   int debug_logging;
>   static int umwait_support;
>   
> +unsigned int dif_blk_arr[] = {512, 520, 4096, 4104};
> +
> +/*ANINDYA Logic to get blk_sz_flg*/

What is ANINDYA?


> +int get_dif_blksz_flg(unsigned long xfer_size)
> +{
> +	int blk_idx_flg = 3;
> +
> +	while (blk_idx_flg) {
> +		if (xfer_size % dif_blk_arr[blk_idx_flg] == 0)
> +			break;
> +		blk_idx_flg--;
> +	}
> +	return blk_idx_flg;
> +}
> +
> +/* ASD Logic */

What is ASD? And what is this comment trying to say?

DJ

> +unsigned long get_blks(unsigned long xfer_size)
> +{
> +	int blk_idx_flg = 3;
> +	unsigned long num_blks;
> +
> +	while (blk_idx_flg) {
> +		if (xfer_size % dif_blk_arr[blk_idx_flg] == 0)
> +			break;
> +		blk_idx_flg--;
> +	}
> +
> +	num_blks = xfer_size / dif_blk_arr[blk_idx_flg];
> +	return num_blks;
> +}
> +
>   static inline void cpuid(unsigned int *eax, unsigned int *ebx,
>   			 unsigned int *ecx, unsigned int *edx)
>   {
> @@ -477,6 +508,196 @@ int init_copy_crc(struct task *tsk, int tflags, int opcode, unsigned long xfer_s
>   	return DSA_STATUS_OK;
>   }
>   
> +int init_dif_check(struct task *tsk, int tflags, int opcode, unsigned long xfer_size)
> +{
> +	unsigned long buf_size;
> +	unsigned long force_align = ADDR_ALIGNMENT;
> +	unsigned char *src;
> +	unsigned int dif_reftag;
> +	unsigned int dif_apptag;
> +	unsigned int dif_guardtag;
> +	unsigned long blks = 0;
> +	unsigned long i;
> +	unsigned long dif_size;
> +
> +	tsk->pattern = 0x0123456789abcdef;
> +	tsk->opcode = opcode;
> +	tsk->test_flags = tflags;
> +	tsk->xfer_size = xfer_size;
> +
> +	tsk->apptag = 0xFACE;
> +	tsk->reftag = 0xABBA;
> +
> +	tsk->blk_idx_flg = get_dif_blksz_flg(tsk->xfer_size);
> +	blks = tsk->xfer_size / dif_blk_arr[tsk->blk_idx_flg];
> +	tsk->blks = blks;
> +
> +	buf_size = tsk->xfer_size / blks;
> +	/* 8 bytes for inclusion of tags */
> +	tsk->xfer_size += 8 * blks;
> +	tsk->src1 = aligned_alloc(force_align, tsk->xfer_size);
> +	if (!tsk->src1)
> +		return -ENOMEM;
> +	src = (unsigned char *)tsk->src1;
> +	dif_reftag = tsk->reftag;
> +	dif_apptag = tsk->apptag;
> +
> +	for (i = 1; i <= blks; i++) {
> +		dif_size = (buf_size + 8) * (i - 1);
> +		memset_pattern((src + dif_size), tsk->pattern, buf_size);
> +		dif_guardtag = dsa_calculate_crc_t10dif((src + dif_size), buf_size, 0);
> +		src[buf_size + DIF_BLK_GRD_1 + dif_size] = (dif_guardtag >> 8) & 0xFF;
> +		src[buf_size + DIF_BLK_GRD_2 + dif_size] = dif_guardtag & 0xFF;
> +		src[buf_size + DIF_APP_TAG_1 + dif_size] = (dif_apptag >> 8) & 0xFF;
> +		src[buf_size + DIF_APP_TAG_2 + dif_size] = (dif_apptag) & 0xFF;
> +		src[buf_size + DIF_REF_TAG_1 + dif_size] = (dif_reftag >> 24) & 0xFF;
> +		src[buf_size + DIF_REF_TAG_2 + dif_size] = (dif_reftag >> 16) & 0xFF;
> +		src[buf_size + DIF_REF_TAG_3 + dif_size] = (dif_reftag >> 8) & 0xFF;
> +		src[buf_size + DIF_REF_TAG_4 + dif_size] = dif_reftag & 0xFF;
> +		dif_reftag++;
> +	}
> +
> +	return DSA_STATUS_OK;
> +}
> +
> +int init_dif_ins(struct task *tsk, int tflags, int opcode, unsigned long xfer_size)
> +{
> +	unsigned long force_align = ADDR_ALIGNMENT;
> +	unsigned long blks = 0;
> +
> +	tsk->pattern = 0x0123456789abcdef;
> +	tsk->opcode = opcode;
> +	tsk->test_flags = tflags;
> +	tsk->xfer_size = xfer_size;
> +
> +	tsk->apptag = 0xFACE;
> +	tsk->reftag = 0xABBA;
> +	tsk->blk_idx_flg = get_dif_blksz_flg(tsk->xfer_size);
> +	blks = tsk->xfer_size / dif_blk_arr[tsk->blk_idx_flg];
> +	tsk->blks = blks;
> +
> +	tsk->src1 = aligned_alloc(force_align, xfer_size);
> +	if (!tsk->src1)
> +		return -ENOMEM;
> +	memset_pattern(tsk->src1, tsk->pattern, xfer_size);
> +	blks = get_blks(xfer_size);
> +	xfer_size += 8 * blks;
> +	tsk->dst1 = aligned_alloc(force_align, xfer_size);
> +	if (!tsk->dst1)
> +		return -ENOMEM;
> +
> +	return DSA_STATUS_OK;
> +}
> +
> +int init_dif_strp(struct task *tsk, int tflags, int opcode, unsigned long xfer_size)
> +{
> +	unsigned long buf_size;
> +	unsigned long force_align = ADDR_ALIGNMENT;
> +	unsigned char *src;
> +	unsigned int dif_reftag;
> +	unsigned int dif_apptag;
> +	unsigned int dif_guardtag;
> +	unsigned long blks = 0;
> +	unsigned long i;
> +	unsigned long dif_size;
> +
> +	tsk->pattern = 0x0123456789abcdef;
> +	tsk->opcode = opcode;
> +	tsk->test_flags = tflags;
> +	tsk->xfer_size = xfer_size;
> +
> +	tsk->apptag = 0xFACE;
> +	tsk->reftag = 0xABBA;
> +
> +	tsk->blk_idx_flg = get_dif_blksz_flg(tsk->xfer_size);
> +	blks = tsk->xfer_size / dif_blk_arr[tsk->blk_idx_flg];
> +	tsk->blks = blks;
> +	buf_size = tsk->xfer_size / blks;
> +	/* 8 bytes for inclusion of tags */
> +	tsk->xfer_size += 8 * blks;
> +	tsk->src1 = aligned_alloc(force_align, tsk->xfer_size);
> +	if (!tsk->src1)
> +		return -ENOMEM;
> +
> +	src = (unsigned char *)tsk->src1;
> +	dif_reftag = tsk->reftag;
> +	dif_apptag = tsk->apptag;
> +
> +	for (i = 1; i <= blks; i++) {
> +		dif_size = (buf_size + 8) * (i - 1);
> +		memset_pattern((src + dif_size), tsk->pattern, buf_size);
> +		dif_guardtag = dsa_calculate_crc_t10dif((src + dif_size), buf_size, 0);
> +		src[buf_size + DIF_BLK_GRD_1 + dif_size] = (dif_guardtag >> 8) & 0xFF;
> +		src[buf_size + DIF_BLK_GRD_2 + dif_size] = dif_guardtag & 0xFF;
> +		src[buf_size + DIF_APP_TAG_1 + dif_size] = (dif_apptag >> 8) & 0xFF;
> +		src[buf_size + DIF_APP_TAG_2 + dif_size] = (dif_apptag) & 0xFF;
> +		src[buf_size + DIF_REF_TAG_1 + dif_size] = (dif_reftag >> 24) & 0xFF;
> +		src[buf_size + DIF_REF_TAG_2 + dif_size] = (dif_reftag >> 16) & 0xFF;
> +		src[buf_size + DIF_REF_TAG_3 + dif_size] = (dif_reftag >> 8) & 0xFF;
> +		src[buf_size + DIF_REF_TAG_4 + dif_size] = dif_reftag & 0xFF;
> +		dif_reftag++;
> +	}
> +
> +	tsk->dst1 = aligned_alloc(force_align, tsk->xfer_size - 8 * blks);
> +	if (!tsk->dst1)
> +		return -ENOMEM;
> +
> +	return DSA_STATUS_OK;
> +}
> +
> +int init_dif_updt(struct task *tsk, int tflags, int opcode, unsigned long xfer_size)
> +{
> +	unsigned long buf_size;
> +	unsigned long force_align = ADDR_ALIGNMENT;
> +	unsigned char *src;
> +	unsigned int dif_reftag;
> +	unsigned int dif_apptag;
> +	unsigned int dif_guardtag;
> +	unsigned long blks = 0;
> +	unsigned long i;
> +	unsigned long dif_size;
> +
> +	tsk->pattern = 0x0123456789abcdef;
> +	tsk->opcode = opcode;
> +	tsk->test_flags = tflags;
> +	tsk->xfer_size = xfer_size;
> +
> +	tsk->apptag = 0xFACE;
> +	tsk->reftag = 0xABBA;
> +
> +	tsk->blk_idx_flg = get_dif_blksz_flg(tsk->xfer_size);
> +	blks = tsk->xfer_size / dif_blk_arr[tsk->blk_idx_flg];
> +	tsk->blks = blks;
> +	buf_size = tsk->xfer_size / blks;
> +	tsk->xfer_size += 8 * blks;
> +	tsk->src1 = aligned_alloc(force_align, tsk->xfer_size);
> +	if (!tsk->src1)
> +		return -ENOMEM;
> +
> +	src = (unsigned char *)tsk->src1;
> +	dif_reftag = tsk->reftag;
> +	dif_apptag = tsk->apptag;
> +
> +	for (i = 1; i <= blks; i++) {
> +		dif_size = (buf_size + 8) * (i - 1);
> +		memset_pattern((src + dif_size), tsk->pattern, buf_size);
> +		dif_guardtag = dsa_calculate_crc_t10dif((src + dif_size), buf_size, 0);
> +		src[buf_size + DIF_BLK_GRD_1 + dif_size] = (dif_guardtag >> 8) & 0xFF;
> +		src[buf_size + DIF_BLK_GRD_2 + dif_size] = dif_guardtag & 0xFF;
> +		src[buf_size + DIF_APP_TAG_1 + dif_size] = (dif_apptag >> 8) & 0xFF;
> +		src[buf_size + DIF_APP_TAG_2 + dif_size] = (dif_apptag) & 0xFF;
> +		src[buf_size + DIF_REF_TAG_1 + dif_size] = (dif_reftag >> 24) & 0xFF;
> +		src[buf_size + DIF_REF_TAG_2 + dif_size] = (dif_reftag >> 16) & 0xFF;
> +		src[buf_size + DIF_REF_TAG_3 + dif_size] = (dif_reftag >> 8) & 0xFF;
> +		src[buf_size + DIF_REF_TAG_4 + dif_size] = dif_reftag & 0xFF;
> +	}
> +	tsk->dst1 = aligned_alloc(force_align, tsk->xfer_size);
> +	if (!tsk->dst1)
> +		return -ENOMEM;
> +
> +	return DSA_STATUS_OK;
> +}
> +
>   /* this function is re-used by batch task */
>   int init_task(struct task *tsk, int tflags, int opcode,
>   	      unsigned long xfer_size)
> @@ -520,6 +741,22 @@ int init_task(struct task *tsk, int tflags, int opcode,
>   	case DSA_OPCODE_COPY_CRC:
>   		rc = init_copy_crc(tsk, tflags, opcode, xfer_size);
>   		break;
> +
> +	case DSA_OPCODE_DIF_CHECK:
> +		rc = init_dif_check(tsk, tflags, opcode, xfer_size);
> +		break;
> +
> +	case DSA_OPCODE_DIF_INS:
> +		rc = init_dif_ins(tsk, tflags, opcode, xfer_size);
> +		break;
> +
> +	case DSA_OPCODE_DIF_STRP:
> +		rc = init_dif_strp(tsk, tflags, opcode, xfer_size);
> +		break;
> +
> +	case DSA_OPCODE_DIF_UPDT:
> +		rc = init_dif_updt(tsk, tflags, opcode, xfer_size);
> +		break;
>   	}
>   
>   	if (rc != DSA_STATUS_OK) {
> @@ -1441,6 +1678,158 @@ int dsa_crc_copy_multi_task_nodes(struct dsa_context *ctx)
>   	return ret;
>   }
>   
> +int dsa_wait_dif(struct dsa_context *ctx, struct task *tsk)
> +{
> +	struct dsa_hw_desc *desc = tsk->desc;
> +	struct dsa_completion_record *comp = tsk->comp;
> +	int rc;
> +
> +again:
> +	rc = dsa_wait_on_desc_timeout(comp, ms_timeout);
> +	if (rc < 0) {
> +		err("DIF desc timeout\n");
> +		return DSA_STATUS_TIMEOUT;
> +	}
> +
> +	/* re-submit if PAGE_FAULT reported by HW && BOF is off */
> +	if (stat_val(comp->status) == DSA_COMP_PAGE_FAULT_NOBOF &&
> +	    !(desc->flags & IDXD_OP_FLAG_BOF)) {
> +		task_result_verify(tsk, 0);
> +		dsa_reprep_dif(ctx, tsk);
> +		goto again;
> +	}
> +
> +	return DSA_STATUS_OK;
> +}
> +
> +int dsa_dif_check_multi_task_nodes(struct dsa_context *ctx)
> +{
> +	struct task_node *tsk_node = ctx->multi_task_node;
> +	int ret = DSA_STATUS_OK;
> +
> +	while (tsk_node) {
> +		tsk_node->tsk->dflags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR;
> +		if ((tsk_node->tsk->test_flags & TEST_FLAGS_BOF) && ctx->bof)
> +			tsk_node->tsk->dflags |= IDXD_OP_FLAG_BOF;
> +
> +		dsa_prep_dif_check(tsk_node->tsk);
> +		tsk_node = tsk_node->next;
> +	}
> +
> +	tsk_node = ctx->multi_task_node;
> +	while (tsk_node) {
> +		dsa_desc_submit(ctx, tsk_node->tsk->desc);
> +		tsk_node = tsk_node->next;
> +	}
> +
> +	info("Submitted all dif check jobs\n");
> +	tsk_node = ctx->multi_task_node;
> +	while (tsk_node) {
> +		ret = dsa_wait_dif(ctx, tsk_node->tsk);
> +		if (ret != DSA_STATUS_OK)
> +			info("Desc: %p failed with ret: %d\n", tsk_node->tsk->desc,
> +			     tsk_node->tsk->comp->status);
> +		tsk_node = tsk_node->next;
> +	}
> +	return ret;
> +}
> +
> +int dsa_dif_ins_multi_task_nodes(struct dsa_context *ctx)
> +{
> +	struct task_node *tsk_node = ctx->multi_task_node;
> +	int ret = DSA_STATUS_OK;
> +
> +	while (tsk_node) {
> +		tsk_node->tsk->dflags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR;
> +		if ((tsk_node->tsk->test_flags & TEST_FLAGS_BOF) && ctx->bof)
> +			tsk_node->tsk->dflags |= IDXD_OP_FLAG_BOF;
> +
> +		dsa_prep_dif_insert(tsk_node->tsk);
> +		tsk_node = tsk_node->next;
> +	}
> +
> +	tsk_node = ctx->multi_task_node;
> +	while (tsk_node) {
> +		dsa_desc_submit(ctx, tsk_node->tsk->desc);
> +		tsk_node = tsk_node->next;
> +	}
> +	tsk_node = ctx->multi_task_node;
> +	info("Submitted all dif insert jobs\n");
> +	while (tsk_node) {
> +		ret = dsa_wait_dif(ctx, tsk_node->tsk);
> +		if (ret != DSA_STATUS_OK)
> +			info("Desc: %p failed with ret: %d\n", tsk_node->tsk->desc,
> +			     tsk_node->tsk->comp->status);
> +		tsk_node = tsk_node->next;
> +	}
> +	return ret;
> +}
> +
> +int dsa_dif_strp_multi_task_nodes(struct dsa_context *ctx)
> +{
> +	struct task_node *tsk_node = ctx->multi_task_node;
> +	int ret = DSA_STATUS_OK;
> +
> +	while (tsk_node) {
> +		tsk_node->tsk->dflags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR;
> +		if ((tsk_node->tsk->test_flags & TEST_FLAGS_BOF) && ctx->bof)
> +			tsk_node->tsk->dflags |= IDXD_OP_FLAG_BOF;
> +
> +		dsa_prep_dif_strip(tsk_node->tsk);
> +		tsk_node = tsk_node->next;
> +	}
> +
> +	tsk_node = ctx->multi_task_node;
> +	while (tsk_node) {
> +		dsa_desc_submit(ctx, tsk_node->tsk->desc);
> +		tsk_node = tsk_node->next;
> +	}
> +
> +	info("Submitted all dif strp jobs\n");
> +	tsk_node = ctx->multi_task_node;
> +	while (tsk_node) {
> +		ret = dsa_wait_dif(ctx, tsk_node->tsk);
> +		if (ret != DSA_STATUS_OK)
> +			info("Desc: %p failed with ret: %d\n", tsk_node->tsk->desc,
> +			     tsk_node->tsk->comp->status);
> +		tsk_node = tsk_node->next;
> +	}
> +
> +	return ret;
> +}
> +
> +int dsa_dif_updt_multi_task_nodes(struct dsa_context *ctx)
> +{
> +	struct task_node *tsk_node = ctx->multi_task_node;
> +	int ret = DSA_STATUS_OK;
> +
> +	while (tsk_node) {
> +		tsk_node->tsk->dflags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR;
> +		if ((tsk_node->tsk->test_flags & TEST_FLAGS_BOF) && ctx->bof)
> +			tsk_node->tsk->dflags |= IDXD_OP_FLAG_BOF;
> +
> +		dsa_prep_dif_update(tsk_node->tsk);
> +		tsk_node = tsk_node->next;
> +	}
> +
> +	tsk_node = ctx->multi_task_node;
> +	while (tsk_node) {
> +		dsa_desc_submit(ctx, tsk_node->tsk->desc);
> +		tsk_node = tsk_node->next;
> +	}
> +	tsk_node = ctx->multi_task_node;
> +
> +	info("Submitted all dif update jobs\n");
> +	while (tsk_node) {
> +		ret = dsa_wait_dif(ctx, tsk_node->tsk);
> +		if (ret != DSA_STATUS_OK)
> +			info("Desc: %p failed with ret: %d\n", tsk_node->tsk->desc,
> +			     tsk_node->tsk->comp->status);
> +		tsk_node = tsk_node->next;
> +	}
> +	return ret;
> +}
> +
>   /* mismatch_expected: expect mismatched buffer with success status 0x1 */
>   int task_result_verify(struct task *tsk, int mismatch_expected)
>   {
> @@ -1476,6 +1865,19 @@ int task_result_verify(struct task *tsk, int mismatch_expected)
>   	case DSA_OPCODE_COPY_CRC:
>   		rc = task_result_verify_crc_copy(tsk, mismatch_expected);
>   		return rc;
> +	case DSA_OPCODE_DIF_INS:
> +		rc = task_result_verify_dif(tsk, tsk->xfer_size, mismatch_expected);
> +		rc = task_result_verify_dif_tags(tsk, tsk->xfer_size);
> +		return rc;
> +	case DSA_OPCODE_DIF_STRP:
> +		rc = task_result_verify_dif(tsk, tsk->xfer_size - 8 * tsk->blks,
> +					    mismatch_expected);
> +		return rc;
> +	case DSA_OPCODE_DIF_UPDT:
> +		rc = task_result_verify_dif(tsk, tsk->xfer_size - 8 * tsk->blks,
> +					    mismatch_expected);
> +		rc = task_result_verify_dif_tags(tsk, tsk->xfer_size - 8 * tsk->blks);
> +		return rc;
>   	}
>   
>   	info("test with op %d passed\n", tsk->opcode);
> @@ -1745,6 +2147,333 @@ int task_result_verify_crc_copy(struct task *tsk, int mismatch_expected)
>   	return DSA_STATUS_OK;
>   }
>   
> +/**
> + * This function calculates the CRC16 T10 checksum for the DIF descriptors.
> + * @param *buffer pointer to the data buffer.
> + * @param len size of the buffer.
> + *
> + **/
> +uint16_t dsa_calculate_crc_t10dif(unsigned char *buffer, size_t len, int flags)
> +{
> +	unsigned short crc;
> +	unsigned int i = 0;
> +
> +	crc = (flags & DIF_INVERT_CRC_SEED) ? 0xFFFF : 0;
> +
> +	for (i = 0; i < len; i++)
> +		crc = (crc << 8) ^ t10_dif_crc_table[((crc >> 8) ^ buffer[i]) & 0xff];
> +
> +	return (flags & DIF_INVERT_CRC_RESULT) ? ~crc : crc;
> +}
> +
> +static int task_result_verify_dif_page_fault(struct task *tsk, unsigned long xfer_size,
> +					     int mismatch_expected)
> +{
> +	struct dsa_hw_desc *hw = tsk->desc;
> +	int rc = 0;
> +	unsigned char *src1 = (unsigned char *)hw->src_addr;
> +	unsigned char *dst1 = (unsigned char *)hw->dst_addr;
> +	unsigned long i, blks;
> +
> +	if (tsk->comp->status == 0x16 || xfer_size == 0)
> +	/* This check need to be removed for GNR-SP. Its a know bug in SPR-SP
> +	 * https://hsdes.intel.com/appstore/article/#/22010927356
> +	 * [SPR][No Fix] For DIF operations, RTL should consider 'computed transfer size'
> +	 * when determining overlapping buffer conditions
> +	 */
> +		return DSA_STATUS_OK;
> +
> +	info("Partial DIF Src and Dest Check Ongoing\n");
> +
> +	if (tsk->opcode == DSA_OPCODE_DIF_INS) {
> +		blks = xfer_size / dif_blk_arr[tsk->blk_idx_flg];
> +		for (i = 0; i < blks; i++)
> +			rc = memcmp(&src1[dif_blk_arr[tsk->blk_idx_flg] * i],
> +				    &dst1[(dif_blk_arr[tsk->blk_idx_flg] + 8) * i],
> +				    dif_blk_arr[tsk->blk_idx_flg]);
> +	}
> +
> +	if (tsk->opcode == DSA_OPCODE_DIF_STRP) {
> +		blks = xfer_size / (dif_blk_arr[tsk->blk_idx_flg] + 8);
> +		for (i = 0; i < blks; i++)
> +			rc = memcmp(&src1[(dif_blk_arr[tsk->blk_idx_flg] + 8) * i],
> +				    &dst1[dif_blk_arr[tsk->blk_idx_flg] * i],
> +				    dif_blk_arr[tsk->blk_idx_flg]);
> +	}
> +
> +	if (tsk->opcode == DSA_OPCODE_DIF_UPDT) {
> +		blks = xfer_size / (dif_blk_arr[tsk->blk_idx_flg] + 8);
> +		for (i = 0; i < blks; i++)
> +			rc = memcmp(&src1[(dif_blk_arr[tsk->blk_idx_flg] + 8) * i],
> +				    &dst1[(dif_blk_arr[tsk->blk_idx_flg] + 8) * i],
> +				    dif_blk_arr[tsk->blk_idx_flg]);
> +	}
> +
> +	if (rc) {
> +		err("dif mismatch dst1, memcmp rc %d\n", rc);
> +		return -ENXIO;
> +	}
> +
> +	return DSA_STATUS_OK;
> +}
> +
> +int task_result_verify_dif(struct task *tsk, unsigned long xfer_size, int mismatch_expected)
> +{
> +	int rc;
> +	unsigned long i;
> +	unsigned long blks = tsk->blks;
> +	unsigned long buf_size = dif_blk_arr[tsk->blk_idx_flg];
> +	unsigned char *src1 = (unsigned char *)tsk->src1;
> +	unsigned char *dst1 = (unsigned char *)tsk->dst1;
> +
> +	if (tsk->comp->status == DSA_COMP_PAGE_FAULT_NOBOF ||
> +	    tsk->comp->status == DSA_COMP_PAGE_FAULT_IR ||
> +	    tsk->comp->status == 0x83) {
> +		rc = task_result_verify_dif_page_fault(tsk, tsk->comp->bytes_completed, 0);
> +		info("Partial DIF Src and Dest Checking Done\n");
> +		if (!rc)
> +			return DSA_STATUS_OK;
> +	}
> +
> +	/* This check need to be removed for GNR-SP. Its a know bug in SPR-SP
> +	 * https://hsdes.intel.com/appstore/article/#/22010927356
> +	 * [SPR][No Fix] For DIF operations, RTL should consider 'computed transfer size'
> +	 * when determining overlapping buffer conditions
> +	 */
> +	if (tsk->comp->status == 0x16)
> +		return DSA_STATUS_OK;
> +
> +	info("Checking Src & Dst buffers\n");
> +	if (tsk->opcode == DSA_OPCODE_DIF_INS) {
> +		for (i = 0; i < blks; i++)
> +			rc = memcmp(&src1[buf_size * i], &dst1[(buf_size + 8) * i], buf_size);
> +	}
> +
> +	if (tsk->opcode == DSA_OPCODE_DIF_STRP) {
> +		for (i = 0; i < blks; i++)
> +			rc = memcmp(&src1[(buf_size + 8) * i], &dst1[buf_size * i], buf_size);
> +	}
> +
> +	if (tsk->opcode == DSA_OPCODE_DIF_UPDT) {
> +		for (i = 0; i < blks; i++)
> +			rc = memcmp(&src1[(buf_size + 8) * i], &dst1[(buf_size + 8) * i], buf_size);
> +	}
> +
> +	if (rc) {
> +		err("dif mismatch dst1, memcmp rc %d\n", rc);
> +		return -ENXIO;
> +	}
> +
> +	return DSA_STATUS_OK;
> +}
> +
> +static int task_result_verify_dif_tags_page_fault(struct task *tsk, unsigned long xfer_size)
> +{
> +	struct dsa_hw_desc *hw = tsk->desc;
> +	unsigned long blks;
> +	unsigned long buf_size;
> +	unsigned char *dst1 = (uint8_t *)hw->dst_addr;
> +	unsigned char *src1 = (uint8_t *)hw->src_addr;
> +	unsigned long g_count = 0;
> +	unsigned long a_count = 0;
> +	unsigned long r_count = 0;
> +	unsigned short dif_apptag = 0;
> +	unsigned long dif_reftag = 0;
> +	unsigned int dif_guardtag = 0;
> +	unsigned char tmp_buf;
> +	unsigned char dst_tag;
> +	unsigned long i;
> +
> +	info("Checking Partial DIF Tags\n");
> +	/* This check need to be removed for GNR-SP. Its a know bug in SPR-SP
> +	 * https://hsdes.intel.com/appstore/article/#/22010927356
> +	 * [SPR][No Fix] For DIF operations, RTL should consider 'computed transfer size'
> +	 * when determining overlapping buffer conditions
> +	 */
> +	if (tsk->comp->status == 0x16 || xfer_size == 0)
> +		return DSA_STATUS_OK;
> +
> +	if (tsk->opcode != DSA_OPCODE_DIF_UPDT)
> +		blks = xfer_size / dif_blk_arr[tsk->blk_idx_flg];
> +	else
> +		blks = xfer_size / (dif_blk_arr[tsk->blk_idx_flg] + 8);
> +
> +	switch (tsk->opcode) {
> +	case DSA_OPCODE_DIF_INS:
> +		dif_reftag = hw->ins_ref_tag_seed;
> +		dif_apptag = hw->ins_app_tag_seed;
> +		break;
> +
> +	case DSA_OPCODE_DIF_CHECK:
> +	case DSA_OPCODE_DIF_STRP:
> +		dif_reftag = hw->chk_ref_tag_seed;
> +		dif_apptag = hw->chk_app_tag_seed;
> +		break;
> +
> +	case DSA_OPCODE_DIF_UPDT:
> +		dif_reftag = hw->dest_ref_tag_seed;
> +		dif_apptag = hw->dest_app_tag_seed;
> +		break;
> +	}
> +
> +	buf_size = dif_blk_arr[tsk->blk_idx_flg];
> +	for (i = 0; i < blks; i++) {
> +		if (tsk->opcode == DSA_OPCODE_DIF_INS)
> +			dif_guardtag = dsa_calculate_crc_t10dif((src1 + buf_size * i),
> +								buf_size, 0);
> +		else
> +			dif_guardtag = dsa_calculate_crc_t10dif((src1 + (buf_size + 8) * i),
> +								buf_size, 0);
> +
> +		dst_tag = dst1[buf_size + DIF_BLK_GRD_1 + (buf_size + 8) * i];
> +		tmp_buf = (dif_guardtag >> 8) & 0xff;
> +		if (tmp_buf != dst_tag)
> +			g_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_BLK_GRD_2 + (buf_size + 8) * i];
> +		tmp_buf = dif_guardtag & 0xff;
> +		if (tmp_buf != dst_tag)
> +			g_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_APP_TAG_1 + (buf_size + 8) * i];
> +		tmp_buf = (dif_apptag >> 8) & 0xff;
> +		if (tmp_buf != dst_tag)
> +			a_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_APP_TAG_2 + (buf_size + 8) * i];
> +		tmp_buf = (dif_apptag) & 0xff;
> +		if (tmp_buf != dst_tag)
> +			a_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_REF_TAG_1 + (buf_size + 8) * i];
> +		tmp_buf = (dif_reftag >> 24) & 0xff;
> +		if (tmp_buf != dst_tag)
> +			r_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_REF_TAG_2 + (buf_size + 8) * i];
> +		tmp_buf = (dif_reftag >> 16) & 0xff;
> +		if (tmp_buf != dst_tag)
> +			r_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_REF_TAG_3 + (buf_size + 8) * i];
> +		tmp_buf = (dif_reftag >> 8) & 0xff;
> +		if (tmp_buf != dst_tag)
> +			r_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_REF_TAG_4 + (buf_size + 8) * i];
> +		tmp_buf = dif_reftag & 0xff;
> +		if (tmp_buf != dst_tag)
> +			r_count++;
> +
> +		if (tsk->opcode != DSA_OPCODE_DIF_UPDT)
> +			dif_reftag++;
> +	}
> +
> +	if (g_count || a_count || r_count)
> +		err("Tag Errors Found g: %ld a: %ld r: %ld\n", g_count, a_count, r_count);
> +	else
> +		info("All Tags Validated\n", g_count, a_count, r_count);
> +
> +	return DSA_STATUS_OK;
> +}
> +
> +int task_result_verify_dif_tags(struct task *tsk, unsigned long xfer_size)
> +{
> +	int rc;
> +	unsigned long blks;
> +	unsigned long buf_size;
> +	unsigned char *dst1 = (unsigned char *)tsk->dst1;
> +	unsigned char *src1 = (unsigned char *)tsk->src1;
> +	unsigned long g_count = 0;
> +	unsigned long a_count = 0;
> +	unsigned long r_count = 0;
> +	unsigned int dif_reftag = tsk->reftag;
> +	unsigned int dif_apptag = tsk->apptag;
> +	unsigned int dif_guardtag = 0;
> +	unsigned char tmp_buf;
> +	unsigned char dst_tag;
> +	unsigned long i;
> +
> +	info("compsts: %x\n", tsk->comp->status);
> +	if (tsk->comp->status == 0x83 ||
> +	    tsk->comp->status == DSA_COMP_PAGE_FAULT_NOBOF ||
> +	    tsk->comp->status == DSA_COMP_PAGE_FAULT_IR) {
> +		rc = task_result_verify_dif_tags_page_fault(tsk, tsk->comp->bytes_completed);
> +		info("Partial DIF Tags Checking Done\n");
> +		if (!rc)
> +			return DSA_STATUS_OK;
> +	}
> +
> +	info("Checking All Tags\n");
> +	if (tsk->opcode != DSA_OPCODE_DIF_UPDT)
> +		blks = xfer_size / dif_blk_arr[tsk->blk_idx_flg];
> +	else
> +		blks = tsk->blks;
> +
> +	buf_size = dif_blk_arr[tsk->blk_idx_flg];
> +	tsk->reftag = 0xABBA;
> +	tsk->apptag = 0xFACE;
> +
> +	for (i = 0; i < blks; i++) {
> +		if (tsk->opcode == DSA_OPCODE_DIF_INS)
> +			dif_guardtag = dsa_calculate_crc_t10dif((src1 + (buf_size) * i),
> +								buf_size, 0);
> +		else
> +			dif_guardtag = dsa_calculate_crc_t10dif((src1 + (buf_size + 8) * i),
> +								buf_size, 0);
> +
> +		dst_tag = dst1[buf_size + DIF_BLK_GRD_1 + (buf_size + 8) * i];
> +		tmp_buf = (dif_guardtag >> 8) & 0xff;
> +		if (tmp_buf != dst_tag)
> +			g_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_BLK_GRD_2 + (buf_size + 8) * i];
> +		tmp_buf = dif_guardtag & 0xff;
> +		if (tmp_buf != dst_tag)
> +			g_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_APP_TAG_1 + (buf_size + 8) * i];
> +		tmp_buf = (dif_apptag >> 8) & 0xff;
> +		if (tmp_buf != dst_tag)
> +			a_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_APP_TAG_2 + (buf_size + 8) * i];
> +		tmp_buf = (dif_apptag) & 0xff;
> +		if (tmp_buf != dst_tag)
> +			a_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_REF_TAG_1 + (buf_size + 8) * i];
> +		tmp_buf = (dif_reftag >> 24) & 0xff;
> +		if (tmp_buf != dst_tag)
> +			r_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_REF_TAG_2 + (buf_size + 8) * i];
> +		tmp_buf = (dif_reftag >> 16) & 0xff;
> +		if (tmp_buf != dst_tag)
> +			r_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_REF_TAG_3 + (buf_size + 8) * i];
> +		tmp_buf = (dif_reftag >> 8) & 0xff;
> +		if (tmp_buf != dst_tag)
> +			r_count++;
> +
> +		dst_tag = dst1[buf_size + DIF_REF_TAG_4 + (buf_size + 8) * i];
> +		tmp_buf = dif_reftag & 0xff;
> +		if (tmp_buf != dst_tag)
> +			r_count++;
> +
> +		if (tsk->opcode != DSA_OPCODE_DIF_UPDT)
> +			dif_reftag++;
> +	}
> +
> +	if (g_count || a_count || r_count)
> +		err("Tag Errors Found g: %ld a: %ld r: %ld\n", g_count, a_count, r_count);
> +	else
> +		info("All Tags Validated\n", g_count, a_count, r_count);
> +
> +	return DSA_STATUS_OK;
> +}
> +
>   int batch_result_verify(struct batch_task *btsk, int bof)
>   {
>   	uint8_t core_stat, sub_stat;
> diff --git a/test/dsa.h b/test/dsa.h
> index 4bb08ed..9157741 100644
> --- a/test/dsa.h
> +++ b/test/dsa.h
> @@ -5,6 +5,7 @@
>   #include <accfg/libaccel_config.h>
>   #include <accfg/idxd.h>
>   #include "accfg_test.h"
> +#include "crc16_t10_lookup.h"
>   
>   #define MAX_PATH_LENGTH 1024
>   
> @@ -46,6 +47,19 @@
>   #define BYPASS_CRC_INV_REF	((unsigned long)(1 << 17))
>   #define BYPASS_DATA_REF		((unsigned long)(1 << 18))
>   
> +/* DIF index */
> +#define DIF_BLK_GRD_1  0
> +#define DIF_BLK_GRD_2  1
> +#define DIF_APP_TAG_1  2
> +#define DIF_APP_TAG_2  3
> +#define DIF_REF_TAG_1  4
> +#define DIF_REF_TAG_2  5
> +#define DIF_REF_TAG_3  6
> +#define DIF_REF_TAG_4  7
> +
> +#define DIF_INVERT_CRC_SEED         ((unsigned long)(1 << 2))
> +#define DIF_INVERT_CRC_RESULT       ((unsigned long)(1 << 3))
> +
>   #define ADDR_ALIGNMENT 32
>   
>   #define MIN_DELTA_RECORD_SIZE 80
> @@ -72,6 +86,11 @@ struct task {
>   	int test_flags;
>   	int crc_seed;
>   	unsigned long long *crc_seed_addr;
> +	int reftag;
> +	int apptag;
> +	int guardtag;
> +	unsigned long blks;
> +	int blk_idx_flg;
>   };
>   
>   struct task_node {
> @@ -247,6 +266,10 @@ int init_dualcast(struct task *tsk, int tflags, int opcode, unsigned long xfer_s
>   int init_cr_delta(struct task *tsk, int tflags, int opcode, unsigned long xfer_size);
>   int init_crcgen(struct task *tsk, int tflags, int opcode, unsigned long xfer_size);
>   int init_copy_crc(struct task *tsk, int tflags, int opcode, unsigned long xfer_size);
> +int init_dif_check(struct task *tsk, int tflags, int opcode, unsigned long xfer_size);
> +int init_dif_ins(struct task *tsk, int tflags, int opcode, unsigned long xfer_size);
> +int init_dif_strp(struct task *tsk, int tflags, int opcode, unsigned long xfer_size);
> +int init_dif_updt(struct task *tsk, int tflags, int opcode, unsigned long xfer_size);
>   int init_task(struct task *tsk, int tflags, int opcode,
>   	      unsigned long xfer_size);
>   
> @@ -283,6 +306,12 @@ int dsa_wait_crcgen(struct dsa_context *ctx, struct task *tsk);
>   int dsa_crc_copy_multi_task_nodes(struct dsa_context *ctx);
>   int dsa_wait_crc_copy(struct dsa_context *ctx, struct task *tsk);
>   
> +int dsa_dif_check_multi_task_nodes(struct dsa_context *ctx);
> +int dsa_dif_ins_multi_task_nodes(struct dsa_context *ctx);
> +int dsa_dif_strp_multi_task_nodes(struct dsa_context *ctx);
> +int dsa_dif_updt_multi_task_nodes(struct dsa_context *ctx);
> +int dsa_wait_dif(struct dsa_context *ctx, struct task *tsk);
> +
>   void dsa_prep_noop(struct task *tsk);
>   void dsa_prep_drain(struct task *tsk);
>   void dsa_prep_memcpy(struct task *tsk);
> @@ -303,6 +332,11 @@ void dsa_prep_crcgen(struct task *tsk);
>   void dsa_reprep_crcgen(struct dsa_context *ctx, struct task *tsk);
>   void dsa_prep_crc_copy(struct task *tsk);
>   void dsa_reprep_crc_copy(struct dsa_context *ctx, struct task *tsk);
> +void dsa_prep_dif_check(struct task *tsk);
> +void dsa_prep_dif_insert(struct task *tsk);
> +void dsa_prep_dif_strip(struct task *tsk);
> +void dsa_prep_dif_update(struct task *tsk);
> +void dsa_reprep_dif(struct dsa_context *ctx, struct task *tsk);
>   
>   int task_result_verify(struct task *tsk, int mismatch_expected);
>   int task_result_verify_task_nodes(struct dsa_context *ctx, int mismatch_expected);
> @@ -314,6 +348,8 @@ int task_result_verify_dualcast(struct task *tsk, int mismatch_expected);
>   int task_result_verify_ap_delta(struct task *tsk, int mismatch_expected);
>   int task_result_verify_crcgen(struct task *tsk, int mismatch_expected);
>   int task_result_verify_crc_copy(struct task *tsk, int mismatch_expected);
> +int task_result_verify_dif(struct task *tsk, unsigned long xfer_size, int mismatch_expected);
> +int task_result_verify_dif_tags(struct task *tsk, unsigned long xfer_size);
>   int batch_result_verify(struct batch_task *btsk, int bof);
>   
>   int alloc_batch_task(struct dsa_context *ctx, unsigned int task_num, int num_itr);
> @@ -331,6 +367,10 @@ void dsa_prep_batch_cr_delta(struct batch_task *btsk);
>   void dsa_prep_batch_ap_delta(struct batch_task *btsk);
>   void dsa_prep_batch_crcgen(struct batch_task *btsk);
>   void dsa_prep_batch_crc_copy(struct batch_task *btsk);
> +void dsa_prep_batch_dif_check(struct batch_task *btsk);
> +void dsa_prep_batch_dif_insert(struct batch_task *btsk);
> +void dsa_prep_batch_dif_strip(struct batch_task *btsk);
> +void dsa_prep_batch_dif_update(struct batch_task *btsk);
>   int dsa_wait_batch(struct batch_task *btsk);
>   
>   void dsa_free(struct dsa_context *ctx);
> @@ -342,4 +382,8 @@ void free_batch_task(struct batch_task *btsk);
>   void dsa_prep_desc_common(struct dsa_hw_desc *hw, char opcode,
>   			  uint64_t dest, uint64_t src, size_t len, unsigned long dflags);
>   void dsa_desc_submit(struct dsa_context *ctx, struct dsa_hw_desc *hw);
> +
> +uint16_t dsa_calculate_crc_t10dif(unsigned char *buffer, size_t len, int flags);
> +int get_dif_blksz_flg(unsigned long xfer_size);
> +unsigned long get_blks(unsigned long xfer_size);
>   #endif
> diff --git a/test/dsa_test.c b/test/dsa_test.c
> index 5a89687..a702f75 100644
> --- a/test/dsa_test.c
> +++ b/test/dsa_test.c
> @@ -111,6 +111,22 @@ static int test_batch(struct dsa_context *ctx, size_t buf_size,
>   				dsa_prep_batch_crc_copy(btsk_node->btsk);
>   				break;
>   
> +			case DSA_OPCODE_DIF_CHECK:
> +				dsa_prep_batch_dif_check(btsk_node->btsk);
> +				break;
> +
> +			case DSA_OPCODE_DIF_INS:
> +				dsa_prep_batch_dif_insert(btsk_node->btsk);
> +				break;
> +
> +			case DSA_OPCODE_DIF_STRP:
> +				dsa_prep_batch_dif_strip(btsk_node->btsk);
> +				break;
> +
> +			case DSA_OPCODE_DIF_UPDT:
> +				dsa_prep_batch_dif_update(btsk_node->btsk);
> +				break;
> +
>   			default:
>   				err("Unsupported op %#x\n", bopcode);
>   				return -EINVAL;
> @@ -191,6 +207,85 @@ static int test_batch(struct dsa_context *ctx, size_t buf_size,
>   	return rc;
>   }
>   
> +static int test_dif(struct dsa_context *ctx, size_t buf_size,
> +		    int tflags, uint32_t opcode, int num_desc)
> +{
> +	struct task_node *tsk_node;
> +	int rc = DSA_STATUS_OK;
> +	int itr = num_desc, i = 0, range = 0;
> +
> +	info("testmemory: opcode %d len %#lx tflags %#x num_desc %ld\n",
> +	     opcode, buf_size, tflags, num_desc);
> +
> +	ctx->is_batch = 0;
> +
> +	if (ctx->dedicated == ACCFG_WQ_SHARED)
> +		range = ctx->threshold;
> +	else
> +		range = ctx->wq_size - 1;
> +
> +	while (itr > 0 && rc == DSA_STATUS_OK) {
> +		i = (itr < range) ? itr : range;
> +		/* Allocate memory to all the task nodes, desc, completion record*/
> +		rc = alloc_multiple_tasks(ctx, i);
> +		if (rc != DSA_STATUS_OK)
> +			return rc;
> +
> +		/* allocate memory to src and dest buffers and fill in the desc for all the nodes*/
> +		tsk_node = ctx->multi_task_node;
> +		while (tsk_node) {
> +			tsk_node->tsk->xfer_size = buf_size;
> +			tsk_node->tsk->blk_idx_flg = get_dif_blksz_flg(tsk_node->tsk->xfer_size);
> +
> +			rc = init_task(tsk_node->tsk, tflags, opcode, buf_size);
> +			if (rc != DSA_STATUS_OK)
> +				return rc;
> +
> +			tsk_node = tsk_node->next;
> +		}
> +
> +		switch (opcode) {
> +		case DSA_OPCODE_DIF_CHECK:
> +			rc = dsa_dif_check_multi_task_nodes(ctx);
> +			if (rc != DSA_STATUS_OK)
> +				return rc;
> +			break;
> +
> +		case DSA_OPCODE_DIF_INS:
> +			rc = dsa_dif_ins_multi_task_nodes(ctx);
> +			if (rc != DSA_STATUS_OK)
> +				return rc;
> +			break;
> +
> +		case DSA_OPCODE_DIF_STRP:
> +			rc = dsa_dif_strp_multi_task_nodes(ctx);
> +			if (rc != DSA_STATUS_OK)
> +				return rc;
> +			break;
> +
> +		case DSA_OPCODE_DIF_UPDT:
> +			rc = dsa_dif_updt_multi_task_nodes(ctx);
> +			if (rc != DSA_STATUS_OK)
> +				return rc;
> +			break;
> +
> +		default:
> +			err("Unsupported op %#x\n", opcode);
> +			return -EINVAL;
> +		}
> +
> +		/* Verification of all the nodes*/
> +		rc = task_result_verify_task_nodes(ctx, 0);
> +		if (rc != DSA_STATUS_OK)
> +			return rc;
> +
> +		dsa_free_task(ctx);
> +		itr = itr - range;
> +	}
> +
> +	return rc;
> +}
> +
>   static int test_noop(struct dsa_context *ctx, int tflags, int num_desc)
>   {
>   	struct task_node *tsk_node;
> @@ -650,6 +745,15 @@ int main(int argc, char *argv[])
>   			goto error;
>   		break;
>   
> +	case DSA_OPCODE_DIF_CHECK:
> +	case DSA_OPCODE_DIF_INS:
> +	case DSA_OPCODE_DIF_STRP:
> +	case DSA_OPCODE_DIF_UPDT:
> +		rc = test_dif(dsa, buf_size, tflags, opcode, num_desc);
> +		if (rc != DSA_STATUS_OK)
> +			goto error;
> +		break;
> +
>   	default:
>   		rc = -EINVAL;
>   		break;
> diff --git a/test/prep.c b/test/prep.c
> index daa8db4..5f85b7c 100644
> --- a/test/prep.c
> +++ b/test/prep.c
> @@ -8,6 +8,8 @@
>   #include <accfg/idxd.h>
>   #include "dsa.h"
>   
> +unsigned int dif_arr[] = {512, 520, 4096, 4104};
> +
>   void dsa_prep_desc_common(struct dsa_hw_desc *hw, char opcode,
>   			  uint64_t dest, uint64_t src, size_t len, unsigned long dflags)
>   {
> @@ -531,6 +533,193 @@ void dsa_prep_batch_crc_copy(struct batch_task *btsk)
>   	}
>   }
>   
> +void dsa_prep_dif_check(struct task *tsk)
> +{
> +	info("preparing descriptor for dif check\n");
> +
> +	dsa_prep_desc_common(tsk->desc, tsk->opcode, (uint64_t)(tsk->dst1),
> +			     (uint64_t)(tsk->src1), tsk->xfer_size, tsk->dflags);
> +	tsk->desc->completion_addr = (uint64_t)(tsk->comp);
> +	tsk->comp->status = 0;
> +	tsk->desc->chk_app_tag_seed = tsk->apptag;
> +	tsk->desc->chk_ref_tag_seed = tsk->reftag;
> +	tsk->desc->dif_chk_flags = tsk->blk_idx_flg;
> +}
> +
> +void dsa_prep_dif_insert(struct task *tsk)
> +{
> +	info("preparing descriptor for dif insert\n");
> +
> +	dsa_prep_desc_common(tsk->desc, tsk->opcode, (uint64_t)(tsk->dst1),
> +			     (uint64_t)(tsk->src1), tsk->xfer_size, tsk->dflags);
> +	tsk->desc->completion_addr = (uint64_t)(tsk->comp);
> +	tsk->comp->status = 0;
> +	tsk->desc->ins_app_tag_seed = tsk->apptag;
> +	tsk->desc->ins_ref_tag_seed = tsk->reftag;
> +	tsk->desc->dif_ins_flags = tsk->blk_idx_flg;
> +}
> +
> +void dsa_prep_dif_strip(struct task *tsk)
> +{
> +	info("preparing descriptor for dif strip\n");
> +
> +	dsa_prep_desc_common(tsk->desc, tsk->opcode, (uint64_t)(tsk->dst1),
> +			     (uint64_t)(tsk->src1), tsk->xfer_size, tsk->dflags);
> +	tsk->desc->completion_addr = (uint64_t)(tsk->comp);
> +	tsk->comp->status = 0;
> +	tsk->desc->chk_app_tag_seed = tsk->apptag;
> +	tsk->desc->chk_ref_tag_seed = tsk->reftag;
> +	tsk->desc->dif_chk_flags = tsk->blk_idx_flg;
> +}
> +
> +void dsa_prep_dif_update(struct task *tsk)
> +{
> +	info("preparing descriptor for dif update\n");
> +
> +	dsa_prep_desc_common(tsk->desc, tsk->opcode, (uint64_t)(tsk->dst1),
> +			     (uint64_t)(tsk->src1), tsk->xfer_size, tsk->dflags);
> +	tsk->desc->completion_addr = (uint64_t)(tsk->comp);
> +	tsk->comp->status = 0;
> +	tsk->desc->src_app_tag_seed = tsk->apptag;
> +	tsk->desc->src_ref_tag_seed = tsk->reftag;
> +	tsk->desc->dest_ref_tag_seed = tsk->reftag;
> +	tsk->desc->dest_app_tag_seed = tsk->apptag;
> +	tsk->desc->src_upd_flags = 0x80;
> +	tsk->desc->upd_dest_flags = 0x80;
> +	tsk->desc->dif_upd_flags = tsk->blk_idx_flg;
> +}
> +
> +void dsa_reprep_dif(struct dsa_context *ctx, struct task *tsk)
> +{
> +	struct dsa_completion_record *compl = tsk->comp;
> +	struct dsa_hw_desc *hw = tsk->desc;
> +	unsigned long blks_completed = 0;
> +
> +	info("PF addr %#lx dir %d bc %#x\n",
> +	     compl->fault_addr, compl->result,
> +	     compl->bytes_completed);
> +
> +	hw->src_addr += compl->bytes_completed;
> +	hw->ins_ref_tag_seed = compl->dif_ins_ref_tag;
> +	if (tsk->opcode == DSA_OPCODE_DIF_INS) {
> +		blks_completed = compl->bytes_completed / (dif_arr[tsk->blk_idx_flg]);
> +		hw->xfer_size -= compl->bytes_completed;
> +		hw->dst_addr += compl->bytes_completed + 8 * blks_completed;
> +		hw->ins_app_tag_seed = compl->dif_ins_app_tag;
> +		hw->ins_ref_tag_seed = compl->dif_ins_ref_tag;
> +	}
> +
> +	if (tsk->opcode == DSA_OPCODE_DIF_STRP) {
> +		blks_completed = compl->bytes_completed / (dif_arr[tsk->blk_idx_flg] + 8);
> +		hw->xfer_size -= compl->bytes_completed;
> +		hw->dst_addr += dif_arr[tsk->blk_idx_flg] * blks_completed;
> +		hw->chk_app_tag_seed = compl->dif_chk_app_tag;
> +		hw->chk_ref_tag_seed = compl->dif_chk_ref_tag;
> +	}
> +
> +	if (tsk->opcode == DSA_OPCODE_DIF_UPDT) {
> +		blks_completed = compl->bytes_completed / (dif_arr[tsk->blk_idx_flg] + 8);
> +		hw->xfer_size -= compl->bytes_completed;
> +		hw->dst_addr += (dif_arr[tsk->blk_idx_flg] + 8) * blks_completed;
> +		hw->src_app_tag_seed = compl->dif_upd_src_app_tag;
> +		hw->dest_app_tag_seed = compl->dif_upd_dest_app_tag;
> +		hw->src_ref_tag_seed = compl->dif_upd_dest_ref_tag;
> +		hw->dest_ref_tag_seed = compl->dif_upd_dest_ref_tag;
> +	}
> +	if (tsk->opcode == DSA_OPCODE_DIF_CHECK) {
> +		blks_completed = compl->bytes_completed / (dif_arr[tsk->blk_idx_flg] + 8);
> +		hw->xfer_size -= compl->bytes_completed;
> +		hw->chk_app_tag_seed = compl->dif_chk_app_tag;
> +		hw->chk_ref_tag_seed = compl->dif_chk_ref_tag;
> +	}
> +
> +	resolve_page_fault(compl->fault_addr, compl->status);
> +
> +	compl->status = 0;
> +
> +	dsa_desc_submit(ctx, hw);
> +}
> +
> +void dsa_prep_batch_dif_check(struct batch_task *btsk)
> +{
> +	int i;
> +	struct task *sub_task;
> +
> +	for (i = 0; i < btsk->task_num; i++) {
> +		sub_task = &btsk->sub_tasks[i];
> +		sub_task->xfer_size = btsk->sub_tasks[i].xfer_size;
> +		sub_task->desc->dif_chk_flags = btsk->sub_tasks[i].blk_idx_flg;
> +		dsa_prep_desc_common(sub_task->desc, sub_task->opcode,
> +				     (uint64_t)(sub_task->dst1), (uint64_t)(sub_task->src1),
> +				     sub_task->xfer_size, sub_task->dflags);
> +		sub_task->desc->completion_addr = (uint64_t)(sub_task->comp);
> +		sub_task->comp->status = 0;
> +		sub_task->desc->chk_app_tag_seed = sub_task->apptag;
> +		sub_task->desc->chk_ref_tag_seed = sub_task->reftag;
> +	}
> +}
> +
> +void dsa_prep_batch_dif_insert(struct batch_task *btsk)
> +{
> +	int i;
> +	struct task *sub_task;
> +
> +	for (i = 0; i < btsk->task_num; i++) {
> +		sub_task = &btsk->sub_tasks[i];
> +		sub_task->xfer_size = btsk->sub_tasks[i].xfer_size;
> +		sub_task->desc->dif_chk_flags = btsk->sub_tasks[i].blk_idx_flg;
> +		dsa_prep_desc_common(sub_task->desc, sub_task->opcode,
> +				     (uint64_t)(sub_task->dst1), (uint64_t)(sub_task->src1),
> +				     sub_task->xfer_size, sub_task->dflags);
> +		sub_task->desc->completion_addr = (uint64_t)(sub_task->comp);
> +		sub_task->comp->status = 0;
> +		sub_task->desc->ins_app_tag_seed = sub_task->apptag;
> +		sub_task->desc->ins_ref_tag_seed = sub_task->reftag;
> +	}
> +}
> +
> +void dsa_prep_batch_dif_strip(struct batch_task *btsk)
> +{
> +	int i;
> +	struct task *sub_task;
> +
> +	for (i = 0; i < btsk->task_num; i++) {
> +		sub_task = &btsk->sub_tasks[i];
> +		sub_task->xfer_size = btsk->sub_tasks[i].xfer_size;
> +		sub_task->desc->dif_chk_flags = btsk->sub_tasks[i].blk_idx_flg;
> +		dsa_prep_desc_common(sub_task->desc, sub_task->opcode,
> +				     (uint64_t)(sub_task->dst1), (uint64_t)(sub_task->src1),
> +				     sub_task->xfer_size, sub_task->dflags);
> +		sub_task->desc->completion_addr = (uint64_t)(sub_task->comp);
> +		sub_task->comp->status = 0;
> +		sub_task->desc->chk_app_tag_seed = sub_task->apptag;
> +		sub_task->desc->chk_ref_tag_seed = sub_task->reftag;
> +	}
> +}
> +
> +void dsa_prep_batch_dif_update(struct batch_task *btsk)
> +{
> +	int i;
> +	struct task *sub_task;
> +
> +	for (i = 0; i < btsk->task_num; i++) {
> +		sub_task = &btsk->sub_tasks[i];
> +		sub_task->xfer_size = btsk->sub_tasks[i].xfer_size;
> +		sub_task->desc->dif_chk_flags = btsk->sub_tasks[i].blk_idx_flg;
> +		dsa_prep_desc_common(sub_task->desc, sub_task->opcode,
> +				     (uint64_t)(sub_task->dst1), (uint64_t)(sub_task->src1),
> +				     sub_task->xfer_size, sub_task->dflags);
> +		sub_task->desc->completion_addr = (uint64_t)(sub_task->comp);
> +		sub_task->comp->status = 0;
> +		sub_task->desc->src_app_tag_seed = sub_task->apptag;
> +		sub_task->desc->src_ref_tag_seed = sub_task->reftag;
> +		sub_task->desc->dest_ref_tag_seed = sub_task->reftag;
> +		sub_task->desc->dest_app_tag_seed = sub_task->apptag;
> +		sub_task->desc->src_upd_flags = 0x80;
> +		sub_task->desc->upd_dest_flags = 0x80;
> +	}
> +}
> +
>   void dsa_prep_batch(struct batch_task *btsk, unsigned long desc_flags)
>   {
>   	struct task *ctsk = btsk->core_task;