scsi: qla2xxx: Fix fabric scan hang
authorQuinn Tran <qutran@marvell.com>
Tue, 17 Dec 2019 22:06:05 +0000 (14:06 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 20 Dec 2019 03:42:44 +0000 (22:42 -0500)
On timeout, SRB pointer was cleared from outstanding command array and
dropped.  It was not allowed to go through the done process and cleanup.
This patch will abort the SRB where FW will return it with an error status
and resume the normal cleanup.

Link: https://lore.kernel.org/r/20191217220617.28084-3-hmadhani@marvell.com
Signed-off-by: Quinn Tran <qutran@marvell.com>
Signed-off-by: Himanshu Madhani <hmadhani@marvell.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_iocb.c

index 51916183cbe93074ed428c75bc50fd48231f027e..0678d18144e348889998bdada8beedbba66e7078 100644 (file)
@@ -255,6 +255,7 @@ extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
 
 extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int);
 extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *);
+extern int qla24xx_async_abort_cmd(srb_t *, bool);
 
 extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *);
 
index c689e34a5235f5b7510d8bce046c8d81ab57a0c4..0758b1cefffebb984ae5e51880ec1ef516e1a219 100644 (file)
@@ -49,16 +49,9 @@ qla2x00_sp_timeout(struct timer_list *t)
 {
        srb_t *sp = from_timer(sp, t, u.iocb_cmd.timer);
        struct srb_iocb *iocb;
-       struct req_que *req;
-       unsigned long flags;
-       struct qla_hw_data *ha = sp->vha->hw;
 
-       WARN_ON_ONCE(irqs_disabled());
-       spin_lock_irqsave(&ha->hardware_lock, flags);
-       req = sp->qpair->req;
-       req->outstanding_cmds[sp->handle] = NULL;
+       WARN_ON(irqs_disabled());
        iocb = &sp->u.iocb_cmd;
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
        iocb->timeout(sp);
 }
 
@@ -142,7 +135,7 @@ static void qla24xx_abort_sp_done(srb_t *sp, int res)
                sp->free(sp);
 }
 
-static int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait)
+int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait)
 {
        scsi_qla_host_t *vha = cmd_sp->vha;
        struct srb_iocb *abt_iocb;
@@ -242,6 +235,7 @@ qla2x00_async_iocb_timeout(void *data)
        case SRB_NACK_PRLI:
        case SRB_NACK_LOGO:
        case SRB_CTRL_VP:
+       default:
                rc = qla24xx_async_abort_cmd(sp, false);
                if (rc) {
                        spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
@@ -258,10 +252,6 @@ qla2x00_async_iocb_timeout(void *data)
                        sp->done(sp, QLA_FUNCTION_TIMEOUT);
                }
                break;
-       default:
-               WARN_ON_ONCE(true);
-               sp->done(sp, QLA_FUNCTION_TIMEOUT);
-               break;
        }
 }
 
@@ -1758,9 +1748,23 @@ qla2x00_tmf_iocb_timeout(void *data)
 {
        srb_t *sp = data;
        struct srb_iocb *tmf = &sp->u.iocb_cmd;
+       int rc, h;
+       unsigned long flags;
 
-       tmf->u.tmf.comp_status = CS_TIMEOUT;
-       complete(&tmf->u.tmf.comp);
+       rc = qla24xx_async_abort_cmd(sp, false);
+       if (rc) {
+               spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
+               for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) {
+                       if (sp->qpair->req->outstanding_cmds[h] == sp) {
+                               sp->qpair->req->outstanding_cmds[h] = NULL;
+                               break;
+                       }
+               }
+               spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags);
+               tmf->u.tmf.comp_status = CS_TIMEOUT;
+               tmf->u.tmf.data = QLA_FUNCTION_FAILED;
+               complete(&tmf->u.tmf.comp);
+       }
 }
 
 static void qla2x00_tmf_sp_done(srb_t *sp, int res)
index 8b050f0b43330543f365a4f8e83eb2ae67342813..15c76b9a4502a151e4215b03331d4ba7fa5558b8 100644 (file)
@@ -2537,13 +2537,32 @@ qla2x00_els_dcmd_iocb_timeout(void *data)
        fc_port_t *fcport = sp->fcport;
        struct scsi_qla_host *vha = sp->vha;
        struct srb_iocb *lio = &sp->u.iocb_cmd;
+       unsigned long flags = 0;
+       int res, h;
 
        ql_dbg(ql_dbg_io, vha, 0x3069,
            "%s Timeout, hdl=%x, portid=%02x%02x%02x\n",
            sp->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area,
            fcport->d_id.b.al_pa);
 
-       complete(&lio->u.els_logo.comp);
+       /* Abort the exchange */
+       res = qla24xx_async_abort_cmd(sp, false);
+       if (res) {
+               ql_dbg(ql_dbg_io, vha, 0x3070,
+                   "mbx abort_command failed.\n");
+               spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
+               for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) {
+                       if (sp->qpair->req->outstanding_cmds[h] == sp) {
+                               sp->qpair->req->outstanding_cmds[h] = NULL;
+                               break;
+                       }
+               }
+               spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags);
+               complete(&lio->u.els_logo.comp);
+       } else {
+               ql_dbg(ql_dbg_io, vha, 0x3071,
+                   "mbx abort_command success.\n");
+       }
 }
 
 static void qla2x00_els_dcmd_sp_done(srb_t *sp, int res)
@@ -2717,23 +2736,29 @@ qla2x00_els_dcmd2_iocb_timeout(void *data)
        srb_t *sp = data;
        fc_port_t *fcport = sp->fcport;
        struct scsi_qla_host *vha = sp->vha;
-       struct qla_hw_data *ha = vha->hw;
        unsigned long flags = 0;
-       int res;
+       int res, h;
 
        ql_dbg(ql_dbg_io + ql_dbg_disc, vha, 0x3069,
            "%s hdl=%x ELS Timeout, %8phC portid=%06x\n",
            sp->name, sp->handle, fcport->port_name, fcport->d_id.b24);
 
        /* Abort the exchange */
-       spin_lock_irqsave(&ha->hardware_lock, flags);
-       res = ha->isp_ops->abort_command(sp);
+       res = qla24xx_async_abort_cmd(sp, false);
        ql_dbg(ql_dbg_io, vha, 0x3070,
            "mbx abort_command %s\n",
            (res == QLA_SUCCESS) ? "successful" : "failed");
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
-       sp->done(sp, QLA_FUNCTION_TIMEOUT);
+       if (res) {
+               spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
+               for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) {
+                       if (sp->qpair->req->outstanding_cmds[h] == sp) {
+                               sp->qpair->req->outstanding_cmds[h] = NULL;
+                               break;
+                       }
+               }
+               spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags);
+               sp->done(sp, QLA_FUNCTION_TIMEOUT);
+       }
 }
 
 void qla2x00_els_dcmd2_free(scsi_qla_host_t *vha, struct els_plogi *els_plogi)