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

Tony Zhu <tony.zhu at intel.com> Mon, 21 Feb 2022 09:34:22 +0800
Newsgroups dev.linux.lists.accel-config
Message-ID <[email protected]>
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      | 713 ++++++++++++++++++++++++++++++++++++++++++++++++
 test/dsa.h      |  44 +++
 test/dsa_test.c | 104 +++++++
 test/prep.c     | 189 +++++++++++++
 4 files changed, 1050 insertions(+)

diff --git a/test/dsa.c b/test/dsa.c
index 9a10267..fa3b8d6 100644
--- a/test/dsa.c
+++ b/test/dsa.c
@@ -23,6 +23,35 @@ unsigned int ms_timeout = 5000;
 int debug_logging;
 static int umwait_support;
 
+unsigned int dif_blk_arr[] = {512, 520, 4096, 4104};
+
+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;
+}
+
+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 +506,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 +739,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 +1676,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 +1863,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 +2145,319 @@ 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)
+		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;
+	}
+
+	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");
+
+	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;
-- 
2.27.0