From 5f63a163ed2f12c34dd4ae9b2757962ec7bb86e5 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Mon, 19 Dec 2022 03:07:42 -0800 Subject: [PATCH] scsi: qla2xxx: Fix exchange oversubscription for management commands Add resource checking for management (non-I/O) commands. Fixes: 89c72f4245a8 ("scsi: qla2xxx: Add IOCB resource tracking") Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_dfs.c | 10 ++++- drivers/scsi/qla2xxx/qla_inline.h | 5 ++- drivers/scsi/qla2xxx/qla_iocb.c | 67 +++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_isr.c | 1 + 4 files changed, 80 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 777808af563473..1925cc6897b683 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -235,7 +235,7 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused) uint16_t mb[MAX_IOCB_MB_REG]; int rc; struct qla_hw_data *ha = vha->hw; - u16 iocbs_used, i; + u16 iocbs_used, i, exch_used; rc = qla24xx_res_count_wait(vha, mb, SIZEOF_IOCB_MB_REG); if (rc != QLA_SUCCESS) { @@ -263,13 +263,19 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused) if (ql2xenforce_iocb_limit) { /* lock is not require. It's an estimate. */ iocbs_used = ha->base_qpair->fwres.iocbs_used; + exch_used = ha->base_qpair->fwres.exch_used; for (i = 0; i < ha->max_qpairs; i++) { - if (ha->queue_pair_map[i]) + if (ha->queue_pair_map[i]) { iocbs_used += ha->queue_pair_map[i]->fwres.iocbs_used; + exch_used += ha->queue_pair_map[i]->fwres.exch_used; + } } seq_printf(s, "Driver: estimate iocb used [%d] high water limit [%d]\n", iocbs_used, ha->base_qpair->fwres.iocbs_limit); + + seq_printf(s, "estimate exchange used[%d] high water limit [%d] n", + exch_used, ha->base_qpair->fwres.exch_limit); } return 0; diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 2d5a275d8b0007..b0ee307b5d4b9a 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -380,7 +380,7 @@ qla2xxx_get_fc4_priority(struct scsi_qla_host *vha) enum { RESOURCE_NONE, - RESOURCE_IOCB = BIT_0, + RESOURCE_IOCB = BIT_0, RESOURCE_EXCH = BIT_1, /* exchange */ RESOURCE_FORCE = BIT_2, }; @@ -396,6 +396,8 @@ qla_get_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores) iores->res_type = RESOURCE_NONE; return 0; } + if (iores->res_type & RESOURCE_FORCE) + goto force; if ((iores->iocb_cnt + qp->fwres.iocbs_used) >= qp->fwres.iocbs_qp_limit) { /* no need to acquire qpair lock. It's just rough calculation */ @@ -423,6 +425,7 @@ qla_get_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores) return -ENOSPC; } } +force: qp->fwres.iocbs_used += iores->iocb_cnt; qp->fwres.exch_used += iores->exch_cnt; return 0; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 399ec8da2d73c3..4f48f098ea5a69 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -3817,6 +3817,65 @@ qla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio) logio->vp_index = sp->fcport->vha->vp_idx; } +int qla_get_iocbs_resource(struct srb *sp) +{ + bool get_exch; + bool push_it_through = false; + + if (!ql2xenforce_iocb_limit) { + sp->iores.res_type = RESOURCE_NONE; + return 0; + } + sp->iores.res_type = RESOURCE_NONE; + + switch (sp->type) { + case SRB_TM_CMD: + case SRB_PRLI_CMD: + case SRB_ADISC_CMD: + push_it_through = true; + fallthrough; + case SRB_LOGIN_CMD: + case SRB_ELS_CMD_RPT: + case SRB_ELS_CMD_HST: + case SRB_ELS_CMD_HST_NOLOGIN: + case SRB_CT_CMD: + case SRB_NVME_LS: + case SRB_ELS_DCMD: + get_exch = true; + break; + + case SRB_FXIOCB_DCMD: + case SRB_FXIOCB_BCMD: + sp->iores.res_type = RESOURCE_NONE; + return 0; + + case SRB_SA_UPDATE: + case SRB_SA_REPLACE: + case SRB_MB_IOCB: + case SRB_ABT_CMD: + case SRB_NACK_PLOGI: + case SRB_NACK_PRLI: + case SRB_NACK_LOGO: + case SRB_LOGOUT_CMD: + case SRB_CTRL_VP: + push_it_through = true; + fallthrough; + default: + get_exch = false; + } + + sp->iores.res_type |= RESOURCE_IOCB; + sp->iores.iocb_cnt = 1; + if (get_exch) { + sp->iores.res_type |= RESOURCE_EXCH; + sp->iores.exch_cnt = 1; + } + if (push_it_through) + sp->iores.res_type |= RESOURCE_FORCE; + + return qla_get_fw_resources(sp->qpair, &sp->iores); +} + int qla2x00_start_sp(srb_t *sp) { @@ -3831,6 +3890,12 @@ qla2x00_start_sp(srb_t *sp) return -EIO; spin_lock_irqsave(qp->qp_lock_ptr, flags); + rval = qla_get_iocbs_resource(sp); + if (rval) { + spin_unlock_irqrestore(qp->qp_lock_ptr, flags); + return -EAGAIN; + } + pkt = __qla2x00_alloc_iocbs(sp->qpair, sp); if (!pkt) { rval = EAGAIN; @@ -3931,6 +3996,8 @@ qla2x00_start_sp(srb_t *sp) wmb(); qla2x00_start_iocbs(vha, qp->req); done: + if (rval) + qla_put_fw_resources(sp->qpair, &sp->iores); spin_unlock_irqrestore(qp->qp_lock_ptr, flags); return rval; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 42d3d2de3d31fa..759bea69de120e 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3112,6 +3112,7 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt, } bsg_reply->reply_payload_rcv_len = 0; + qla_put_fw_resources(sp->qpair, &sp->iores); done: /* Return the vendor specific reply to API */ bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval;