Re: [PATCH v2 11/13] qla2xxx: Add IOCB resource tracking

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> On Sep 2, 2020, at 2:25 AM, Nilesh Javali <njavali@xxxxxxxxxxx> wrote:
> 
> From: Quinn Tran <qutran@xxxxxxxxxxx>
> 
> This patch tracks number of IOCB resources used in the IO
> fast path. If the number of used IOCBs reach a high water
> limit, driver would return the IO as busy and let upper layer
> retry. This prevents over subscription of IOCB resources where
> any future error recovery command is unable to cut through.
> Enable IOCB throttling by default.
> 
> Signed-off-by: Quinn Tran <qutran@xxxxxxxxxxx>
> Signed-off-by: Arun Easi <aeasi@xxxxxxxxxxx>
> Signed-off-by: Nilesh Javali <njavali@xxxxxxxxxxx>
> ---
> drivers/scsi/qla2xxx/qla_def.h    | 17 ++++++++++
> drivers/scsi/qla2xxx/qla_dfs.c    | 14 ++++++++
> drivers/scsi/qla2xxx/qla_gbl.h    |  3 ++
> drivers/scsi/qla2xxx/qla_init.c   | 26 +++++++++++++++
> drivers/scsi/qla2xxx/qla_inline.h | 55 +++++++++++++++++++++++++++++++
> drivers/scsi/qla2xxx/qla_iocb.c   | 28 ++++++++++++++++
> drivers/scsi/qla2xxx/qla_isr.c    |  2 ++
> drivers/scsi/qla2xxx/qla_os.c     |  6 ++++
> 8 files changed, 151 insertions(+)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
> index 3ca8665638c4..863b9c7766e1 100644
> --- a/drivers/scsi/qla2xxx/qla_def.h
> +++ b/drivers/scsi/qla2xxx/qla_def.h
> @@ -624,6 +624,12 @@ enum {
> 	TYPE_TGT_TMCMD,		/* task management */
> };
> 
> +struct iocb_resource {
> +	u8 res_type;
> +	u8 pad;
> +	u16 iocb_cnt;
> +};
> +
> typedef struct srb {
> 	/*
> 	 * Do not move cmd_type field, it needs to
> @@ -631,6 +637,7 @@ typedef struct srb {
> 	 */
> 	uint8_t cmd_type;
> 	uint8_t pad[3];
> +	struct iocb_resource iores;
> 	struct kref cmd_kref;	/* need to migrate ref_count over to this */
> 	void *priv;
> 	wait_queue_head_t nvme_ls_waitq;
> @@ -3577,6 +3584,15 @@ struct req_que {
> 	uint8_t req_pkt[REQUEST_ENTRY_SIZE];
> };
> 
> +struct qla_fw_resources {
> +	u16 iocbs_total;
> +	u16 iocbs_limit;
> +	u16 iocbs_qp_limit;
> +	u16 iocbs_used;
> +};
> +
> +#define QLA_IOCB_PCT_LIMIT 95
> +
> /*Queue pair data structure */
> struct qla_qpair {
> 	spinlock_t qp_lock;
> @@ -3629,6 +3645,7 @@ struct qla_qpair {
> 	uint64_t retry_term_jiff;
> 	struct qla_tgt_counters tgt_counters;
> 	uint16_t cpuid;
> +	struct qla_fw_resources fwres ____cacheline_aligned;
> };
> 
> /* Place holder for FW buffer parameters */
> diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
> index 118f2b223531..6f5f18fc974a 100644
> --- a/drivers/scsi/qla2xxx/qla_dfs.c
> +++ b/drivers/scsi/qla2xxx/qla_dfs.c
> @@ -261,6 +261,8 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
> 	struct scsi_qla_host *vha = s->private;
> 	uint16_t mb[MAX_IOCB_MB_REG];
> 	int rc;
> +	struct qla_hw_data *ha = vha->hw;
> +	u16 iocbs_used, i;
> 
> 	rc = qla24xx_res_count_wait(vha, mb, SIZEOF_IOCB_MB_REG);
> 	if (rc != QLA_SUCCESS) {
> @@ -285,6 +287,18 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
> 		    mb[23]);
> 	}
> 
> +	if (ql2xenforce_iocb_limit) {
> +		/* lock is not require. It's an estimate. */
> +		iocbs_used = ha->base_qpair->fwres.iocbs_used;
> +		for (i = 0; i < ha->max_qpairs; i++) {
> +			if (ha->queue_pair_map[i])
> +				iocbs_used += ha->queue_pair_map[i]->fwres.iocbs_used;
> +		}
> +
> +		seq_printf(s, "Driver: estimate iocb used [%d] high water limit [%d]\n",
> +			   iocbs_used, ha->base_qpair->fwres.iocbs_limit);
> +	}
> +
> 	return 0;
> }
> 
> diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
> index 3360857c4405..9c4d077edf9e 100644
> --- a/drivers/scsi/qla2xxx/qla_gbl.h
> +++ b/drivers/scsi/qla2xxx/qla_gbl.h
> @@ -129,6 +129,8 @@ int qla2x00_reserve_mgmt_server_loop_id(scsi_qla_host_t *);
> void qla_rscn_replay(fc_port_t *fcport);
> void qla24xx_free_purex_item(struct purex_item *item);
> extern bool qla24xx_risc_firmware_invalid(uint32_t *);
> +void qla_init_iocb_limit(scsi_qla_host_t *);
> +
> 
> /*
>  * Global Data in qla_os.c source file.
> @@ -175,6 +177,7 @@ extern int qla2xuseresexchforels;
> extern int ql2xexlogins;
> extern int ql2xdifbundlinginternalbuffers;
> extern int ql2xfulldump_on_mpifail;
> +extern int ql2xenforce_iocb_limit;
> 
> extern int qla2x00_loop_reset(scsi_qla_host_t *);
> extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
> diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
> index 99f322fb74ab..a1603bad3ee6 100644
> --- a/drivers/scsi/qla2xxx/qla_init.c
> +++ b/drivers/scsi/qla2xxx/qla_init.c
> @@ -3622,6 +3622,31 @@ qla24xx_detect_sfp(scsi_qla_host_t *vha)
> 	return ha->flags.lr_detected;
> }
> 
> +void qla_init_iocb_limit(scsi_qla_host_t *vha)
> +{
> +	u16 i, num_qps;
> +	u32 limit;
> +	struct qla_hw_data *ha = vha->hw;
> +
> +	num_qps = ha->num_qpairs + 1;
> +	limit = (ha->orig_fw_iocb_count * QLA_IOCB_PCT_LIMIT) / 100;
> +
> +	ha->base_qpair->fwres.iocbs_total = ha->orig_fw_iocb_count;
> +	ha->base_qpair->fwres.iocbs_limit = limit;
> +	ha->base_qpair->fwres.iocbs_qp_limit = limit / num_qps;
> +	ha->base_qpair->fwres.iocbs_used = 0;
> +	for (i = 0; i < ha->max_qpairs; i++) {
> +		if (ha->queue_pair_map[i])  {
> +			ha->queue_pair_map[i]->fwres.iocbs_total =
> +				ha->orig_fw_iocb_count;
> +			ha->queue_pair_map[i]->fwres.iocbs_limit = limit;
> +			ha->queue_pair_map[i]->fwres.iocbs_qp_limit =
> +				limit / num_qps;
> +			ha->queue_pair_map[i]->fwres.iocbs_used = 0;
> +		}
> +	}
> +}
> +
> /**
>  * qla2x00_setup_chip() - Load and start RISC firmware.
>  * @vha: HA context
> @@ -3722,6 +3747,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
> 						    MIN_MULTI_ID_FABRIC - 1;
> 				}
> 				qla2x00_get_resource_cnts(vha);
> +				qla_init_iocb_limit(vha);
> 
> 				/*
> 				 * Allocate the array of outstanding commands
> diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
> index 5501b4c581ec..9e9a5d3fb802 100644
> --- a/drivers/scsi/qla2xxx/qla_inline.h
> +++ b/drivers/scsi/qla2xxx/qla_inline.h
> @@ -373,3 +373,58 @@ qla2xxx_get_fc4_priority(struct scsi_qla_host *vha)
> 
> 	return (data >> 6) & BIT_0 ? FC4_PRIORITY_FCP : FC4_PRIORITY_NVME;
> }
> +
> +enum {
> +	RESOURCE_NONE,
> +	RESOURCE_INI,
> +};
> +
> +static inline int
> +qla_get_iocbs(struct qla_qpair *qp, struct iocb_resource *iores)
> +{
> +	u16 iocbs_used, i;
> +	struct qla_hw_data *ha = qp->vha->hw;
> +
> +	if (!ql2xenforce_iocb_limit) {
> +		iores->res_type = RESOURCE_NONE;
> +		return 0;
> +	}
> +
> +	if ((iores->iocb_cnt + qp->fwres.iocbs_used) < qp->fwres.iocbs_qp_limit) {
> +		qp->fwres.iocbs_used += iores->iocb_cnt;
> +		return 0;
> +	} else {
> +		/* no need to acquire qpair lock. It's just rough calculation */
> +		iocbs_used = ha->base_qpair->fwres.iocbs_used;
> +		for (i = 0; i < ha->max_qpairs; i++) {
> +			if (ha->queue_pair_map[i])
> +				iocbs_used += ha->queue_pair_map[i]->fwres.iocbs_used;
> +		}
> +
> +		if ((iores->iocb_cnt + iocbs_used) < qp->fwres.iocbs_limit) {
> +			qp->fwres.iocbs_used += iores->iocb_cnt;
> +			return 0;
> +		} else {
> +			iores->res_type = RESOURCE_NONE;
> +			return -ENOSPC;
> +		}
> +	}
> +}
> +
> +static inline void
> +qla_put_iocbs(struct qla_qpair *qp, struct iocb_resource *iores)
> +{
> +	switch (iores->res_type) {
> +	case RESOURCE_NONE:
> +		break;
> +	default:
> +		if (qp->fwres.iocbs_used >= iores->iocb_cnt) {
> +			qp->fwres.iocbs_used -= iores->iocb_cnt;
> +		} else {
> +			// should not happen
> +			qp->fwres.iocbs_used = 0;
> +		}
> +		break;
> +	}
> +	iores->res_type = RESOURCE_NONE;
> +}
> diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
> index d69e16e844aa..b60a332e5846 100644
> --- a/drivers/scsi/qla2xxx/qla_iocb.c
> +++ b/drivers/scsi/qla2xxx/qla_iocb.c
> @@ -1637,6 +1637,12 @@ qla24xx_start_scsi(srb_t *sp)
> 
> 	tot_dsds = nseg;
> 	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
> +
> +	sp->iores.res_type = RESOURCE_INI;
> +	sp->iores.iocb_cnt = req_cnt;
> +	if (qla_get_iocbs(sp->qpair, &sp->iores))
> +		goto queuing_error;
> +
> 	if (req->cnt < (req_cnt + 2)) {
> 		cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr :
> 		    rd_reg_dword_relaxed(req->req_q_out);
> @@ -1709,6 +1715,7 @@ qla24xx_start_scsi(srb_t *sp)
> 	if (tot_dsds)
> 		scsi_dma_unmap(cmd);
> 
> +	qla_put_iocbs(sp->qpair, &sp->iores);
> 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
> 
> 	return QLA_FUNCTION_FAILED;
> @@ -1822,6 +1829,12 @@ qla24xx_dif_start_scsi(srb_t *sp)
> 	/* Total Data and protection sg segment(s) */
> 	tot_prot_dsds = nseg;
> 	tot_dsds += nseg;
> +
> +	sp->iores.res_type = RESOURCE_INI;
> +	sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
> +	if (qla_get_iocbs(sp->qpair, &sp->iores))
> +		goto queuing_error;
> +
> 	if (req->cnt < (req_cnt + 2)) {
> 		cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr :
> 		    rd_reg_dword_relaxed(req->req_q_out);
> @@ -1896,6 +1909,7 @@ qla24xx_dif_start_scsi(srb_t *sp)
> 	}
> 	/* Cleanup will be performed by the caller (queuecommand) */
> 
> +	qla_put_iocbs(sp->qpair, &sp->iores);
> 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
> 	return QLA_FUNCTION_FAILED;
> }
> @@ -1957,6 +1971,12 @@ qla2xxx_start_scsi_mq(srb_t *sp)
> 
> 	tot_dsds = nseg;
> 	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
> +
> +	sp->iores.res_type = RESOURCE_INI;
> +	sp->iores.iocb_cnt = req_cnt;
> +	if (qla_get_iocbs(sp->qpair, &sp->iores))
> +		goto queuing_error;
> +
> 	if (req->cnt < (req_cnt + 2)) {
> 		cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr :
> 		    rd_reg_dword_relaxed(req->req_q_out);
> @@ -2029,6 +2049,7 @@ qla2xxx_start_scsi_mq(srb_t *sp)
> 	if (tot_dsds)
> 		scsi_dma_unmap(cmd);
> 
> +	qla_put_iocbs(sp->qpair, &sp->iores);
> 	spin_unlock_irqrestore(&qpair->qp_lock, flags);
> 
> 	return QLA_FUNCTION_FAILED;
> @@ -2157,6 +2178,12 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp)
> 	/* Total Data and protection sg segment(s) */
> 	tot_prot_dsds = nseg;
> 	tot_dsds += nseg;
> +
> +	sp->iores.res_type = RESOURCE_INI;
> +	sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
> +	if (qla_get_iocbs(sp->qpair, &sp->iores))
> +		goto queuing_error;
> +
> 	if (req->cnt < (req_cnt + 2)) {
> 		cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr :
> 		    rd_reg_dword_relaxed(req->req_q_out);
> @@ -2234,6 +2261,7 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp)
> 	}
> 	/* Cleanup will be performed by the caller (queuecommand) */
> 
> +	qla_put_iocbs(sp->qpair, &sp->iores);
> 	spin_unlock_irqrestore(&qpair->qp_lock, flags);
> 	return QLA_FUNCTION_FAILED;
> }
> diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
> index a63f2000fadf..bb3beaa77d39 100644
> --- a/drivers/scsi/qla2xxx/qla_isr.c
> +++ b/drivers/scsi/qla2xxx/qla_isr.c
> @@ -2901,6 +2901,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
> 		}
> 		return;
> 	}
> +	qla_put_iocbs(sp->qpair, &sp->iores);
> 
> 	if (sp->cmd_type != TYPE_SRB) {
> 		req->outstanding_cmds[handle] = NULL;
> @@ -3313,6 +3314,7 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
> 	default:
> 		sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
> 		if (sp) {
> +			qla_put_iocbs(sp->qpair, &sp->iores);
> 			sp->done(sp, res);
> 			return 0;
> 		}
> diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
> index c53cc31cd068..a4d737b92ec1 100644
> --- a/drivers/scsi/qla2xxx/qla_os.c
> +++ b/drivers/scsi/qla2xxx/qla_os.c
> @@ -40,6 +40,11 @@ module_param(ql2xfulldump_on_mpifail, int, S_IRUGO | S_IWUSR);
> MODULE_PARM_DESC(ql2xfulldump_on_mpifail,
> 		 "Set this to take full dump on MPI hang.");
> 
> +int ql2xenforce_iocb_limit = 1;
> +module_param(ql2xenforce_iocb_limit, int, S_IRUGO | S_IWUSR);
> +MODULE_PARM_DESC(ql2xenforce_iocb_limit,
> +		 "Enforce IOCB throttling, to avoid FW congestion. (default: 0)");
> +
> /*
>  * CT6 CTX allocation cache
>  */
> @@ -3316,6 +3321,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
> 		for (i = 0; i < ha->max_qpairs; i++)
> 			qla2xxx_create_qpair(base_vha, 5, 0, startit);
> 	}
> +	qla_init_iocb_limit(base_vha);
> 
> 	if (ha->flags.running_gold_fw)
> 		goto skip_dpc;
> -- 
> 2.19.0.rc0
> 

Looks Good.

Reviewed-by: Himanshu Madhani <himanshu.madhani@xxxxxxxxxx>

--
Himanshu Madhani	 Oracle Linux Engineering





[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux