summaryrefslogtreecommitdiff
path: root/drivers/scsi/qla2xxx/qla_inline.h
diff options
context:
space:
mode:
authorQuinn Tran <qutran@marvell.com>2022-12-19 03:07:41 -0800
committerMartin K. Petersen <martin.petersen@oracle.com>2023-01-11 21:28:37 -0500
commit41e5afe51f75f2858f5563145348f6c26d307b8f (patch)
tree7d7ada02cd9e0ea31e985ec9d1e605bdc3d2311a /drivers/scsi/qla2xxx/qla_inline.h
parentc75e6aef5039830cce5d4cf764dd204522f89e6b (diff)
downloadlwn-41e5afe51f75f2858f5563145348f6c26d307b8f.tar.gz
lwn-41e5afe51f75f2858f5563145348f6c26d307b8f.zip
scsi: qla2xxx: Fix exchange oversubscription
In large environment, it is possible to experience command timeout and escalation of path recovery. Currently the driver does not track the number of exchanges/commands sent to FW. If there is a delay for commands at the head of the queue, then this will create back pressure for commands at the back of the queue. Check for exchange availability before command submission. Fixes: 89c72f4245a8 ("scsi: qla2xxx: Add IOCB resource tracking") Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_inline.h')
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h52
1 files changed, 35 insertions, 17 deletions
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 5185dc5daf80..2d5a275d8b00 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -380,13 +380,16 @@ qla2xxx_get_fc4_priority(struct scsi_qla_host *vha)
enum {
RESOURCE_NONE,
- RESOURCE_INI,
+ RESOURCE_IOCB = BIT_0,
+ RESOURCE_EXCH = BIT_1, /* exchange */
+ RESOURCE_FORCE = BIT_2,
};
static inline int
-qla_get_iocbs(struct qla_qpair *qp, struct iocb_resource *iores)
+qla_get_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores)
{
u16 iocbs_used, i;
+ u16 exch_used;
struct qla_hw_data *ha = qp->vha->hw;
if (!ql2xenforce_iocb_limit) {
@@ -394,10 +397,7 @@ qla_get_iocbs(struct qla_qpair *qp, struct iocb_resource *iores)
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 {
+ if ((iores->iocb_cnt + qp->fwres.iocbs_used) >= qp->fwres.iocbs_qp_limit) {
/* 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++) {
@@ -405,30 +405,48 @@ qla_get_iocbs(struct qla_qpair *qp, struct iocb_resource *iores)
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 {
+ if ((iores->iocb_cnt + iocbs_used) >= qp->fwres.iocbs_limit) {
+ iores->res_type = RESOURCE_NONE;
+ return -ENOSPC;
+ }
+ }
+
+ if (iores->res_type & RESOURCE_EXCH) {
+ exch_used = ha->base_qpair->fwres.exch_used;
+ for (i = 0; i < ha->max_qpairs; i++) {
+ if (ha->queue_pair_map[i])
+ exch_used += ha->queue_pair_map[i]->fwres.exch_used;
+ }
+
+ if ((exch_used + iores->exch_cnt) >= qp->fwres.exch_limit) {
iores->res_type = RESOURCE_NONE;
return -ENOSPC;
}
}
+ qp->fwres.iocbs_used += iores->iocb_cnt;
+ qp->fwres.exch_used += iores->exch_cnt;
+ return 0;
}
static inline void
-qla_put_iocbs(struct qla_qpair *qp, struct iocb_resource *iores)
+qla_put_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores)
{
- switch (iores->res_type) {
- case RESOURCE_NONE:
- break;
- default:
+ if (iores->res_type & RESOURCE_IOCB) {
if (qp->fwres.iocbs_used >= iores->iocb_cnt) {
qp->fwres.iocbs_used -= iores->iocb_cnt;
} else {
- // should not happen
+ /* should not happen */
qp->fwres.iocbs_used = 0;
}
- break;
+ }
+
+ if (iores->res_type & RESOURCE_EXCH) {
+ if (qp->fwres.exch_used >= iores->exch_cnt) {
+ qp->fwres.exch_used -= iores->exch_cnt;
+ } else {
+ /* should not happen */
+ qp->fwres.exch_used = 0;
+ }
}
iores->res_type = RESOURCE_NONE;
}