scsi: qla2xxx: Fix exchange oversubscription for management commands
authorQuinn Tran <qutran@marvell.com>
Mon, 19 Dec 2022 11:07:42 +0000 (03:07 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 12 Jan 2023 02:28:37 +0000 (21:28 -0500)
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>
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 777808af56347311363692124d3f0dbe802e09da..1925cc6897b6833c2cc4e263dcd99b58e034cb0e 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 42d3d2de3d31fa8b68bc74f4b951b8b06754e2a8..759bea69de120eb7d71eb4b3d9f64ef3779148d0 100644 (file)
@@ -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;