diff mbox

[09/22] qla2xxx: Refactor T10-DIF PI support

Message ID 1481056251-2310-10-git-send-email-himanshu.madhani@cavium.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Madhani, Himanshu Dec. 6, 2016, 8:30 p.m. UTC
From: Quinn Tran <quinn.tran@cavium.com>

qla2xxx currently access T10-DIF protection opcode and type
field in se_cmd struct. Add translation code so qla2xxx driver
would not acces private TCM data structure.

Signed-off-by: Quinn Tran <quinn.tran@cavium.com>
Signed-off-by: Anil Gurumurthy <anil.gurumurthy@cavium.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
---
 drivers/scsi/qla2xxx/qla_dbg.h     |   1 +
 drivers/scsi/qla2xxx/qla_def.h     |  23 ++
 drivers/scsi/qla2xxx/qla_dfs.c     |  15 +
 drivers/scsi/qla2xxx/qla_gbl.h     |   6 +-
 drivers/scsi/qla2xxx/qla_init.c    |   3 +
 drivers/scsi/qla2xxx/qla_inline.h  |  17 +
 drivers/scsi/qla2xxx/qla_iocb.c    |  17 +-
 drivers/scsi/qla2xxx/qla_isr.c     |   3 +
 drivers/scsi/qla2xxx/qla_target.c  | 613 ++++++++++++++++++++++++-------------
 drivers/scsi/qla2xxx/qla_target.h  |  47 ++-
 drivers/scsi/qla2xxx/tcm_qla2xxx.c | 158 ++++++++--
 11 files changed, 661 insertions(+), 242 deletions(-)

Comments

Christoph Hellwig Dec. 14, 2016, 9:03 p.m. UTC | #1
On Tue, Dec 06, 2016 at 12:30:38PM -0800, Himanshu Madhani wrote:
> From: Quinn Tran <quinn.tran@cavium.com>
> 
> qla2xxx currently access T10-DIF protection opcode and type
> field in se_cmd struct. Add translation code so qla2xxx driver
> would not acces private TCM data structure.

And what's the point of doing that?

>  11 files changed, 661 insertions(+), 242 deletions(-)

And independent of the above a "cleanup" that adds over 400 lines of
code is simply not acceptable.
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index e1fc4e6..c6bffe9 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -348,6 +348,7 @@  void __attribute__((format (printf, 4, 5)))
 #define ql_dbg_tgt	0x00004000 /* Target mode */
 #define ql_dbg_tgt_mgt	0x00002000 /* Target mode management */
 #define ql_dbg_tgt_tmr	0x00001000 /* Target mode task management */
+#define ql_dbg_tgt_dif  0x00000800 /* Target mode dif */
 
 extern int qla27xx_dump_mpi_ram(struct qla_hw_data *, uint32_t, uint32_t *,
 	uint32_t, void **);
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 07cda5a..8cee332 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2859,6 +2859,16 @@  struct qla_chip_state_84xx {
 	uint32_t gold_fw_version;
 };
 
+struct qla_dif_statistics {
+	uint64_t dif_input_bytes;
+	uint64_t dif_output_bytes;
+	uint64_t dif_input_requests;
+	uint64_t dif_output_requests;
+	uint32_t dif_guard_err;
+	uint32_t dif_ref_tag_err;
+	uint32_t dif_app_tag_err;
+};
+
 struct qla_statistics {
 	uint32_t total_isp_aborts;
 	uint64_t input_bytes;
@@ -2871,6 +2881,7 @@  struct qla_statistics {
 	uint32_t stat_max_pend_cmds;
 	uint32_t stat_max_qfull_cmds_alloc;
 	uint32_t stat_max_qfull_cmds_dropped;
+	struct qla_dif_statistics qla_dif_stats;
 };
 
 struct bidi_statistics {
@@ -2878,6 +2889,17 @@  struct bidi_statistics {
 	unsigned long long transfer_bytes;
 };
 
+/* DIF */
+struct qla_tc_param {
+	struct scsi_qla_host	*vha;
+	uint32_t		blk_sz;
+	uint32_t		bufflen;
+	struct scatterlist	*sg;
+	struct scatterlist	*prot_sg;
+	struct crc_context	*ctx;
+	uint8_t			*ctx_dsd_alloced;
+};
+
 /* Multi queue support */
 #define MBC_INITIALIZE_MULTIQ 0x1f
 #define QLA_QUE_PAGE 0X1000
@@ -3007,6 +3029,7 @@  struct qlt_hw_data {
 	uint16_t atio_q_length;
 	uint32_t __iomem *atio_q_in;
 	uint32_t __iomem *atio_q_out;
+	uint64_t        atio_ring_end_addr;
 
 	struct qla_tgt_func_tmpl *tgt_ops;
 	struct qla_tgt_cmd *cmds[DEFAULT_OUTSTANDING_COMMANDS];
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 6aa24ee..f69ff52 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -151,6 +151,21 @@ 
 	seq_printf(s, "num Q full sent = %lld\n",
 		vha->tgt_counters.num_q_full_sent);
 
+/* DIF stats */
+	seq_printf(s, "DIF Inp Bytes = %lld\n",
+		vha->qla_stats.qla_dif_stats.dif_input_bytes);
+	seq_printf(s, "DIF Outp Bytes = %lld\n",
+		vha->qla_stats.qla_dif_stats.dif_output_bytes);
+	seq_printf(s, "DIF Inp Req = %lld\n",
+		vha->qla_stats.qla_dif_stats.dif_input_requests);
+	seq_printf(s, "DIF Outp Req = %lld\n",
+		vha->qla_stats.qla_dif_stats.dif_output_requests);
+	seq_printf(s, "DIF Guard err = %d\n",
+		vha->qla_stats.qla_dif_stats.dif_guard_err);
+	seq_printf(s, "DIF Ref tag err = %d\n",
+		vha->qla_stats.qla_dif_stats.dif_ref_tag_err);
+	seq_printf(s, "DIF App tag err = %d\n",
+		vha->qla_stats.qla_dif_stats.dif_app_tag_err);
 	return 0;
 }
 
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 13c4d51..9303dbe 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -243,11 +243,11 @@  int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
 extern void *qla2x00_alloc_iocbs(scsi_qla_host_t *, srb_t *);
 extern int qla2x00_issue_marker(scsi_qla_host_t *, int);
 extern int qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *, srb_t *,
-	uint32_t *, uint16_t, struct qla_tgt_cmd *);
+	uint32_t *, uint16_t, struct qla_tc_param *);
 extern int qla24xx_walk_and_build_sglist(struct qla_hw_data *, srb_t *,
-	uint32_t *, uint16_t, struct qla_tgt_cmd *);
+	uint32_t *, uint16_t, struct qla_tc_param *);
 extern int qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *, srb_t *,
-	uint32_t *, uint16_t, struct qla_tgt_cmd *);
+	uint32_t *, uint16_t, struct qla_tc_param *);
 extern int qla24xx_get_one_block_sg(uint32_t, struct qla2_sgx *, uint32_t *);
 extern int qla24xx_configure_prot_mode(srb_t *, uint16_t *);
 extern int qla24xx_build_scsi_crc_2_iocbs(srb_t *,
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index f3ea6b6..30c840d 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -2260,6 +2260,9 @@  static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *,
 
 	ha->tgt.atio_ring_ptr = ha->tgt.atio_ring;
 	ha->tgt.atio_ring_index = 0;
+	ha->tgt.atio_ring_end_addr = (uint64_t)(ha->tgt.atio_ring +
+		(ha->tgt.atio_q_length - 1));
+
 	/* Initialize ATIO queue entries */
 	qlt_init_atio_q_entries(vha);
 
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 44e4045..5382b03 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -319,3 +319,20 @@ 
 		fcport->retry_delay_timestamp = jiffies +
 		    (retry_delay * HZ / 10);
 }
