(target mode)
Similar fixes to both functions:
qlt_xmit_response:
- If the cmd cannot be processed, remember to call ->free_cmd() to
prevent the target-mode midlevel from seeing a cmd lockup.
- Do not try to send the response if the exchange has been terminated.
- Check for chip reset once after lock instead of both before and after
lock.
- Give errors from qlt_pre_xmit_response() a lower priority to
compensate for removing the first check for chip reset.
qlt_rdy_to_xfer:
- Check for chip reset after lock instead of before lock to avoid races.
- Do not try to receive data if the exchange has been terminated.
- Give errors from qlt_pci_map_calc_cnt() a lower priority to compensate
for moving the check for chip reset.
Signed-off-by: Tony Battersby <tonyb@cybernetics.com>
---
drivers/scsi/qla2xxx/qla_target.c | 86 +++++++++++++++++--------------
1 file changed, 48 insertions(+), 38 deletions(-)
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 1160ca4c118f..da010de9ba8a 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -3207,12 +3207,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
uint32_t full_req_cnt = 0;
unsigned long flags = 0;
int res;
-
- if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) ||
- (cmd->sess && cmd->sess->deleted)) {
- cmd->state = QLA_TGT_STATE_PROCESSED;
- return 0;
- }
+ int pre_xmit_res;
ql_dbg_qp(ql_dbg_tgt, qpair, 0xe018,
"is_send_status=%d, cmd->bufflen=%d, cmd->sg_cnt=%d, cmd->dma_data_direction=%d se_cmd[%p] qp %d\n",
@@ -3220,33 +3215,39 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
1 : 0, cmd->bufflen, cmd->sg_cnt, cmd->dma_data_direction,
&cmd->se_cmd, qpair->id);
- res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status,
+ pre_xmit_res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status,
&full_req_cnt);
- if (unlikely(res != 0)) {
- return res;
- }
+ /*
+ * Check pre_xmit_res later because we want to check other errors
+ * first.
+ */
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
+ if (unlikely(cmd->sent_term_exchg ||
+ cmd->sess->deleted ||
+ !qpair->fw_started ||
+ cmd->reset_count != qpair->chip_reset)) {
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xe101,
+ "qla_target(%d): tag %lld: skipping send response for aborted cmd\n",
+ vha->vp_idx, cmd->se_cmd.tag);
+ qlt_unmap_sg(vha, cmd);
+ cmd->state = QLA_TGT_STATE_PROCESSED;
+ vha->hw->tgt.tgt_ops->free_cmd(cmd);
+ spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
+ return 0;
+ }
+
+ /* Check for errors from qlt_pre_xmit_response(). */
+ res = pre_xmit_res;
+ if (unlikely(res))
+ goto out_unmap_unlock;
+
if (xmit_type == QLA_TGT_XMIT_STATUS)
qpair->tgt_counters.core_qla_snd_status++;
else
qpair->tgt_counters.core_qla_que_buf++;
- if (!qpair->fw_started || cmd->reset_count != qpair->chip_reset) {
- /*
- * Either the port is not online or this request was from
- * previous life, just abort the processing.
- */
- cmd->state = QLA_TGT_STATE_PROCESSED;
- ql_dbg_qp(ql_dbg_async, qpair, 0xe101,
- "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n",
- vha->flags.online, qla2x00_reset_active(vha),
- cmd->reset_count, qpair->chip_reset);
- res = 0;
- goto out_unmap_unlock;
- }
-
/* Does F/W have an IOCBs for this request */
res = qlt_check_reserve_free_req(qpair, full_req_cnt);
if (unlikely(res))
@@ -3361,6 +3362,7 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
struct qla_tgt_prm prm;
unsigned long flags = 0;
int res = 0;
+ int pci_map_res;
struct qla_qpair *qpair = cmd->qpair;
memset(&prm, 0, sizeof(prm));
@@ -3369,28 +3371,36 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
prm.sg = NULL;
prm.req_cnt = 1;
- if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) ||
- (cmd->sess && cmd->sess->deleted)) {
- /*
- * Either the port is not online or this request was from
- * previous life, just abort the processing.
- */
+ /* Calculate number of entries and segments required */
+ pci_map_res = qlt_pci_map_calc_cnt(&prm);
+ /*
+ * Check pci_map_res later because we want to check other errors first.
+ */
+
+ spin_lock_irqsave(qpair->qp_lock_ptr, flags);
+
+ if (unlikely(cmd->sent_term_exchg ||
+ cmd->sess->deleted ||
+ !qpair->fw_started ||
+ cmd->reset_count != qpair->chip_reset)) {
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xe102,
+ "qla_target(%d): tag %lld: skipping data-out for aborted cmd\n",
+ vha->vp_idx, cmd->se_cmd.tag);
+ qlt_unmap_sg(vha, cmd);
cmd->aborted = 1;
cmd->write_data_transferred = 0;
cmd->state = QLA_TGT_STATE_DATA_IN;
vha->hw->tgt.tgt_ops->handle_data(cmd);
- ql_dbg_qp(ql_dbg_async, qpair, 0xe102,
- "RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n",
- vha->flags.online, qla2x00_reset_active(vha),
- cmd->reset_count, qpair->chip_reset);
+ spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
return 0;
}
- /* Calculate number of entries and segments required */
- if (qlt_pci_map_calc_cnt(&prm) != 0)
- return -EAGAIN;
+ /* Check for errors from qlt_pci_map_calc_cnt(). */
+ if (unlikely(pci_map_res != 0)) {
+ res = -EAGAIN;
+ goto out_unlock_free_unmap;
+ }
- spin_lock_irqsave(qpair->qp_lock_ptr, flags);
/* Does F/W have an IOCBs for this request */
res = qlt_check_reserve_free_req(qpair, prm.req_cnt);
if (res != 0)
--
2.43.0