]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
scsi: qla2xxx: target: Improve checks in qlt_xmit_response() / qlt_rdy_to_xfer()
authorTony Battersby <tonyb@cybernetics.com>
Mon, 10 Nov 2025 15:58:12 +0000 (10:58 -0500)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 12 Nov 2025 23:17:28 +0000 (18:17 -0500)
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>
Link: https://patch.msgid.link/cd6ccd31-33fa-4454-be36-507bf578a546@cybernetics.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_target.c

index c6dc5e9efb695d3bcbe836aa5d72dae3245db5f1..849ab256807be87100f34e6e94a00f281b86b040 100644 (file)
@@ -3206,12 +3206,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",
@@ -3219,33 +3214,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))
@@ -3360,6 +3361,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));
@@ -3368,28 +3370,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)