scsi: qla2xxx: Fix task management cmd fail due to unavailable resource
authorQuinn Tran <qutran@marvell.com>
Fri, 28 Apr 2023 07:53:35 +0000 (00:53 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Mon, 8 May 2023 11:16:39 +0000 (07:16 -0400)
Task management command failed with status 2Ch which is
a result of too many task management commands sent
to the same target. Hence limit task management commands
to 8 per target.

Reported-by: kernel test robot <lkp@intel.com>
Link: https://lore.kernel.org/oe-kbuild-all/202304271952.NKNmoFzv-lkp@intel.com/
Cc: stable@vger.kernel.org
Signed-off-by: Quinn Tran <qutran@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Link: https://lore.kernel.org/r/20230428075339.32551-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

index 0228720..e345ccb 100644 (file)
@@ -2542,6 +2542,7 @@ 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,6 +2563,8 @@ 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];
index bc4600b..84841ed 100644 (file)
@@ -2149,6 +2149,54 @@ done:
        return rval;
 }
 
+static void qla_put_tmf(fc_port_t *fcport)
+{
+       struct scsi_qla_host *vha = fcport->vha;
+       struct qla_hw_data *ha = vha->hw;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+       fcport->active_tmf--;
+       spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+}
+
+static
+int qla_get_tmf(fc_port_t *fcport)
+{
+       struct scsi_qla_host *vha = fcport->vha;
+       struct qla_hw_data *ha = vha->hw;
+       unsigned long flags;
+       int rc = 0;
+       LIST_HEAD(tmf_elem);
+
+       spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+       list_add_tail(&tmf_elem, &fcport->tmf_pending);
+
+       while (fcport->active_tmf >= MAX_ACTIVE_TMF) {
+               spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
+               msleep(1);
+
+               spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+               if (fcport->deleted) {
+                       rc = EIO;
+                       break;
+               }
+               if (fcport->active_tmf < MAX_ACTIVE_TMF &&
+                   list_is_first(&tmf_elem, &fcport->tmf_pending))
+                       break;
+       }
+
+       list_del(&tmf_elem);
+
+       if (!rc)
+               fcport->active_tmf++;
+
+       spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
+       return rc;
+}
+
 int
 qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
                     uint32_t tag)
@@ -2156,18 +2204,19 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
        struct scsi_qla_host *vha = fcport->vha;
        struct qla_qpair *qpair;
        struct tmf_arg a;
-       struct completion comp;
        int i, rval;
 
-       init_completion(&comp);
        a.vha = fcport->vha;
        a.fcport = fcport;
        a.lun = lun;
-
-       if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA))
+       if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) {
                a.modifier = MK_SYNC_ID_LUN;
-       else
+
+               if (qla_get_tmf(fcport))
+                       return QLA_FUNCTION_FAILED;
+       } else {
                a.modifier = MK_SYNC_ID;
+       }
 
        if (vha->hw->mqenable) {
                for (i = 0; i < vha->hw->num_qpairs; i++) {
@@ -2186,6 +2235,9 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
        a.flags = flags;
        rval = __qla2x00_async_tm_cmd(&a);
 
+       if (a.modifier == MK_SYNC_ID_LUN)
+               qla_put_tmf(fcport);
+
        return rval;
 }
 
@@ -5400,6 +5452,7 @@ 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);