scsi: qla2xxx: Limit TMF to 8 per function
authorQuinn Tran <qutran@marvell.com>
Fri, 14 Jul 2023 07:00:57 +0000 (12:30 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sun, 23 Jul 2023 20:27:47 +0000 (16:27 -0400)
Per FW recommendation, 8 TMF's can be outstanding for each
function. Previously, it allowed 8 per target.

Limit TMF to 8 per function.

Cc: stable@vger.kernel.org
Fixes: 6a87679626b5 ("scsi: qla2xxx: Fix task management cmd fail due to unavailable resource")
Signed-off-by: Quinn Tran <qutran@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Link: https://lore.kernel.org/r/20230714070104.40052-4-njavali@marvell.com
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_os.c

index d44c4d37b50b45748db1ff09fa08dfab6bdeaadb..b3b1df34afd3ab29f424964c1117be1efde451eb 100644 (file)
@@ -466,6 +466,7 @@ static inline be_id_t port_id_to_be_id(port_id_t port_id)
 }
 
 struct tmf_arg {
+       struct list_head tmf_elem;
        struct qla_qpair *qpair;
        struct fc_port *fcport;
        struct scsi_qla_host *vha;
@@ -2541,7 +2542,6 @@ enum rscn_addr_format {
 typedef struct fc_port {
        struct list_head list;
        struct scsi_qla_host *vha;
-       struct list_head tmf_pending;
 
        unsigned int conf_compl_supported:1;
        unsigned int deleted:2;
@@ -2562,9 +2562,6 @@ typedef struct fc_port {
        unsigned int do_prli_nvme:1;
 
        uint8_t nvme_flag;
-       uint8_t active_tmf;
-#define MAX_ACTIVE_TMF 8
-
        uint8_t node_name[WWN_SIZE];
        uint8_t port_name[WWN_SIZE];
        port_id_t d_id;
@@ -4657,6 +4654,8 @@ struct qla_hw_data {
                uint32_t        flt_region_aux_img_status_sec;
        };
        uint8_t         active_image;
+       uint8_t active_tmf;
+#define MAX_ACTIVE_TMF 8
 
        /* Needed for BEACON */
        uint16_t        beacon_blink_led;
@@ -4671,6 +4670,8 @@ struct qla_hw_data {
 
        struct qla_msix_entry *msix_entries;
 
+       struct list_head tmf_pending;
+       struct list_head tmf_active;
        struct list_head        vp_list;        /* list of VP */
        unsigned long   vp_idx_map[(MAX_MULTI_ID_FABRIC / 8) /
                        sizeof(unsigned long)];
index eb25fc2451d3cad6b40e8eb4cb07502c2084d4b8..404b32ceeaa2bda1506f0bfea33f352711571471 100644 (file)
@@ -2192,30 +2192,42 @@ done:
        return rval;
 }
 
-static void qla_put_tmf(fc_port_t *fcport)
+static void qla_put_tmf(struct tmf_arg *arg)
 {
-       struct scsi_qla_host *vha = fcport->vha;
+       struct scsi_qla_host *vha = arg->vha;
        struct qla_hw_data *ha = vha->hw;
        unsigned long flags;
 
        spin_lock_irqsave(&ha->tgt.sess_lock, flags);
-       fcport->active_tmf--;
+       ha->active_tmf--;
+       list_del(&arg->tmf_elem);
        spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 }
 
 static
-int qla_get_tmf(fc_port_t *fcport)
+int qla_get_tmf(struct tmf_arg *arg)
 {
-       struct scsi_qla_host *vha = fcport->vha;
+       struct scsi_qla_host *vha = arg->vha;
        struct qla_hw_data *ha = vha->hw;
        unsigned long flags;
+       fc_port_t *fcport = arg->fcport;
        int rc = 0;
-       LIST_HEAD(tmf_elem);
+       struct tmf_arg *t;
 
        spin_lock_irqsave(&ha->tgt.sess_lock, flags);
-       list_add_tail(&tmf_elem, &fcport->tmf_pending);
+       list_for_each_entry(t, &ha->tmf_active, tmf_elem) {
+               if (t->fcport == arg->fcport && t->lun == arg->lun) {
+                       /* reject duplicate TMF */
+                       ql_log(ql_log_warn, vha, 0x802c,
+                              "found duplicate TMF.  Nexus=%ld:%06x:%llu.\n",
+                              vha->host_no, fcport->d_id.b24, arg->lun);
+                       spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+                       return -EINVAL;
+               }
+       }
 
-       while (fcport->active_tmf >= MAX_ACTIVE_TMF) {
+       list_add_tail(&arg->tmf_elem, &ha->tmf_pending);
+       while (ha->active_tmf >= MAX_ACTIVE_TMF) {
                spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 
                msleep(1);
@@ -2227,15 +2239,17 @@ int qla_get_tmf(fc_port_t *fcport)
                        rc = EIO;
                        break;
                }
-               if (fcport->active_tmf < MAX_ACTIVE_TMF &&
-                   list_is_first(&tmf_elem, &fcport->tmf_pending))
+               if (ha->active_tmf < MAX_ACTIVE_TMF &&
+                   list_is_first(&arg->tmf_elem, &ha->tmf_pending))
                        break;
        }
 
-       list_del(&tmf_elem);
+       list_del(&arg->tmf_elem);
 
-       if (!rc)
-               fcport->active_tmf++;
+       if (!rc) {
+               ha->active_tmf++;
+               list_add_tail(&arg->tmf_elem, &ha->tmf_active);
+       }
 
        spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 
@@ -2257,15 +2271,18 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
        a.vha = fcport->vha;
        a.fcport = fcport;
        a.lun = lun;
+       a.flags = flags;
+       INIT_LIST_HEAD(&a.tmf_elem);
+
        if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) {
                a.modifier = MK_SYNC_ID_LUN;
-
-               if (qla_get_tmf(fcport))
-                       return QLA_FUNCTION_FAILED;
        } else {
                a.modifier = MK_SYNC_ID;
        }
 
+       if (qla_get_tmf(&a))
+               return QLA_FUNCTION_FAILED;
+
        if (vha->hw->mqenable) {
                for (i = 0; i < vha->hw->num_qpairs; i++) {
                        qpair = vha->hw->queue_pair_map[i];
@@ -2291,13 +2308,10 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
                goto bailout;
 
        a.qpair = vha->hw->base_qpair;
-       a.flags = flags;
        rval = __qla2x00_async_tm_cmd(&a);
 
 bailout:
-       if (a.modifier == MK_SYNC_ID_LUN)
-               qla_put_tmf(fcport);
-
+       qla_put_tmf(&a);
        return rval;
 }
 
@@ -5526,7 +5540,6 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
        INIT_WORK(&fcport->reg_work, qla_register_fcport_fn);
        INIT_LIST_HEAD(&fcport->gnl_entry);
        INIT_LIST_HEAD(&fcport->list);
-       INIT_LIST_HEAD(&fcport->tmf_pending);
 
        INIT_LIST_HEAD(&fcport->sess_cmd_list);
        spin_lock_init(&fcport->sess_cmd_lock);
index 877e4f446709d5fb6792b670c290fa9519220f13..47bbc8b321f8bdadce4d9daa3d0d718e4bb5ce27 100644 (file)
@@ -3009,6 +3009,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        atomic_set(&ha->num_pend_mbx_stage3, 0);
        atomic_set(&ha->zio_threshold, DEFAULT_ZIO_THRESHOLD);
        ha->last_zio_threshold = DEFAULT_ZIO_THRESHOLD;
+       INIT_LIST_HEAD(&ha->tmf_pending);
+       INIT_LIST_HEAD(&ha->tmf_active);
 
        /* Assign ISP specific operations. */
        if (IS_QLA2100(ha)) {