diff mbox series

[03/10] qla2xxx: Limit TMF to 8 per function

Message ID 20230712090535.34894-4-njavali@marvell.com (mailing list archive)
State Superseded
Headers show
Series qla2xxx driver bug fixes | expand

Commit Message

Nilesh Javali July 12, 2023, 9:05 a.m. UTC
From: Quinn Tran <qutran@marvell.com>

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>
---
 drivers/scsi/qla2xxx/qla_def.h  |  9 +++---
 drivers/scsi/qla2xxx/qla_init.c | 55 ++++++++++++++++++++-------------
 drivers/scsi/qla2xxx/qla_os.c   |  2 ++
 3 files changed, 41 insertions(+), 25 deletions(-)

Comments

Himanshu Madhani July 13, 2023, 6:54 p.m. UTC | #1
> On Jul 12, 2023, at 2:05 AM, Nilesh Javali <njavali@marvell.com> wrote:
> 
> From: Quinn Tran <qutran@marvell.com>
> 
> 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>
> ---
> drivers/scsi/qla2xxx/qla_def.h  |  9 +++---
> drivers/scsi/qla2xxx/qla_init.c | 55 ++++++++++++++++++++-------------
> drivers/scsi/qla2xxx/qla_os.c   |  2 ++
> 3 files changed, 41 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
> index 95a12b4e0484..03d94e024bdd 100644
> --- a/drivers/scsi/qla2xxx/qla_def.h
> +++ b/drivers/scsi/qla2xxx/qla_def.h
> @@ -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;
> @@ -4656,6 +4653,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;
> @@ -4670,6 +4669,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)];
> diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
> index 60dd0e415351..5ec6f01ca635 100644
> --- a/drivers/scsi/qla2xxx/qla_init.c
> +++ b/drivers/scsi/qla2xxx/qla_init.c
> @@ -2192,30 +2192,42 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
> 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);
> diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
> index 877e4f446709..47bbc8b321f8 100644
> --- a/drivers/scsi/qla2xxx/qla_os.c
> +++ b/drivers/scsi/qla2xxx/qla_os.c
> @@ -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)) {
> -- 
> 2.23.1
> 

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
diff mbox series

Patch

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 95a12b4e0484..03d94e024bdd 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -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;
@@ -4656,6 +4653,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;
@@ -4670,6 +4669,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)];
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 60dd0e415351..5ec6f01ca635 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -2192,30 +2192,42 @@  __qla2x00_async_tm_cmd(struct tmf_arg *arg)
 	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);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 877e4f446709..47bbc8b321f8 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -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)) {