scsi: qla2xxx: Fix exchange oversubscription for management commands
Add resource checking for management (non-I/O) commands.
Fixes: 89c72f4245
("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>
This commit is contained in:
parent
41e5afe51f
commit
5f63a163ed
4 changed files with 80 additions and 3 deletions
|
@ -235,7 +235,7 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
|
||||||
uint16_t mb[MAX_IOCB_MB_REG];
|
uint16_t mb[MAX_IOCB_MB_REG];
|
||||||
int rc;
|
int rc;
|
||||||
struct qla_hw_data *ha = vha->hw;
|
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);
|
rc = qla24xx_res_count_wait(vha, mb, SIZEOF_IOCB_MB_REG);
|
||||||
if (rc != QLA_SUCCESS) {
|
if (rc != QLA_SUCCESS) {
|
||||||
|
@ -263,13 +263,19 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
|
||||||
if (ql2xenforce_iocb_limit) {
|
if (ql2xenforce_iocb_limit) {
|
||||||
/* lock is not require. It's an estimate. */
|
/* lock is not require. It's an estimate. */
|
||||||
iocbs_used = ha->base_qpair->fwres.iocbs_used;
|
iocbs_used = ha->base_qpair->fwres.iocbs_used;
|
||||||
|
exch_used = ha->base_qpair->fwres.exch_used;
|
||||||
for (i = 0; i < ha->max_qpairs; i++) {
|
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;
|
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",
|
seq_printf(s, "Driver: estimate iocb used [%d] high water limit [%d]\n",
|
||||||
iocbs_used, ha->base_qpair->fwres.iocbs_limit);
|
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;
|
return 0;
|
||||||
|
|
|
@ -380,7 +380,7 @@ qla2xxx_get_fc4_priority(struct scsi_qla_host *vha)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RESOURCE_NONE,
|
RESOURCE_NONE,
|
||||||
RESOURCE_IOCB = BIT_0,
|
RESOURCE_IOCB = BIT_0,
|
||||||
RESOURCE_EXCH = BIT_1, /* exchange */
|
RESOURCE_EXCH = BIT_1, /* exchange */
|
||||||
RESOURCE_FORCE = BIT_2,
|
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;
|
iores->res_type = RESOURCE_NONE;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (iores->res_type & RESOURCE_FORCE)
|
||||||
|
goto force;
|
||||||
|
|
||||||
if ((iores->iocb_cnt + qp->fwres.iocbs_used) >= qp->fwres.iocbs_qp_limit) {
|
if ((iores->iocb_cnt + qp->fwres.iocbs_used) >= qp->fwres.iocbs_qp_limit) {
|
||||||
/* no need to acquire qpair lock. It's just rough calculation */
|
/* 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;
|
return -ENOSPC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
force:
|
||||||
qp->fwres.iocbs_used += iores->iocb_cnt;
|
qp->fwres.iocbs_used += iores->iocb_cnt;
|
||||||
qp->fwres.exch_used += iores->exch_cnt;
|
qp->fwres.exch_used += iores->exch_cnt;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -3817,6 +3817,65 @@ qla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio)
|
||||||
logio->vp_index = sp->fcport->vha->vp_idx;
|
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
|
int
|
||||||
qla2x00_start_sp(srb_t *sp)
|
qla2x00_start_sp(srb_t *sp)
|
||||||
{
|
{
|
||||||
|
@ -3831,6 +3890,12 @@ qla2x00_start_sp(srb_t *sp)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
spin_lock_irqsave(qp->qp_lock_ptr, flags);
|
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);
|
pkt = __qla2x00_alloc_iocbs(sp->qpair, sp);
|
||||||
if (!pkt) {
|
if (!pkt) {
|
||||||
rval = EAGAIN;
|
rval = EAGAIN;
|
||||||
|
@ -3931,6 +3996,8 @@ qla2x00_start_sp(srb_t *sp)
|
||||||
wmb();
|
wmb();
|
||||||
qla2x00_start_iocbs(vha, qp->req);
|
qla2x00_start_iocbs(vha, qp->req);
|
||||||
done:
|
done:
|
||||||
|
if (rval)
|
||||||
|
qla_put_fw_resources(sp->qpair, &sp->iores);
|
||||||
spin_unlock_irqrestore(qp->qp_lock_ptr, flags);
|
spin_unlock_irqrestore(qp->qp_lock_ptr, flags);
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3112,6 +3112,7 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt,
|
||||||
}
|
}
|
||||||
bsg_reply->reply_payload_rcv_len = 0;
|
bsg_reply->reply_payload_rcv_len = 0;
|
||||||
|
|
||||||
|
qla_put_fw_resources(sp->qpair, &sp->iores);
|
||||||
done:
|
done:
|
||||||
/* Return the vendor specific reply to API */
|
/* Return the vendor specific reply to API */
|
||||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval;
|
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval;
|
||||||
|
|
Loading…
Add table
Reference in a new issue