Skip to content

Commit e370b64

Browse files
Quinn Tranmartinkpetersen
authored andcommitted
scsi: qla2xxx: Fix firmware resource tracking
The storage was not draining I/Os and the work load was not spread out across different CPUs evenly. This led to firmware resource counters getting overrun on the busy CPU. This overrun prevented error recovery from happening in a timely manner. By switching the counter to atomic, it allows the count to be little more accurate to prevent the overrun. Cc: stable@vger.kernel.org Fixes: da7c21b ("scsi: qla2xxx: Fix command flush during TMF") Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Link: https://lore.kernel.org/r/20230821130045.34850-4-njavali@marvell.com Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 6d0b655 commit e370b64

File tree

5 files changed

+88
-3
lines changed

5 files changed

+88
-3
lines changed

drivers/scsi/qla2xxx/qla_def.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3770,6 +3770,16 @@ struct qla_fw_resources {
37703770
u16 pad;
37713771
};
37723772

3773+
struct qla_fw_res {
3774+
u16 iocb_total;
3775+
u16 iocb_limit;
3776+
atomic_t iocb_used;
3777+
3778+
u16 exch_total;
3779+
u16 exch_limit;
3780+
atomic_t exch_used;
3781+
};
3782+
37733783
#define QLA_IOCB_PCT_LIMIT 95
37743784

37753785
struct qla_buf_pool {
@@ -4830,6 +4840,7 @@ struct qla_hw_data {
48304840
u8 edif_post_stop_cnt_down;
48314841
struct qla_vp_map *vp_map;
48324842
struct qla_nvme_fc_rjt lsrjt;
4843+
struct qla_fw_res fwres ____cacheline_aligned;
48334844
};
48344845

48354846
#define RX_ELS_SIZE (roundup(sizeof(struct enode) + ELS_MAX_PAYLOAD, SMP_CACHE_BYTES))

drivers/scsi/qla2xxx/qla_dfs.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,16 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
276276

277277
seq_printf(s, "estimate exchange used[%d] high water limit [%d] n",
278278
exch_used, ha->base_qpair->fwres.exch_limit);
279+
280+
if (ql2xenforce_iocb_limit == 2) {
281+
iocbs_used = atomic_read(&ha->fwres.iocb_used);
282+
exch_used = atomic_read(&ha->fwres.exch_used);
283+
seq_printf(s, " estimate iocb2 used [%d] high water limit [%d]\n",
284+
iocbs_used, ha->fwres.iocb_limit);
285+
286+
seq_printf(s, " estimate exchange2 used[%d] high water limit [%d] \n",
287+
exch_used, ha->fwres.exch_limit);
288+
}
279289
}
280290

281291
return 0;

drivers/scsi/qla2xxx/qla_init.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4214,6 +4214,14 @@ void qla_init_iocb_limit(scsi_qla_host_t *vha)
42144214
ha->queue_pair_map[i]->fwres.exch_used = 0;
42154215
}
42164216
}
4217+
4218+
ha->fwres.iocb_total = ha->orig_fw_iocb_count;
4219+
ha->fwres.iocb_limit = (ha->orig_fw_iocb_count * QLA_IOCB_PCT_LIMIT) / 100;
4220+
ha->fwres.exch_total = ha->orig_fw_xcb_count;
4221+
ha->fwres.exch_limit = (ha->orig_fw_xcb_count * QLA_IOCB_PCT_LIMIT) / 100;
4222+
4223+
atomic_set(&ha->fwres.iocb_used, 0);
4224+
atomic_set(&ha->fwres.exch_used, 0);
42174225
}
42184226

42194227
void qla_adjust_iocb_limit(scsi_qla_host_t *vha)

drivers/scsi/qla2xxx/qla_inline.h

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,14 +386,15 @@ enum {
386386
RESOURCE_IOCB = BIT_0,
387387
RESOURCE_EXCH = BIT_1, /* exchange */
388388
RESOURCE_FORCE = BIT_2,
389+
RESOURCE_HA = BIT_3,
389390
};
390391

391392
static inline int
392393
qla_get_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores)
393394
{
394395
u16 iocbs_used, i;
395396
u16 exch_used;
396-
struct qla_hw_data *ha = qp->vha->hw;
397+
struct qla_hw_data *ha = qp->hw;
397398

398399
if (!ql2xenforce_iocb_limit) {
399400
iores->res_type = RESOURCE_NONE;
@@ -428,15 +429,69 @@ qla_get_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores)
428429
return -ENOSPC;
429430
}
430431
}
432+
433+
if (ql2xenforce_iocb_limit == 2) {
434+
if ((iores->iocb_cnt + atomic_read(&ha->fwres.iocb_used)) >=
435+
ha->fwres.iocb_limit) {
436+
iores->res_type = RESOURCE_NONE;
437+
return -ENOSPC;
438+
}
439+
440+
if (iores->res_type & RESOURCE_EXCH) {
441+
if ((iores->exch_cnt + atomic_read(&ha->fwres.exch_used)) >=
442+
ha->fwres.exch_limit) {
443+
iores->res_type = RESOURCE_NONE;
444+
return -ENOSPC;
445+
}
446+
}
447+
}
448+
431449
force:
432450
qp->fwres.iocbs_used += iores->iocb_cnt;
433451
qp->fwres.exch_used += iores->exch_cnt;
452+
if (ql2xenforce_iocb_limit == 2) {
453+
atomic_add(iores->iocb_cnt, &ha->fwres.iocb_used);
454+
atomic_add(iores->exch_cnt, &ha->fwres.exch_used);
455+
iores->res_type |= RESOURCE_HA;
456+
}
434457
return 0;
435458
}
436459

460+
/*
461+
* decrement to zero. This routine will not decrement below zero
462+
* @v: pointer of type atomic_t
463+
* @amount: amount to decrement from v
464+
*/
465+
static void qla_atomic_dtz(atomic_t *v, int amount)
466+
{
467+
int c, old, dec;
468+
469+
c = atomic_read(v);
470+
for (;;) {
471+
dec = c - amount;
472+
if (unlikely(dec < 0))
473+
dec = 0;
474+
475+
old = atomic_cmpxchg((v), c, dec);
476+
if (likely(old == c))
477+
break;
478+
c = old;
479+
}
480+
}
481+
437482
static inline void
438483
qla_put_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores)
439484
{
485+
struct qla_hw_data *ha = qp->hw;
486+
487+
if (iores->res_type & RESOURCE_HA) {
488+
if (iores->res_type & RESOURCE_IOCB)
489+
qla_atomic_dtz(&ha->fwres.iocb_used, iores->iocb_cnt);
490+
491+
if (iores->res_type & RESOURCE_EXCH)
492+
qla_atomic_dtz(&ha->fwres.exch_used, iores->exch_cnt);
493+
}
494+
440495
if (iores->res_type & RESOURCE_IOCB) {
441496
if (qp->fwres.iocbs_used >= iores->iocb_cnt) {
442497
qp->fwres.iocbs_used -= iores->iocb_cnt;

drivers/scsi/qla2xxx/qla_os.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@ module_param(ql2xfulldump_on_mpifail, int, S_IRUGO | S_IWUSR);
4444
MODULE_PARM_DESC(ql2xfulldump_on_mpifail,
4545
"Set this to take full dump on MPI hang.");
4646

47-
int ql2xenforce_iocb_limit = 1;
47+
int ql2xenforce_iocb_limit = 2;
4848
module_param(ql2xenforce_iocb_limit, int, S_IRUGO | S_IWUSR);
4949
MODULE_PARM_DESC(ql2xenforce_iocb_limit,
50-
"Enforce IOCB throttling, to avoid FW congestion. (default: 1)");
50+
"Enforce IOCB throttling, to avoid FW congestion. (default: 2) "
51+
"1: track usage per queue, 2: track usage per adapter");
5152

5253
/*
5354
* CT6 CTX allocation cache

0 commit comments

Comments
 (0)