@@ -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 **);
@@ -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];
@@ -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;
}
@@ -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 *,
@@ -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);
@@ -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;
+}
@@ -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) ||
@@ -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;
}
@@ -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;
@@ -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 */
@@ -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)