+
+static inline uint8_t *qla_atio_look_ahead(struct qlt_hw_data *ha_tgt,
+	struct atio *cur_atio, int index)
+{
+	struct atio *npkt = NULL;
+	int i;
+
+	/* index=1 : get the next IOCB. index=2: get 2nd iocb from cur_atio */
+	npkt = cur_atio;
+	for (i = 1; i <= index; i++) {
+		npkt++;
+		if ((uint64_t)npkt > ha_tgt->atio_ring_end_addr)
+			npkt = ha_tgt->atio_ring;
+	}
+
+	return (uint8_t *)npkt;
+}
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 61f4d21..2bb65c6 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -889,7 +889,7 @@  struct fw_dif_context {
 
 int
 qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *ha, srb_t *sp,
-	uint32_t *dsd, uint16_t tot_dsds, struct qla_tgt_cmd *tc)
+	uint32_t *dsd, uint16_t tot_dsds, struct qla_tc_param *tc)
 {
 	void *next_dsd;
 	uint8_t avail_dsds = 0;
@@ -966,7 +966,7 @@  struct fw_dif_context {
 			} else {
 				list_add_tail(&dsd_ptr->list,
 				    &(tc->ctx->dsd_list));
-				tc->ctx_dsd_alloced = 1;
+				*tc->ctx_dsd_alloced = 1;
 			}
 
 
@@ -1005,7 +1005,7 @@  struct fw_dif_context {
 
 int
 qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
-	uint16_t tot_dsds, struct qla_tgt_cmd *tc)
+	uint16_t tot_dsds, struct qla_tc_param *tc)
 {
 	void *next_dsd;
 	uint8_t avail_dsds = 0;
@@ -1066,7 +1066,7 @@  struct fw_dif_context {
 			} else {
 				list_add_tail(&dsd_ptr->list,
 				    &(tc->ctx->dsd_list));
-				tc->ctx_dsd_alloced = 1;
+				*tc->ctx_dsd_alloced = 1;
 			}
 
 			/* add new list to cmd iocb or last list */
@@ -1092,7 +1092,7 @@  struct fw_dif_context {
 
 int
 qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
-	uint32_t *dsd, uint16_t tot_dsds, struct qla_tgt_cmd *tc)
+	uint32_t *dsd, uint16_t tot_dsds, struct qla_tc_param *tc)
 {
 	void *next_dsd;
 	uint8_t avail_dsds = 0;
@@ -1158,7 +1158,7 @@  struct fw_dif_context {
 			} else {
 				list_add_tail(&dsd_ptr->list,
 				    &(tc->ctx->dsd_list));
-				tc->ctx_dsd_alloced = 1;
+				*tc->ctx_dsd_alloced = 1;
 			}
 
 			/* add new list to cmd iocb or last list */
@@ -1231,9 +1231,14 @@  struct fw_dif_context {
 	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
 		cmd_pkt->control_flags =
 		    cpu_to_le16(CF_WRITE_DATA);
+		vha->qla_stats.qla_dif_stats.dif_output_bytes += scsi_bufflen(cmd);
+		vha->qla_stats.qla_dif_stats.dif_output_requests++;
+
 	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
 		cmd_pkt->control_flags =
 		    cpu_to_le16(CF_READ_DATA);
+		vha->qla_stats.qla_dif_stats.dif_input_bytes += scsi_bufflen(cmd);
+		vha->qla_stats.qla_dif_stats.dif_input_requests++;
 	}
 
 	if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) ||
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 5fd3b07..ccdb890 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1872,6 +1872,7 @@  struct scsi_dif_tuple {
 		set_driver_byte(cmd, DRIVER_SENSE);
 		set_host_byte(cmd, DID_ABORT);
 		cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
+		vha->qla_stats.qla_dif_stats.dif_guard_err++;
 		return 1;
 	}
 
@@ -1882,6 +1883,7 @@  struct scsi_dif_tuple {
 		set_driver_byte(cmd, DRIVER_SENSE);
 		set_host_byte(cmd, DID_ABORT);
 		cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
+		vha->qla_stats.qla_dif_stats.dif_ref_tag_err++;
 		return 1;
 	}
 
@@ -1892,6 +1894,7 @@  struct scsi_dif_tuple {
 		set_driver_byte(cmd, DRIVER_SENSE);
 		set_host_byte(cmd, DID_ABORT);
 		cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
+		vha->qla_stats.qla_dif_stats.dif_app_tag_err++;
 		return 1;
 	}
 
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index cf4f86d..8c42ff4 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -36,8 +36,6 @@ 
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
-#include <target/target_core_base.h>
-#include <target/target_core_fabric.h>
 
 #include "qla_def.h"
 #include "qla_target.h"
@@ -129,6 +127,28 @@  static void qlt_send_term_imm_notif(struct scsi_qla_host *vha,
 LIST_HEAD(qla_tgt_glist);
 EXPORT_SYMBOL(qla_tgt_glist);
 
+static const char *prot_op_str(u32 prot_op)
+{
+	switch (prot_op) {
+	case QLA_PROT_NORMAL:
+	    return "NORMAL";
+	case QLA_PROT_DIN_INSERT:
+	    return "DIN_INSERT";
+	case QLA_PROT_DOUT_INSERT:
+	    return "DOUT_INSERT";
+	case QLA_PROT_DIN_STRIP:
+	    return "DIN_STRIP";
+	case QLA_PROT_DOUT_STRIP:
+	    return "DOUT_STRIP";
+	case QLA_PROT_DIN_PASS:
+	    return "DIN_PASS";
+	case QLA_PROT_DOUT_PASS:
+	    return "DOUT_PASS";
+	default:
+	    return "UNKNOWN";
+	}
+}
+
 /* This API intentionally takes dest as a parameter, rather than returning
  * int value to avoid caller forgetting to issue wmb() after the store */
 void qlt_do_generation_tick(struct scsi_qla_host *vha, int *dest)
@@ -1603,6 +1623,99 @@  static void qlt_24xx_send_task_mgmt_ctio(struct scsi_qla_host *ha,
 	qla2x00_start_iocbs(ha, ha->req);
 }
 
+/* ha->hardware_lock supposed to be held on entry */
+static inline uint32_t qlt_make_handle(struct scsi_qla_host *vha)
+{
+	struct qla_hw_data *ha = vha->hw;
+	uint32_t h;
+
+	h = ha->tgt.current_handle;
+	/* always increment cmd handle */
+	do {
+		++h;
+		if (h > DEFAULT_OUTSTANDING_COMMANDS)
+			h = 1; /* 0 is QLA_TGT_NULL_HANDLE */
+		if (h == ha->tgt.current_handle) {
+			ql_dbg(ql_dbg_io, vha, 0x305b,
+			    "qla_target(%d): Ran out of "
+			    "empty cmd slots in ha %p\n", vha->vp_idx, ha);
+			h = QLA_TGT_NULL_HANDLE;
+			break;
+		}
+	} while ((h == QLA_TGT_NULL_HANDLE) ||
+	    (h == QLA_TGT_SKIP_HANDLE) ||
+	    (ha->tgt.cmds[h-1] != NULL));
+
+	if (h != QLA_TGT_NULL_HANDLE)
+		ha->tgt.current_handle = h;
+
+	return h;
+}
+/* Code added for T10 DIF support */
+/*
+ * ha->hardware_lock supposed to be held on entry. Might drop it, then reacquire
+ */
+void qlt_send_resp_ctio(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
+	uint8_t scsi_status, uint8_t sense_key, uint8_t asc, uint8_t ascq)
+{
+	struct atio_from_isp *atio = &cmd->atio;
+	struct ctio7_to_24xx *ctio;
+	uint16_t temp;
+
+
+	ql_dbg(ql_dbg_tgt_dif, vha, 0x3066,
+		  "Sending response CTIO7 (vha=%p, atio=%p, scsi_status=%02x, "
+		  "sense_key=%02x, asc=%02x, ascq=%02x",
+		  vha, atio, scsi_status, sense_key, asc, ascq);
+
+	ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs(vha, NULL);
+	if (ctio == NULL) {
+		ql_dbg(ql_dbg_async, vha, 0x3067,
+			"qla2x00t(%ld): %s failed: unable to allocate "
+			"request packet", vha->host_no, __func__);
+		goto out;
+	}
+
+	ctio->entry_type = CTIO_TYPE7;
+	ctio->entry_count = 1;
+	ctio->handle = QLA_TGT_SKIP_HANDLE;
+	ctio->nport_handle = cmd->sess->loop_id;
+	ctio->timeout = __constant_cpu_to_le16(QLA_TGT_TIMEOUT);
+	ctio->vp_index = vha->vp_idx;
+	ctio->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2];
+	ctio->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1];
+	ctio->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0];
+	ctio->exchange_addr = atio->u.isp24.exchange_addr;
+	ctio->u.status1.flags = (atio->u.isp24.attr << 9) |
+	    cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS);
+	temp = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id);
+	ctio->u.status1.ox_id = cpu_to_le16(temp);
+	ctio->u.status1.scsi_status =
+	    cpu_to_le16(SS_RESPONSE_INFO_LEN_VALID | scsi_status);
+	ctio->u.status1.response_len = __constant_cpu_to_le16(18);
+
+	ctio->u.status1.residual = get_unaligned((uint32_t *)
+		&atio->u.isp24.fcp_cmnd.add_cdb[0]);
+	if (ctio->u.status1.residual != 0)
+		ctio->u.status1.scsi_status |= __constant_cpu_to_le16(SS_RESIDUAL_UNDER);
+
+	/* Response code and sense key */
+	((uint32_t *)ctio->u.status1.sense_data)[0] =
+		cpu_to_le32((0x70 << 24) | (sense_key << 8));
+	/* Additional sense length */
+	((uint32_t *)ctio->u.status1.sense_data)[1] = __constant_cpu_to_le32(0x0a);
+	/* ASC and ASCQ */
+	((uint32_t *)ctio->u.status1.sense_data)[3] = cpu_to_le32((asc << 24) |
+							(ascq << 16));
+
+	/* Memory Barrier */
+	wmb();
+	qla2x00_start_iocbs(vha, vha->req);
+
+out:
+	return;
+}
+
 /* callback from target fabric module code */
 void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
 {
@@ -1669,7 +1782,7 @@  static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm)
 
 	prm->cmd->sg_mapped = 1;
 
