scsi: qla2xxx: Fix session cleanup hang
authorQuinn Tran <quinn.tran@cavium.com>
Fri, 25 Jan 2019 07:23:42 +0000 (23:23 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 6 Feb 2019 02:41:16 +0000 (21:41 -0500)
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>
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_os.c

index 65ba0e36ee60b92c1b8082812899b3c01d8d7fb6..2c27ae1924c575d62972b57e3b7c4aed4fa6ca13 100644 (file)
@@ -3645,23 +3645,22 @@ qla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio)
 int
 qla2x00_start_sp(srb_t *sp)
 {
-       int rval;
+       int rval = QLA_SUCCESS;
        scsi_qla_host_t *vha = sp->vha;
        struct qla_hw_data *ha = vha->hw;
        struct qla_qpair *qp = sp->qpair;
        void *pkt;
        unsigned long flags;
 
-       rval = QLA_FUNCTION_FAILED;
        spin_lock_irqsave(qp->qp_lock_ptr, flags);
        pkt = __qla2x00_alloc_iocbs(sp->qpair, sp);
        if (!pkt) {
+               rval = EAGAIN;
                ql_log(ql_log_warn, vha, 0x700c,
                    "qla2x00_alloc_iocbs failed.\n");
                goto done;
        }
 
-       rval = QLA_SUCCESS;
        switch (sp->type) {
        case SRB_LOGIN_CMD:
                IS_FWI2_CAPABLE(ha) ?
index ea58398bfdb1f5dc9d5e5c073824f5a1f6db8c40..7bf23943c81505d950ede0e4de9e4dac4a2f8054 100644 (file)
@@ -5204,14 +5204,14 @@ qla2x00_do_work(struct scsi_qla_host *vha)
        struct qla_work_evt *e, *tmp;
        unsigned long flags;
        LIST_HEAD(work);
+       int rc;
 
        spin_lock_irqsave(&vha->work_lock, flags);
        list_splice_init(&vha->work_list, &work);
        spin_unlock_irqrestore(&vha->work_lock, flags);
 
        list_for_each_entry_safe(e, tmp, &work, list) {
-               list_del_init(&e->list);
-
+               rc = QLA_SUCCESS;
                switch (e->type) {
                case QLA_EVT_AEN:
                        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);
                        break;
                case QLA_EVT_ASYNC_LOGOUT:
-                       qla2x00_async_logout(vha, e->u.logio.fcport);
+                       rc = qla2x00_async_logout(vha, e->u.logio.fcport);
                        break;
                case QLA_EVT_ASYNC_LOGOUT_DONE:
                        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);
                        break;
                case QLA_EVT_ASYNC_PRLO:
-                       qla2x00_async_prlo(vha, e->u.logio.fcport);
+                       rc = qla2x00_async_prlo(vha, e->u.logio.fcport);
                        break;
                case QLA_EVT_ASYNC_PRLO_DONE:
                        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);
                        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)
                        kfree(e);