scsi: qla2xxx: Fix exchange oversubscription for management commands
authorQuinn Tran <qutran@marvell.com>
Mon, 19 Dec 2022 11:07:42 +0000 (03:07 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 10 Mar 2023 08:39:22 +0000 (09:39 +0100)
[ Upstream commit 5f63a163ed2f12c34dd4ae9b2757962ec7bb86e5 ]

Add resource checking for management (non-I/O) commands.

Fixes: 89c72f4245a8 ("scsi: qla2xxx: Add IOCB resource tracking")
Signed-off-by: Quinn Tran <qutran@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/scsi/qla2xxx/qla_dfs.c
drivers/scsi/qla2xxx/qla_inline.h
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c

index 85bd0e468d43edaff3610ad40f0fc6bea4bbc924..8f6f56c9584ce44e2af3254016327e367c0249b9 100644 (file)
@@ -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;
index 2d5a275d8b00078a51597227554e7dd8c4320e0f..b0ee307b5d4b9a3628bade5998fbffb414a554bb 100644 (file)
@@ -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;
index 399ec8da2d73c3354cde61e96036f490efda6142..4f48f098ea5a69194453083c4ef13440d8283b56 100644 (file)
@@ -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;
 }
index c545f39362ffce2d0eda65a25a24b1e067ff2c98..5589251c87f0ad00b462bb42df3bae4f1de153a8 100644 (file)
@@ -3099,6 +3099,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;