-	if (cmd->se_cmd.prot_op == TARGET_PROT_NORMAL) {
+	if (cmd->prot_op == QLA_PROT_NORMAL) {
 		/*
 		 * If greater than four sg entries then we need to allocate
 		 * the continuation entries
@@ -1680,8 +1793,8 @@  static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm)
 			prm->tgt->datasegs_per_cont);
 	} else {
 		/* DIF */
-		if ((cmd->se_cmd.prot_op == TARGET_PROT_DIN_INSERT) ||
-		    (cmd->se_cmd.prot_op == TARGET_PROT_DOUT_STRIP)) {
+		if ((cmd->prot_op == QLA_PROT_DIN_INSERT) ||
+		    (cmd->prot_op == QLA_PROT_DOUT_STRIP)) {
 			prm->seg_cnt = DIV_ROUND_UP(cmd->bufflen, cmd->blk_sz);
 			prm->tot_dsds = prm->seg_cnt;
 		} else
@@ -1695,8 +1808,8 @@  static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm)
 			if (unlikely(prm->prot_seg_cnt == 0))
 				goto out_err;
 
-			if ((cmd->se_cmd.prot_op == TARGET_PROT_DIN_INSERT) ||
-			    (cmd->se_cmd.prot_op == TARGET_PROT_DOUT_STRIP)) {
+			if ((cmd->prot_op == QLA_PROT_DIN_INSERT) ||
+			    (cmd->prot_op == QLA_PROT_DOUT_STRIP)) {
 				/* Dif Bundling not support here */
 				prm->prot_seg_cnt = DIV_ROUND_UP(cmd->bufflen,
 								cmd->blk_sz);
@@ -1782,34 +1895,6 @@  static inline void *qlt_get_req_pkt(struct scsi_qla_host *vha)
 	return (cont_entry_t *)vha->req->ring_ptr;
 }
 
-/* ha->hardware_lock supposed to be held on entry */
-static inline uint32_t qlt_make_handle(struct scsi_qla_host *vha)
-{
-	struct qla_hw_data *ha = vha->hw;
-	uint32_t h;
-
-	h = ha->tgt.current_handle;
-	/* always increment cmd handle */
-	do {
-		++h;
-		if (h > DEFAULT_OUTSTANDING_COMMANDS)
-			h = 1; /* 0 is QLA_TGT_NULL_HANDLE */
-		if (h == ha->tgt.current_handle) {
-			ql_dbg(ql_dbg_io, vha, 0x305b,
-			    "qla_target(%d): Ran out of "
-			    "empty cmd slots in ha %p\n", vha->vp_idx, ha);
-			h = QLA_TGT_NULL_HANDLE;
-			break;
-		}
-	} while ((h == QLA_TGT_NULL_HANDLE) ||
-	    (h == QLA_TGT_SKIP_HANDLE) ||
-	    (ha->tgt.cmds[h-1] != NULL));
-
-	if (h != QLA_TGT_NULL_HANDLE)
-		ha->tgt.current_handle = h;
-
-	return h;
-}
 
 /* ha->hardware_lock supposed to be held on entry */
 static int qlt_24xx_build_ctio_pkt(struct qla_tgt_prm *prm,
@@ -2143,6 +2228,60 @@  static inline void qlt_check_srr_debug(struct qla_tgt_cmd *cmd, int *xmit_type)
 {}
 #endif
 
+
+static void qlt_print_dif_err(struct qla_tgt_prm *prm)
+{
+	struct qla_tgt_cmd *cmd;
+	struct scsi_qla_host *vha;
+
+
+	/* asc 0x10=dif error */
+	if (prm->sense_buffer && (prm->sense_buffer[12] == 0x10)) {
+
+		cmd = prm->cmd;
+		vha = cmd->vha;
+		/* ASCQ */
+		switch (prm->sense_buffer[13]) {
+		case 1:
+			ql_dbg(ql_dbg_tgt_dif, vha, 0xffff,
+				"BE detected Guard TAG ERR: lba[0x%llx|%lld] len[0x%x] "
+				"ulp_cmd=%p tag[%x]",
+				cmd->lba, cmd->lba,
+				cmd->num_blks, cmd->ulp_cmd,
+				cmd->atio.u.isp24.exchange_addr);
+			break;
+		case 2:
+			ql_dbg(ql_dbg_tgt_dif, vha, 0xffff,
+				"BE detected APP TAG ERR: lba[0x%llx|%lld] len[0x%x] "
+				"ulp_cmd=%p tag[%x]",
+				cmd->lba, cmd->lba,
+				cmd->num_blks, cmd->ulp_cmd,
+				cmd->atio.u.isp24.exchange_addr);
+			break;
+		case 3:
+			ql_dbg(ql_dbg_tgt_dif, vha, 0xffff,
+				"BE detected REF TAG ERR: lba[0x%llx|%lld] len[0x%x] "
+				"ulp_cmd=%p tag[%x]",
+				cmd->lba, cmd->lba,
+				cmd->num_blks, cmd->ulp_cmd,
+				cmd->atio.u.isp24.exchange_addr);
+			break;
+		default:
+			ql_dbg(ql_dbg_tgt_dif, vha, 0xffff,
+				"BE detected Dif ERR: lba[%llx|%lld] len[%x] "
+				"ulp_cmd=%p tag[%x]",
+				cmd->lba, cmd->lba,
+				cmd->num_blks, cmd->ulp_cmd,
+				cmd->atio.u.isp24.exchange_addr);
+			break;
+		}
+
+		ql_dump_buffer(ql_dbg_tgt_dif, vha, 0xffff,
+			cmd->cdb, 16);
+	}
+}
+
+
 static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 	struct qla_tgt_prm *prm)
 {
@@ -2183,18 +2322,9 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 		for (i = 0; i < prm->sense_buffer_len/4; i++)
 			((uint32_t *)ctio->u.status1.sense_data)[i] =
 				cpu_to_be32(((uint32_t *)prm->sense_buffer)[i]);
-#if 0
-		if (unlikely((prm->sense_buffer_len % 4) != 0)) {
-			static int q;
-			if (q < 10) {
-				ql_dbg(ql_dbg_tgt, vha, 0xe04f,
-				    "qla_target(%d): %d bytes of sense "
-				    "lost", prm->tgt->ha->vp_idx,
-				    prm->sense_buffer_len % 4);
-				q++;
-			}
-		}
-#endif
+
+		qlt_print_dif_err(prm);
+
 	} else {
 		ctio->u.status1.flags &=
 		    ~cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_0);
@@ -2212,7 +2342,7 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 
 /* diff  */
 static inline int
-qlt_hba_err_chk_enabled(struct se_cmd *se_cmd)
+qlt_hba_err_chk_enabled(struct qla_tgt_cmd *cmd)
 {
 	/*
 	 * Uncomment when corresponding SCSI changes are done.
@@ -2221,19 +2351,19 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 	 return 0;
 	 *
 	 */
-	switch (se_cmd->prot_op) {
-	case TARGET_PROT_DOUT_INSERT:
-	case TARGET_PROT_DIN_STRIP:
+	switch (cmd->prot_op) {
+	case QLA_PROT_DOUT_INSERT:
+	case QLA_PROT_DIN_STRIP:
 		if (ql2xenablehba_err_chk >= 1)
 			return 1;
 		break;
-	case TARGET_PROT_DOUT_PASS:
-	case TARGET_PROT_DIN_PASS:
+	case QLA_PROT_DOUT_PASS:
+	case QLA_PROT_DIN_PASS:
 		if (ql2xenablehba_err_chk >= 2)
 			return 1;
 		break;
-	case TARGET_PROT_DIN_INSERT:
-	case TARGET_PROT_DOUT_STRIP:
+	case QLA_PROT_DIN_INSERT:
+	case QLA_PROT_DOUT_STRIP:
 		return 1;
 	default:
 		break;
@@ -2241,14 +2371,32 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 	return 0;
 }
 
-/*
- * qla24xx_set_t10dif_tags_from_cmd - Extract Ref and App tags from SCSI command
- *
- */
-static inline void
-qlt_set_t10dif_tags(struct se_cmd *se_cmd, struct crc_context *ctx)
+static inline int
+qla_tgt_ref_mask_check(struct qla_tgt_cmd *cmd)
+{
+	switch (cmd->prot_op) {
+	case QLA_PROT_DIN_INSERT:
+	case QLA_PROT_DOUT_INSERT:
+	case QLA_PROT_DIN_STRIP:
+	case QLA_PROT_DOUT_STRIP:
+	case QLA_PROT_DIN_PASS:
+	case QLA_PROT_DOUT_PASS:
+		return 1;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static void
+qla_tgt_set_dif_tags(struct qla_tgt_cmd *cmd, struct crc_context *ctx,
+    uint16_t *pfw_prot_opts)
 {
-	uint32_t lba = 0xffffffff & se_cmd->t_task_lba;
+	uint32_t lba = 0xffffffff & cmd->lba;
+	uint32_t t32 = 0;
+	scsi_qla_host_t *vha = cmd->tgt->vha;
+	struct qla_hw_data *ha = vha->hw;
 
 	/* wait til Mode Sense/Select cmd, modepage Ah, subpage 2
 	 * have been immplemented by TCM, before AppTag is avail.
@@ -2258,17 +2406,32 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 	ctx->app_tag_mask[0] = 0x0;
 	ctx->app_tag_mask[1] = 0x0;
 
-	switch (se_cmd->prot_type) {
-	case TARGET_DIF_TYPE0_PROT:
+	if (IS_PI_UNINIT_CAPABLE(ha)) {
+		if ((cmd->prot_type == QLA_TGT_PROT_TYPE1) ||
+			(cmd->prot_type == QLA_TGT_PROT_TYPE2))
+		*pfw_prot_opts |= PO_DIS_VALD_APP_ESC;
+		else if (cmd->prot_type == QLA_TGT_PROT_TYPE3)
+			*pfw_prot_opts |= PO_DIS_VALD_APP_REF_ESC;
+	}
+
+	t32 = ha->tgt.tgt_ops->get_dif_tags(cmd, pfw_prot_opts);
+
+#if 0
+	if (cmd->prot_op == TARGET_PROT_PASS_NOCHECK) {
+		*pfw_prot_opts |= PO_DISABLE_GUARD_CHECK|
+		PO_DIS_APP_TAG_VALD|PO_DIS_REF_TAG_VALD;
+		return;
+	}
+#endif
+
+	switch (cmd->prot_type) {
+	case QLA_TGT_PROT_TYPE0:
 		/*
 		 * No check for ql2xenablehba_err_chk, as it would be an
 		 * I/O error if hba tag generation is not done.
 		 */
 		ctx->ref_tag = cpu_to_le32(lba);
 
-		if (!qlt_hba_err_chk_enabled(se_cmd))
-			break;
-
 		/* enable ALL bytes of the ref tag */
 		ctx->ref_tag_mask[0] = 0xff;
 		ctx->ref_tag_mask[1] = 0xff;
@@ -2279,11 +2442,14 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 	 * For TYpe 1 protection: 16 bit GUARD tag, 32 bit REF tag, and
 	 * 16 bit app tag.
 	 */
-	case TARGET_DIF_TYPE1_PROT:
+	case QLA_TGT_PROT_TYPE1:
 		ctx->ref_tag = cpu_to_le32(lba);
 
-		if (!qlt_hba_err_chk_enabled(se_cmd))
+		if (!qla_tgt_ref_mask_check(cmd) ||
+		    !(ha->tgt.tgt_ops->chk_dif_tags(t32))) {
+			*pfw_prot_opts |= PO_DIS_REF_TAG_VALD;
 			break;
+		}
 
 		/* enable ALL bytes of the ref tag */
 		ctx->ref_tag_mask[0] = 0xff;
@@ -2295,11 +2461,14 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 	 * For TYPE 2 protection: 16 bit GUARD + 32 bit REF tag has to
 	 * match LBA in CDB + N
 	 */
-	case TARGET_DIF_TYPE2_PROT:
+	case QLA_TGT_PROT_TYPE2:
 		ctx->ref_tag = cpu_to_le32(lba);
 
-		if (!qlt_hba_err_chk_enabled(se_cmd))
+		if (!qla_tgt_ref_mask_check(cmd) ||
+		    !(ha->tgt.tgt_ops->chk_dif_tags(t32))) {
+			*pfw_prot_opts |= PO_DIS_REF_TAG_VALD;
 			break;
+		}
 
 		/* enable ALL bytes of the ref tag */
 		ctx->ref_tag_mask[0] = 0xff;
@@ -2309,14 +2478,13 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 		break;
 
 	/* For Type 3 protection: 16 bit GUARD only */
-	case TARGET_DIF_TYPE3_PROT:
+	case QLA_TGT_PROT_TYPE3:
+		*pfw_prot_opts |= PO_DIS_REF_TAG_VALD;
 		ctx->ref_tag_mask[0] = ctx->ref_tag_mask[1] =
 			ctx->ref_tag_mask[2] = ctx->ref_tag_mask[3] = 0x00;
 		break;
 	}
 }
-
-
 static inline int
 qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha)
 {
@@ -2332,10 +2500,10 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 	dma_addr_t		crc_ctx_dma;
 	uint16_t		fw_prot_opts = 0;
 	struct qla_tgt_cmd	*cmd = prm->cmd;
-	struct se_cmd		*se_cmd = &cmd->se_cmd;
 	uint32_t h;
 	struct atio_from_isp *atio = &prm->cmd->atio;
 	uint16_t t16;
+	struct qla_tc_param     tc;
 
 	ha = vha->hw;
 
@@ -2345,28 +2513,29 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 
 	ql_dbg(ql_dbg_tgt, vha, 0xe071,
 	    "qla_target(%d):%s: ulp_cmd[%p] CRC2 prot_op[0x%x] cmd prot sg:cnt[%p:%x] lba[%llu]\n",
-	    vha->vp_idx, __func__, se_cmd, se_cmd->prot_op,
+	    vha->vp_idx, __func__, cmd->ulp_cmd, cmd->prot_op,
 	    prm->prot_sg, prm->prot_seg_cnt, cmd->lba);
 
-	if ((se_cmd->prot_op == TARGET_PROT_DIN_INSERT) ||
-	    (se_cmd->prot_op == TARGET_PROT_DOUT_STRIP))
+	if ((cmd->prot_op == QLA_PROT_DIN_INSERT) ||
+	    (cmd->prot_op == QLA_PROT_DOUT_STRIP))
 		bundling = 0;
 
 	/* Compute dif len and adjust data len to incude protection */
 	data_bytes = cmd->bufflen;
 	dif_bytes  = (data_bytes / cmd->blk_sz) * 8;
 
-	switch (se_cmd->prot_op) {
-	case TARGET_PROT_DIN_INSERT:
-	case TARGET_PROT_DOUT_STRIP:
+	switch (cmd->prot_op) {
+	case QLA_PROT_DIN_INSERT:
+	case QLA_PROT_DOUT_STRIP:
 		transfer_length = data_bytes;
-		data_bytes += dif_bytes;
+		if (cmd->prot_sg_cnt)
+			data_bytes += dif_bytes;
 		break;
 
-	case TARGET_PROT_DIN_STRIP:
-	case TARGET_PROT_DOUT_INSERT:
-	case TARGET_PROT_DIN_PASS:
-	case TARGET_PROT_DOUT_PASS:
+	case QLA_PROT_DIN_STRIP:
+	case QLA_PROT_DOUT_INSERT:
+	case QLA_PROT_DIN_PASS:
+	case QLA_PROT_DOUT_PASS:
 		transfer_length = data_bytes + dif_bytes;
 		break;
 
@@ -2374,29 +2543,30 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 		BUG();
 		break;
 	}
-
-	if (!qlt_hba_err_chk_enabled(se_cmd))
+	if (!qlt_hba_err_chk_enabled(cmd))
 		fw_prot_opts |= 0x10; /* Disable Guard tag checking */
 	/* HBA error checking enabled */
 	else if (IS_PI_UNINIT_CAPABLE(ha)) {
-		if ((se_cmd->prot_type == TARGET_DIF_TYPE1_PROT) ||
-		    (se_cmd->prot_type == TARGET_DIF_TYPE2_PROT))
+		if ((cmd->prot_type == QLA_TGT_PROT_TYPE1) ||
+		    (cmd->prot_type == QLA_TGT_PROT_TYPE2))
 			fw_prot_opts |= PO_DIS_VALD_APP_ESC;
-		else if (se_cmd->prot_type == TARGET_DIF_TYPE3_PROT)
+		else if (cmd->prot_type == QLA_TGT_PROT_TYPE3)
 			fw_prot_opts |= PO_DIS_VALD_APP_REF_ESC;
 	}
 
-	switch (se_cmd->prot_op) {
-	case TARGET_PROT_DIN_INSERT:
-	case TARGET_PROT_DOUT_INSERT:
+	switch (cmd->prot_op) {
+	case QLA_PROT_DIN_INSERT:
+	case QLA_PROT_DOUT_INSERT:
 		fw_prot_opts |= PO_MODE_DIF_INSERT;
+		bundling = 0;
 		break;
-	case TARGET_PROT_DIN_STRIP:
-	case TARGET_PROT_DOUT_STRIP:
+	case QLA_PROT_DIN_STRIP:
+	case QLA_PROT_DOUT_STRIP:
 		fw_prot_opts |= PO_MODE_DIF_REMOVE;
+		bundling = 0;
 		break;
-	case TARGET_PROT_DIN_PASS:
-	case TARGET_PROT_DOUT_PASS:
+	case QLA_PROT_DIN_PASS:
+	case QLA_PROT_DOUT_PASS:
 		fw_prot_opts |= PO_MODE_DIF_PASS;
 		/* FUTURE: does tcm require T10CRC<->IPCKSUM conversion? */
 		break;
@@ -2425,7 +2595,7 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 
 
 	pkt->handle  = h | CTIO_COMPLETION_HANDLE_MARK;
-	pkt->nport_handle = prm->cmd->loop_id;
+	pkt->nport_handle = cpu_to_le16(prm->cmd->loop_id);
 	pkt->timeout = cpu_to_le16(QLA_TGT_TIMEOUT);
 	pkt->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2];
 	pkt->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1];
@@ -2471,7 +2641,7 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 	/* Set handle */
 	crc_ctx_pkt->handle = pkt->handle;
 
-	qlt_set_t10dif_tags(se_cmd, crc_ctx_pkt);
+	qla_tgt_set_dif_tags(cmd, crc_ctx_pkt, &fw_prot_opts);
 
 	pkt->crc_context_address[0] = cpu_to_le32(LSD(crc_ctx_dma));
 	pkt->crc_context_address[1] = cpu_to_le32(MSD(crc_ctx_dma));
@@ -2498,16 +2668,24 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 	crc_ctx_pkt->byte_count = cpu_to_le32(data_bytes);
 	crc_ctx_pkt->guard_seed = cpu_to_le16(0);
 
+	memset((uint8_t *)&tc, 0 , sizeof(tc));
+	tc.vha     = vha;
+	tc.blk_sz  = cmd->blk_sz;
+	tc.bufflen = cmd->bufflen;
+	tc.sg      = cmd->sg;
+	tc.prot_sg = cmd->prot_sg;
+	tc.ctx     = crc_ctx_pkt;
+	tc.ctx_dsd_alloced = &cmd->ctx_dsd_alloced;
 
 	/* Walks data segments */
 	pkt->flags |= cpu_to_le16(CTIO7_FLAGS_DSD_PTR);
 
 	if (!bundling && prm->prot_seg_cnt) {
 		if (qla24xx_walk_and_build_sglist_no_difb(ha, NULL, cur_dsd,
-			prm->tot_dsds, cmd))
+			prm->tot_dsds, &tc))
 			goto crc_queuing_error;
 	} else if (qla24xx_walk_and_build_sglist(ha, NULL, cur_dsd,
-		(prm->tot_dsds - prm->prot_seg_cnt), cmd))
+		(prm->tot_dsds - prm->prot_seg_cnt), &tc))
 		goto crc_queuing_error;
 
 	if (bundling && prm->prot_seg_cnt) {
@@ -2516,13 +2694,14 @@  static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio,
 
 		cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address;
 		if (qla24xx_walk_and_build_prot_sglist(ha, NULL, cur_dsd,
-			prm->prot_seg_cnt, cmd))
+			prm->prot_seg_cnt, &tc))
 			goto crc_queuing_error;
 	}
 	return QLA_SUCCESS;
 
 crc_queuing_error:
 	/* Cleanup will be performed by the caller */
+	vha->hw->tgt.cmds[h-1] = NULL;
 
 	return QLA_FUNCTION_FAILED;
 }
@@ -2598,10 +2777,14 @@  int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
 	if (unlikely(res))
 		goto out_unmap_unlock;
 
-	if (cmd->se_cmd.prot_op && (xmit_type & QLA_TGT_XMIT_DATA))
+	if (cmd->prot_op &&
+	    (xmit_type & QLA_TGT_XMIT_DATA) &&
+	    qlt_has_data(cmd)) {
 		res = qlt_build_ctio_crc2_pkt(&prm, vha);
+	}
 	else
 		res = qlt_24xx_build_ctio_pkt(&prm, vha);
+
 	if (unlikely(res != 0)) {
 		vha->req->cnt += full_req_cnt;
 		goto out_unmap_unlock;
@@ -2614,7 +2797,7 @@  int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
 		    cpu_to_le16(CTIO7_FLAGS_DATA_IN |
 			CTIO7_FLAGS_STATUS_MODE_0);
 
-		if (cmd->se_cmd.prot_op == TARGET_PROT_NORMAL)
+		if (cmd->prot_op == QLA_PROT_NORMAL)
 			qlt_load_data_segments(&prm, vha);
 
 		if (prm.add_status_pkt == 0) {
@@ -2739,7 +2922,7 @@  int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
 	res = qlt_check_reserve_free_req(vha, prm.req_cnt);
 	if (res != 0)
 		goto out_unlock_free_unmap;
-	if (cmd->se_cmd.prot_op)
+	if (cmd->prot_op != QLA_PROT_NORMAL)
 		res = qlt_build_ctio_crc2_pkt(&prm, vha);
 	else
 		res = qlt_24xx_build_ctio_pkt(&prm, vha);
@@ -2753,7 +2936,7 @@  int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
 	pkt->u.status0.flags |= cpu_to_le16(CTIO7_FLAGS_DATA_OUT |
 	    CTIO7_FLAGS_STATUS_MODE_0);
 
-	if (cmd->se_cmd.prot_op == TARGET_PROT_NORMAL)
+	if (cmd->prot_op == QLA_PROT_NORMAL)
 		qlt_load_data_segments(&prm, vha);
 
 	cmd->state = QLA_TGT_STATE_NEED_DATA;
@@ -2776,50 +2959,47 @@  int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
 
 
 /*
- * Checks the guard or meta-data for the type of error
- * detected by the HBA.
+ * it is assumed either hardware_lock or qpair lock is held.
  */
-static inline int
+static void
 qlt_handle_dif_error(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd,
-		struct ctio_crc_from_fw *sts)
+	struct ctio_crc_from_fw *sts)
 {
 	uint8_t		*ap = &sts->actual_dif[0];
 	uint8_t		*ep = &sts->expected_dif[0];
-	uint32_t	e_ref_tag, a_ref_tag;
-	uint16_t	e_app_tag, a_app_tag;
-	uint16_t	e_guard, a_guard;
 	uint64_t	lba = cmd->lba;
+	uint8_t scsi_status, sense_key, asc, ascq;
+	unsigned long flags;
 
-	a_guard   = be16_to_cpu(*(uint16_t *)(ap + 0));
-	a_app_tag = be16_to_cpu(*(uint16_t *)(ap + 2));
-	a_ref_tag = be32_to_cpu(*(uint32_t *)(ap + 4));
+	cmd->trc_flags |= TRC_DIF_ERR;
 
-	e_guard   = be16_to_cpu(*(uint16_t *)(ep + 0));
-	e_app_tag = be16_to_cpu(*(uint16_t *)(ep + 2));
-	e_ref_tag = be32_to_cpu(*(uint32_t *)(ep + 4));
+	cmd->a_guard   = be16_to_cpu(*(uint16_t *)(ap + 0));
+	cmd->a_app_tag = be16_to_cpu(*(uint16_t *)(ap + 2));
+	cmd->a_ref_tag = be32_to_cpu(*(uint32_t *)(ap + 4));
 
-	ql_dbg(ql_dbg_tgt, vha, 0xe075,
-	    "iocb(s) %p Returned STATUS.\n", sts);
+	cmd->e_guard   = be16_to_cpu(*(uint16_t *)(ep + 0));
+	cmd->e_app_tag = be16_to_cpu(*(uint16_t *)(ep + 2));
+	cmd->e_ref_tag = be32_to_cpu(*(uint32_t *)(ep + 4));
 
-	ql_dbg(ql_dbg_tgt, vha, 0xf075,
-	    "dif check TGT cdb 0x%x lba 0x%llx: [Actual|Expected] Ref Tag[0x%x|0x%x], App Tag [0x%x|0x%x], Guard [0x%x|0x%x]\n",
-	    cmd->atio.u.isp24.fcp_cmnd.cdb[0], lba,
-	    a_ref_tag, e_ref_tag, a_app_tag, e_app_tag, a_guard, e_guard);
+	ql_dbg(ql_dbg_tgt_dif, vha, 0xf075,
+	    "%s:  aborted %d state %d\n",
+		   __func__, cmd->aborted, cmd->state);
 
+	scsi_status = sense_key = asc = ascq = 0;
+
+#if 0
 	/*
 	 * Ignore sector if:
 	 * For type     3: ref & app tag is all 'f's
 	 * For type 0,1,2: app tag is all 'f's
 	 */
-	if ((a_app_tag == 0xffff) &&
-	    ((cmd->se_cmd.prot_type != TARGET_DIF_TYPE3_PROT) ||
-	     (a_ref_tag == 0xffffffff))) {
+	if ((cmd->a_app_tag == 0xffff) &&
+	    ((cmd->prot_type != QLA_TGT_PROT_TYPE3) ||
+	     (cmd->a_ref_tag == 0xffffffff))) {
 		uint32_t blocks_done;
 
 		/* 2TB boundary case covered automatically with this */
-		blocks_done = e_ref_tag - (uint32_t)lba + 1;
-		cmd->se_cmd.bad_sector = e_ref_tag;
-		cmd->se_cmd.pi_err = 0;
+		blocks_done = cmd->e_ref_tag - (uint32_t)lba + 1;
 		ql_dbg(ql_dbg_tgt, vha, 0xf074,
 			"need to return scsi good\n");
 
@@ -2828,7 +3008,6 @@  int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
 			uint32_t i, k = 0, num_ent;
 			struct scatterlist *sg, *sgl;
 
-
 			sgl = cmd->prot_sg;
 
 			/* Patch the corresponding protection tags */
@@ -2845,68 +3024,97 @@  int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
 			if (k != blocks_done) {
 				ql_log(ql_log_warn, vha, 0xf076,
 				    "unexpected tag values tag:lba=%u:%llu)\n",
-				    e_ref_tag, (unsigned long long)lba);
+				    cmd->e_ref_tag, (unsigned long long)lba);
 				goto out;
 			}
-
-#if 0
-			struct sd_dif_tuple *spt;
-			/* TODO:
-			 * This section came from initiator. Is it valid here?
-			 * should ulp be override with actual val???
-			 */
-			spt = page_address(sg_page(sg)) + sg->offset;
-			spt += j;
-
-			spt->app_tag = 0xffff;
-			if (cmd->se_cmd.prot_type == SCSI_PROT_DIF_TYPE3)
-				spt->ref_tag = 0xffffffff;
-#endif
 		}
-
-		return 0;
 	}
+#endif
 
-	/* check guard */
-	if (e_guard != a_guard) {
-		cmd->se_cmd.pi_err = TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED;
-		cmd->se_cmd.bad_sector = cmd->lba;
-
-		ql_log(ql_log_warn, vha, 0xe076,
-		    "Guard ERR: cdb 0x%x lba 0x%llx: [Actual|Expected] Ref Tag[0x%x|0x%x], App Tag [0x%x|0x%x], Guard [0x%x|0x%x] cmd=%p\n",
-		    cmd->atio.u.isp24.fcp_cmnd.cdb[0], lba,
-		    a_ref_tag, e_ref_tag, a_app_tag, e_app_tag,
-		    a_guard, e_guard, cmd);
-		goto out;
+	/* check appl tag */
+	if (cmd->e_app_tag != cmd->a_app_tag) {
+		ql_dbg(ql_dbg_tgt_dif, vha, 0xffff,
+			"App Tag ERR: cdb[%x] lba[%llx %llx] blks[%x] [Actual|Expected] "
+			"Ref[%x|%x], App[%x|%x], "
+			"Guard [%x|%x] cmd=%p ox_id[%04x]",
+			cmd->cdb[0], lba, (lba+cmd->num_blks), cmd->num_blks,
+			cmd->a_ref_tag, cmd->e_ref_tag,
+			cmd->a_app_tag, cmd->e_app_tag,
+			cmd->a_guard, cmd->e_guard,
+			cmd, cmd->atio.u.isp24.fcp_hdr.ox_id);
+
+		cmd->dif_err_code = DIF_ERR_APP;
+		scsi_status = SAM_STAT_CHECK_CONDITION;
+		sense_key = ABORTED_COMMAND;
+		asc = 0x10;
+		ascq = 0x2;
 	}
 
 	/* check ref tag */
-	if (e_ref_tag != a_ref_tag) {
-		cmd->se_cmd.pi_err = TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED;
-		cmd->se_cmd.bad_sector = e_ref_tag;
-
-		ql_log(ql_log_warn, vha, 0xe077,
-			"Ref Tag ERR: cdb 0x%x lba 0x%llx: [Actual|Expected] Ref Tag[0x%x|0x%x], App Tag [0x%x|0x%x], Guard [0x%x|0x%x] cmd=%p\n",
-			cmd->atio.u.isp24.fcp_cmnd.cdb[0], lba,
-			a_ref_tag, e_ref_tag, a_app_tag, e_app_tag,
-			a_guard, e_guard, cmd);
+	if (cmd->e_ref_tag != cmd->a_ref_tag) {
+		ql_dbg(ql_dbg_tgt_dif, vha, 0xffff,
+			"Ref Tag ERR: cdb[%x] lba[%llx %llx] blks[%x] [Actual|Expected] "
+			"Ref[%x|%x], App[%x|%x], "
+			"Guard[%x|%x] cmd=%p ox_id[%04x] ",
+			cmd->cdb[0], lba, (lba+cmd->num_blks), cmd->num_blks,
+			cmd->a_ref_tag, cmd->e_ref_tag,
+			cmd->a_app_tag, cmd->e_app_tag,
+			cmd->a_guard, cmd->e_guard,
+			cmd, cmd->atio.u.isp24.fcp_hdr.ox_id);
+
+		cmd->dif_err_code = DIF_ERR_REF;
+		scsi_status = SAM_STAT_CHECK_CONDITION;
+		sense_key = ABORTED_COMMAND;
+		asc = 0x10;
+		ascq = 0x3;
 		goto out;
 	}
 
-	/* check appl tag */
-	if (e_app_tag != a_app_tag) {
-		cmd->se_cmd.pi_err = TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED;
-		cmd->se_cmd.bad_sector = cmd->lba;
-
-		ql_log(ql_log_warn, vha, 0xe078,
-			"App Tag ERR: cdb 0x%x lba 0x%llx: [Actual|Expected] Ref Tag[0x%x|0x%x], App Tag [0x%x|0x%x], Guard [0x%x|0x%x] cmd=%p\n",
-			cmd->atio.u.isp24.fcp_cmnd.cdb[0], lba,
-			a_ref_tag, e_ref_tag, a_app_tag, e_app_tag,
-			a_guard, e_guard, cmd);
+	/* check guard */
+	if (cmd->e_guard != cmd->a_guard) {
+		ql_dbg(ql_dbg_tgt_dif, vha, 0xffff,
+			"Guard ERR: cdb[%x] lba[%llx %llx] blks[%x] [Actual|Expected] "
+			"Ref[%x|%x], App[%x|%x], "
+			"Guard [%x|%x] cmd=%p ox_id[%04x]",
+			cmd->cdb[0], lba, (lba+cmd->num_blks), cmd->num_blks,
+			cmd->a_ref_tag, cmd->e_ref_tag,
+			cmd->a_app_tag, cmd->e_app_tag,
+			cmd->a_guard, cmd->e_guard,
+			cmd, cmd->atio.u.isp24.fcp_hdr.ox_id);
+
+		cmd->dif_err_code = DIF_ERR_GRD;
+		scsi_status = SAM_STAT_CHECK_CONDITION;
+		sense_key = ABORTED_COMMAND;
+		asc = 0x10;
+		ascq = 0x1;
 		goto out;
 	}
+
 out:
-	return 1;
+	switch (cmd->state) {
+	case QLA_TGT_STATE_NEED_DATA:
+		/* handle_data will load DIF error code  */
+		cmd->state = QLA_TGT_STATE_DATA_IN;
+		vha->hw->tgt.tgt_ops->handle_data(cmd);
+		break;
+
+	default:
+		spin_lock_irqsave(&cmd->cmd_lock, flags);
+		if (cmd->aborted) {
+			spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+			vha->hw->tgt.tgt_ops->free_cmd(cmd);
+			break;
+		}
+		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
+		qlt_send_resp_ctio(vha, cmd, scsi_status, sense_key, asc, ascq);
+		/* assume scsi status gets out on the wire.
+		 * Will not wait for completion.
+		 */
+		vha->hw->tgt.tgt_ops->free_cmd(cmd);
+
+		break;
+	}
 }
 
 
@@ -3046,8 +3254,7 @@  static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
 
 	/* Most likely, it isn't needed */
 	ctio24->u.status1.residual = get_unaligned((uint32_t *)
-	    &atio->u.isp24.fcp_cmnd.add_cdb[
-	    atio->u.isp24.fcp_cmnd.add_cdb_len]);
+	    &atio->u.isp24.fcp_cmnd.add_cdb[0]);
 	if (ctio24->u.status1.residual != 0)
 		ctio24->u.status1.scsi_status |= SS_RESIDUAL_UNDER;
 
@@ -3281,6 +3488,17 @@  static int qlt_term_ctio_exchange(struct scsi_qla_host *vha, void *ctio,
 {
 	int term = 0;
 
+	if (cmd->prot_op) {
+		ql_dbg(ql_dbg_tgt_dif, vha, 0xffff,
+			   "Term DIF cmd: lba[0x%llx|%lld] len[0x%x] "
+			   "ulp_cmd=%p tag[%x] op %#x/%s",
+			   cmd->lba, cmd->lba,
+			   cmd->num_blks, cmd->ulp_cmd,
+			   cmd->atio.u.isp24.exchange_addr,
+			   cmd->prot_op,
+			   prot_op_str(cmd->prot_op));
+	}
+
 	if (ctio != NULL) {
 		struct ctio7_from_24xx *c = (struct ctio7_from_24xx *)ctio;
 		term = !(c->flags &
@@ -3505,32 +3723,15 @@  static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
 			struct ctio_crc_from_fw *crc =
 				(struct ctio_crc_from_fw *)ctio;
 			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf073,
-			    "qla_target(%d): CTIO with DIF_ERROR status %x received (state %x, ulp_cmd %p) actual_dif[0x%llx] expect_dif[0x%llx]\n",
+			    "qla_target(%d): CTIO with DIF_ERROR status %x "
+			    "received (state %x, ulp_cmd %p) actual_dif[0x%llx] "
+			    "expect_dif[0x%llx]\n",
 			    vha->vp_idx, status, cmd->state, ulp_cmd,
 			    *((u64 *)&crc->actual_dif[0]),
 			    *((u64 *)&crc->expected_dif[0]));
 
-			if (qlt_handle_dif_error(vha, cmd, ctio)) {
-				if (cmd->state == QLA_TGT_STATE_NEED_DATA) {
-					/* scsi Write/xfer rdy complete */
-					goto skip_term;
-				} else {
-					/* scsi read/xmit respond complete
-					 * call handle dif to send scsi status
-					 * rather than terminate exchange.
-					 */
-					cmd->state = QLA_TGT_STATE_PROCESSED;
-					ha->tgt.tgt_ops->handle_dif_err(cmd);
-					return;
-				}
-			} else {
-				/* Need to generate a SCSI good completion.
-				 * because FW did not send scsi status.
-				 */
-				status = 0;
-				goto skip_term;
-			}
-			break;
+			qlt_handle_dif_error(vha, cmd, ctio);
+			return;
 		}
 		default:
 			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05b,
@@ -3554,7 +3755,7 @@  static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
 				return;
 		}
 	}
-skip_term:
+
 
 	if (cmd->state == QLA_TGT_STATE_PROCESSED) {
 		cmd->trc_flags |= TRC_CTIO_DONE;
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index b09445d..c43910b 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -725,7 +725,6 @@  struct qla_tgt_func_tmpl {
 	int (*handle_cmd)(struct scsi_qla_host *, struct qla_tgt_cmd *,
 			unsigned char *, uint32_t, uint8_t, int, int);
 	void (*handle_data)(struct qla_tgt_cmd *);
-	void (*handle_dif_err)(struct qla_tgt_cmd *);
 	int (*handle_tmr)(struct qla_tgt_mgmt_cmd *, u64, uint16_t,
 			uint32_t);
 	void (*free_cmd)(struct qla_tgt_cmd *);
@@ -750,6 +749,8 @@  struct qla_tgt_func_tmpl {
 
 	/* support routine */
 	void (*srr_get_cur_state)(struct qla_tgt_cmd *, srr_state_op_t op);
+	int (*get_dif_tags)(struct qla_tgt_cmd *cmd, uint16_t *pfw_prot_opts);
+	int (*chk_dif_tags)(uint32_t tag);
 };
 
 int qla2x00_wait_for_hba_online(struct scsi_qla_host *);
@@ -907,6 +908,23 @@  enum qla_sess_deletion {
 	QLA_SESS_DELETION_IN_PROGRESS	= 2,
 };
 
+enum qla_tgt_prot_op {
+	QLA_PROT_NORMAL  = 0,
+	QLA_PROT_DIN_INSERT,
+	QLA_PROT_DOUT_INSERT,
+	QLA_PROT_DIN_STRIP,
+	QLA_PROT_DOUT_STRIP,
+	QLA_PROT_DIN_PASS,
+	QLA_PROT_DOUT_PASS,
+};
+
+enum qla_tgt_prot_type {
+	QLA_TGT_PROT_TYPE0,
+	QLA_TGT_PROT_TYPE1,
+	QLA_TGT_PROT_TYPE2,
+	QLA_TGT_PROT_TYPE3,
+};
+
 enum trace_flags {
 	TRC_NEW_CMD = BIT_0,
 	TRC_DO_WORK = BIT_1,
@@ -927,6 +945,7 @@  enum trace_flags {
 	TRC_CMD_CHK_STOP = BIT_16,
 	TRC_CMD_FREE = BIT_17,
 	TRC_DATA_IN = BIT_18,
+	TRC_DIF_ERR = BIT_19,
 };
 
 struct qla_tgt_cmd {
@@ -944,7 +963,6 @@  struct qla_tgt_cmd {
 	unsigned int sg_mapped:1;
 	unsigned int free_sg:1;
 	unsigned int write_data_transferred:1;
-	unsigned int ctx_dsd_alloced:1;
 	unsigned int q_full:1;
 	unsigned int term_exchg:1;
 	unsigned int cmd_sent_to_fw:1;
@@ -961,7 +979,6 @@  struct qla_tgt_cmd {
 	enum dma_data_direction dma_data_direction;
 	uint32_t reset_count;
 	int residual;				/* + = over, - = under */
-	int8_t scsi_status;
 
 	uint16_t loop_id;	/* to save extra sess dereferences */
 	struct qla_tgt *tgt;	/* to save extra sess dereferences */
@@ -973,9 +990,28 @@  struct qla_tgt_cmd {
 	struct scatterlist *prot_sg;
 	uint32_t prot_sg_cnt;
 	uint32_t blk_sz;
+	uint32_t num_blks;
+
+	uint8_t ctx_dsd_alloced; /* do not covert this field to bit field */
+
+	/* override scsi status in case of ULP does not T10-dif */
+	uint8_t dif_err_code;
+#define DIF_ERR_NONE 0
+#define DIF_ERR_GRD 1
+#define DIF_ERR_REF 2
+#define DIF_ERR_APP 3
+	uint8_t scsi_status;
+	uint8_t sense_key;
+	uint8_t asc;
+	uint8_t ascq;
+
 	struct crc_context *ctx;
+	uint32_t prot_op;			/* qla_tgt_prot_op */
+	uint32_t prot_type;
 	uint8_t  *cdb;
 	uint64_t lba;
+	uint32_t a_ref_tag, e_ref_tag;
+	uint16_t a_guard, e_guard, a_app_tag, e_app_tag;
 
 	uint64_t jiffies_at_alloc;
 	uint64_t jiffies_at_free;
@@ -1152,4 +1188,9 @@  extern void qlt_modify_vp_config(struct scsi_qla_host *,
 extern void qlt_logo_completion_handler(fc_port_t *, int);
 extern void qlt_do_generation_tick(struct scsi_qla_host *, int *);
 
+void qlt_set_t10dif_tags(struct qla_tgt_cmd *cmd, struct crc_context *ctx,
+    uint16_t *pfw_prot_opts);
+void qlt_send_resp_ctio(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
+	uint8_t scsi_status, uint8_t sense_key, uint8_t asc, uint8_t ascq);
+
 #endif /* __QLA_TARGET_H */
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 3fef40b..8facd3d 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -490,10 +490,43 @@  static u32 tcm_qla2xxx_sess_get_index(struct se_session *se_sess)
 	return 0;
 }
 
+static void tcm_qla2xxx_prot_op(struct qla_tgt_cmd *cmd)
+{
+	struct se_cmd *se_cmd = Q_TO_SE_CMD(cmd);
+
+	switch (se_cmd->prot_op) {
+	case TARGET_PROT_NORMAL:
+		cmd->prot_op = QLA_PROT_NORMAL;
+		break;
+	case TARGET_PROT_DIN_INSERT:
+		cmd->prot_op = QLA_PROT_DIN_INSERT;
+		break;
+	case TARGET_PROT_DOUT_INSERT:
+		cmd->prot_op = QLA_PROT_DOUT_INSERT;
+		break;
+	case TARGET_PROT_DIN_STRIP:
+		cmd->prot_op = QLA_PROT_DIN_STRIP;
+		break;
+	case TARGET_PROT_DOUT_STRIP:
+		cmd->prot_op = QLA_PROT_DOUT_STRIP;
+		break;
+	case TARGET_PROT_DIN_PASS:
+		cmd->prot_op = QLA_PROT_DIN_PASS;
+		break;
+	case TARGET_PROT_DOUT_PASS:
+		cmd->prot_op = QLA_PROT_DOUT_PASS;
+		break;
+	}
+}
+
+static void tcm_qla2xxx_prot_type(struct qla_tgt_cmd *cmd)
+{
+	cmd->prot_type = (Q_TO_SE_CMD(cmd))->prot_type;
+}
+
 static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
 {
-	struct qla_tgt_cmd *cmd = container_of(se_cmd,
-				struct qla_tgt_cmd, se_cmd);
+	struct qla_tgt_cmd *cmd = SE_TO_Q_CMD(se_cmd);
 
 	if (cmd->aborted) {
 		/* Cmd can loop during Q-full.  tcm_qla2xxx_aborted_task
@@ -519,6 +552,8 @@  static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
 	cmd->prot_sg = se_cmd->t_prot_sg;
 	cmd->blk_sz  = se_cmd->se_dev->dev_attrib.block_size;
 	se_cmd->pi_err = 0;
+	tcm_qla2xxx_prot_op(cmd);
+	tcm_qla2xxx_prot_type(cmd);
 	cmd->cdb = se_cmd->t_task_cdb;
 	cmd->lba = se_cmd->t_task_lba;
 
@@ -639,6 +674,80 @@  static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
 				data_dir, flags);
 }
 
+static int
+tcm_qla2xxx_chk_dif_tags(uint32_t tag)
+{
+	return 0;
+}
+
+/* TODO: Return the type of check needed, similar to SCST */
+
+static int
+tcm_qla2xxx_dif_tags(struct qla_tgt_cmd *cmd, uint16_t *pfw_prot_opts)
+{
+	struct se_cmd *se_cmd = Q_TO_SE_CMD(cmd);
+	uint32_t t32=0;
+
+	if (!(se_cmd->prot_checks & TARGET_DIF_CHECK_GUARD))
+		*pfw_prot_opts |= PO_DISABLE_GUARD_CHECK;
+
+	if (!(se_cmd->prot_checks & TARGET_DIF_CHECK_APPTAG))
+		*pfw_prot_opts |= PO_DIS_APP_TAG_VALD;
+
+        return t32;
+}
+
+static void tcm_qla2xxx_check_dif_err(struct qla_tgt_cmd *cmd)
+{
+	struct se_cmd *se_cmd = Q_TO_SE_CMD(cmd);
+
+	if ((cmd->a_app_tag == 0xffff) &&
+	    ((cmd->prot_type != QLA_TGT_PROT_TYPE3) ||
+	     (cmd->a_ref_tag == 0xffffffff))) {
+		se_cmd->bad_sector = cmd->e_ref_tag;
+		se_cmd->pi_err = 0;
+		return;
+	}
+
+	/* check guard */
+	if (cmd->e_guard != cmd->a_guard) {
+		se_cmd->pi_err = TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED;
+		se_cmd->bad_sector = cmd->lba;
+
+		pr_err("Guard ERR: cdb 0x%x lba 0x%llx: [Actual|Expected] Ref Tag[0x%x|0x%x], App Tag [0x%x|0x%x], Guard [0x%x|0x%x] cmd=%p\n",
+		    cmd->atio.u.isp24.fcp_cmnd.cdb[0], cmd->lba,
+		    cmd->a_ref_tag, cmd->e_ref_tag, cmd->a_app_tag, cmd->e_app_tag,
+		    cmd->a_guard, cmd->e_guard, cmd);
+		goto out;
+	}
+
+	/* check ref tag */
+	if (cmd->e_ref_tag != cmd->a_ref_tag) {
+		se_cmd->pi_err = TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED;
+		se_cmd->bad_sector = cmd->e_ref_tag;
+
+		pr_err("Ref Tag ERR: cdb 0x%x lba 0x%llx: [Actual|Expected] Ref Tag[0x%x|0x%x], App Tag [0x%x|0x%x], Guard [0x%x|0x%x] cmd=%p\n",
+			cmd->atio.u.isp24.fcp_cmnd.cdb[0], cmd->lba,
+			cmd->a_ref_tag, cmd->e_ref_tag, cmd->a_app_tag, cmd->e_app_tag,
+			cmd->a_guard, cmd->e_guard, cmd);
+		goto out;
+	}
+
+	/* check appl tag */
+	if (cmd->e_app_tag != cmd->a_app_tag) {
+		se_cmd->pi_err = TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED;
+		se_cmd->bad_sector = cmd->lba;
+
+		pr_err("App Tag ERR: cdb 0x%x lba 0x%llx: [Actual|Expected] Ref Tag[0x%x|0x%x], App Tag [0x%x|0x%x], Guard [0x%x|0x%x] cmd=%p\n",
+			cmd->atio.u.isp24.fcp_cmnd.cdb[0], cmd->lba,
+			cmd->a_ref_tag, cmd->e_ref_tag, cmd->a_app_tag, cmd->e_app_tag,
+			cmd->a_guard, cmd->e_guard, cmd);
+		goto out;
+	}
+out:
+	return;
+}
+
 static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
 {
 	struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
@@ -663,6 +772,10 @@  static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
 	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
 
 	cmd->vha->tgt_counters.qla_core_ret_ctio++;
+
+	if (cmd->prot_op)
+		tcm_qla2xxx_check_dif_err(cmd);
+
 	if (!cmd->write_data_transferred) {
 		/*
 		 * Check if se_cmd has already been aborted via LUN_RESET, and
@@ -673,6 +786,21 @@  static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
 			return;
 		}
 
+		switch (cmd->dif_err_code) {
+		case DIF_ERR_GRD:
+			se_cmd->pi_err = TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED;
+			break;
+		case DIF_ERR_REF:
+			se_cmd->pi_err = TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED;
+			break;
+		case DIF_ERR_APP:
+			se_cmd->pi_err = TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED;
+			break;
+		case DIF_ERR_NONE:
+		default:
+			break;
+		}
+
 		if (se_cmd->pi_err)
 			transport_generic_request_failure(se_cmd,
 				se_cmd->pi_err);
@@ -697,27 +825,6 @@  static void tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd)
 	queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work);
 }
 
-static void tcm_qla2xxx_handle_dif_work(struct work_struct *work)
-{
-	struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
-
-	/* take an extra kref to prevent cmd free too early.
-	 * need to wait for SCSI status/check condition to
-	 * finish responding generate by transport_generic_request_failure.
-	 */
-	kref_get(&se_cmd->cmd_kref);
-	transport_generic_request_failure(se_cmd, se_cmd->pi_err);
-}
-
-/*
- * Called from qla_target.c:qlt_do_ctio_completion()
- */
-static void tcm_qla2xxx_handle_dif_err(struct qla_tgt_cmd *cmd)
-{
-	INIT_WORK(&cmd->work, tcm_qla2xxx_handle_dif_work);
-	queue_work(tcm_qla2xxx_free_wq, &cmd->work);
-}
-
 /*
  * Called from qla_target.c:qlt_issue_task_mgmt()
  */
@@ -855,6 +962,8 @@  static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
 	cmd->prot_sg = se_cmd->t_prot_sg;
 	cmd->blk_sz  = se_cmd->se_dev->dev_attrib.block_size;
 	se_cmd->pi_err = 0;
+	tcm_qla2xxx_prot_op(cmd);
+	tcm_qla2xxx_prot_type(cmd);
 	cmd->cdb = se_cmd->t_task_cdb;
 	cmd->lba = se_cmd->t_task_lba;
 
@@ -1844,7 +1953,6 @@  static void tcm_qla2xxx_srr_get_cur_state(struct qla_tgt_cmd *cmd,
 static struct qla_tgt_func_tmpl tcm_qla2xxx_template = {
 	.handle_cmd		= tcm_qla2xxx_handle_cmd,
 	.handle_data		= tcm_qla2xxx_handle_data,
-	.handle_dif_err		= tcm_qla2xxx_handle_dif_err,
 	.handle_tmr		= tcm_qla2xxx_handle_tmr,
 	.free_cmd		= tcm_qla2xxx_free_cmd,
 	.free_mcmd		= tcm_qla2xxx_free_mcmd,
@@ -1861,6 +1969,8 @@  static void tcm_qla2xxx_srr_get_cur_state(struct qla_tgt_cmd *cmd,
 	.alloc_cmd		= tcm_qla2xxx_alloc_cmd,
 	.alloc_mgmt_cmd		= tcm_qla2xxx_alloc_mgmt_cmd,
 	.srr_get_cur_state 	= tcm_qla2xxx_srr_get_cur_state,
+	.get_dif_tags		= tcm_qla2xxx_dif_tags,
+	.chk_dif_tags		= tcm_qla2xxx_chk_dif_tags,
 };
 
 static int tcm_qla2xxx_init_lport(struct tcm_qla2xxx_lport *lport)