scsi: qla2xxx: Fix session cleanup hang

On session cleanup, either an implicit LOGO or an implicit PRLO is used to
flush IOs.  If the flush command hit Queue Full condition, then it is
dropped.  This patch adds retry code to prevent command drop.

Signed-off-by: Quinn Tran <quinn.tran@cavium.com>
Signed-off-by: Himanshu Madhani <hmadhani@marvell.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Quinn Tran 2019-01-24 23:23:42 -08:00 committed by Martin K. Petersen
parent 4825034afb
commit 80676d054e
2 changed files with 15 additions and 7 deletions

View File

@ -3645,23 +3645,22 @@ qla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio)
int int
qla2x00_start_sp(srb_t *sp) qla2x00_start_sp(srb_t *sp)
{ {
int rval; int rval = QLA_SUCCESS;
scsi_qla_host_t *vha = sp->vha; scsi_qla_host_t *vha = sp->vha;
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
struct qla_qpair *qp = sp->qpair; struct qla_qpair *qp = sp->qpair;
void *pkt; void *pkt;
unsigned long flags; unsigned long flags;
rval = QLA_FUNCTION_FAILED;
spin_lock_irqsave(qp->qp_lock_ptr, flags); spin_lock_irqsave(qp->qp_lock_ptr, flags);
pkt = __qla2x00_alloc_iocbs(sp->qpair, sp); pkt = __qla2x00_alloc_iocbs(sp->qpair, sp);
if (!pkt) { if (!pkt) {
rval = EAGAIN;
ql_log(ql_log_warn, vha, 0x700c, ql_log(ql_log_warn, vha, 0x700c,
"qla2x00_alloc_iocbs failed.\n"); "qla2x00_alloc_iocbs failed.\n");
goto done; goto done;
} }
rval = QLA_SUCCESS;
switch (sp->type) { switch (sp->type) {
case SRB_LOGIN_CMD: case SRB_LOGIN_CMD:
IS_FWI2_CAPABLE(ha) ? IS_FWI2_CAPABLE(ha) ?

View File

@ -5204,14 +5204,14 @@ qla2x00_do_work(struct scsi_qla_host *vha)
struct qla_work_evt *e, *tmp; struct qla_work_evt *e, *tmp;
unsigned long flags; unsigned long flags;
LIST_HEAD(work); LIST_HEAD(work);
int rc;
spin_lock_irqsave(&vha->work_lock, flags); spin_lock_irqsave(&vha->work_lock, flags);
list_splice_init(&vha->work_list, &work); list_splice_init(&vha->work_list, &work);
spin_unlock_irqrestore(&vha->work_lock, flags); spin_unlock_irqrestore(&vha->work_lock, flags);
list_for_each_entry_safe(e, tmp, &work, list) { list_for_each_entry_safe(e, tmp, &work, list) {
list_del_init(&e->list); rc = QLA_SUCCESS;
switch (e->type) { switch (e->type) {
case QLA_EVT_AEN: case QLA_EVT_AEN:
fc_host_post_event(vha->host, fc_get_event_number(), fc_host_post_event(vha->host, fc_get_event_number(),
@ -5225,7 +5225,7 @@ qla2x00_do_work(struct scsi_qla_host *vha)
e->u.logio.data); e->u.logio.data);
break; break;
case QLA_EVT_ASYNC_LOGOUT: case QLA_EVT_ASYNC_LOGOUT:
qla2x00_async_logout(vha, e->u.logio.fcport); rc = qla2x00_async_logout(vha, e->u.logio.fcport);
break; break;
case QLA_EVT_ASYNC_LOGOUT_DONE: case QLA_EVT_ASYNC_LOGOUT_DONE:
qla2x00_async_logout_done(vha, e->u.logio.fcport, qla2x00_async_logout_done(vha, e->u.logio.fcport,
@ -5270,7 +5270,7 @@ qla2x00_do_work(struct scsi_qla_host *vha)
qla24xx_do_nack_work(vha, e); qla24xx_do_nack_work(vha, e);
break; break;
case QLA_EVT_ASYNC_PRLO: case QLA_EVT_ASYNC_PRLO:
qla2x00_async_prlo(vha, e->u.logio.fcport); rc = qla2x00_async_prlo(vha, e->u.logio.fcport);
break; break;
case QLA_EVT_ASYNC_PRLO_DONE: case QLA_EVT_ASYNC_PRLO_DONE:
qla2x00_async_prlo_done(vha, e->u.logio.fcport, qla2x00_async_prlo_done(vha, e->u.logio.fcport,
@ -5303,6 +5303,15 @@ qla2x00_do_work(struct scsi_qla_host *vha)
e->u.fcport.fcport, false); e->u.fcport.fcport, false);
break; break;
} }
if (rc == EAGAIN) {
/* put 'work' at head of 'vha->work_list' */
spin_lock_irqsave(&vha->work_lock, flags);
list_splice(&work, &vha->work_list);
spin_unlock_irqrestore(&vha->work_lock, flags);
break;
}
list_del_init(&e->list);
if (e->flags & QLA_EVT_FLAG_FREE) if (e->flags & QLA_EVT_FLAG_FREE)
kfree(e); kfree(e);