OSDN Git Service

scsi: qla2xxx: Fix stuck session in GNL
authorQuinn Tran <qutran@marvell.com>
Tue, 17 Dec 2019 22:06:15 +0000 (14:06 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sat, 21 Dec 2019 18:42:41 +0000 (13:42 -0500)
Fix race condition between GNL completion processing and GNL request. Late
submission of GNL request was not seen by the GNL completion thread. This
patch will re-submit the GNL request for late submission fcport.

Link: https://lore.kernel.org/r/20191217220617.28084-13-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_init.c
drivers/scsi/qla2xxx/qla_target.c

index 4f849b1..a5076f4 100644 (file)
@@ -990,7 +990,7 @@ static void qla24xx_async_gnl_sp_done(srb_t *sp, int res)
                set_bit(loop_id, vha->hw->loop_id_map);
                wwn = wwn_to_u64(e->port_name);
 
-               ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x20e8,
+               ql_dbg(ql_dbg_disc, vha, 0x20e8,
                    "%s %8phC %02x:%02x:%02x CLS %x/%x lid %x \n",
                    __func__, (void *)&wwn, e->port_id[2], e->port_id[1],
                    e->port_id[0], e->current_login_state, e->last_login_state,
@@ -1049,6 +1049,16 @@ static void qla24xx_async_gnl_sp_done(srb_t *sp, int res)
 
        spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
        vha->gnl.sent = 0;
+       if (!list_empty(&vha->gnl.fcports)) {
+               /* retrigger gnl */
+               list_for_each_entry_safe(fcport, tf, &vha->gnl.fcports,
+                   gnl_entry) {
+                       list_del_init(&fcport->gnl_entry);
+                       fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
+                       if (qla24xx_post_gnl_work(vha, fcport) == QLA_SUCCESS)
+                               break;
+               }
+       }
        spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 
        sp->free(sp);
@@ -2000,7 +2010,7 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
                        qla24xx_post_prli_work(vha, ea->fcport);
                } else {
                        ql_dbg(ql_dbg_disc, vha, 0x20ea,
-                           "%s %d %8phC LoopID 0x%x in use with %06x. post gnl\n",
+                           "%s %d %8phC LoopID 0x%x in use with %06x. post gpdb\n",
                            __func__, __LINE__, ea->fcport->port_name,
                            ea->fcport->loop_id, ea->fcport->d_id.b24);
 
@@ -2071,6 +2081,7 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
                        set_bit(lid, vha->hw->loop_id_map);
                        ea->fcport->loop_id = lid;
                        ea->fcport->keep_nport_handle = 0;
+                       ea->fcport->logout_on_delete = 1;
                        qlt_schedule_sess_for_deletion(ea->fcport);
                }
                break;
index 0ef7674..97af678 100644 (file)
@@ -958,7 +958,7 @@ void qlt_free_session_done(struct work_struct *work)
        struct qlt_plogi_ack_t *own =
                sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN];
 
-       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf084,
+       ql_dbg(ql_dbg_disc, vha, 0xf084,
                "%s: se_sess %p / sess %p from port %8phC loop_id %#04x"
                " s_id %02x:%02x:%02x logout %d keep %d els_logo %d\n",
                __func__, sess->se_sess, sess, sess->port_name, sess->loop_id,
@@ -1025,7 +1025,7 @@ void qlt_free_session_done(struct work_struct *work)
 
                while (!READ_ONCE(sess->logout_completed)) {
                        if (!traced) {
-                               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf086,
+                               ql_dbg(ql_dbg_disc, vha, 0xf086,
                                        "%s: waiting for sess %p logout\n",
                                        __func__, sess);
                                traced = true;
@@ -1046,6 +1046,10 @@ void qlt_free_session_done(struct work_struct *work)
                        (struct imm_ntfy_from_isp *)sess->iocb, SRB_NACK_LOGO);
        }
 
+       spin_lock_irqsave(&vha->work_lock, flags);
+       sess->flags &= ~FCF_ASYNC_SENT;
+       spin_unlock_irqrestore(&vha->work_lock, flags);
+
        spin_lock_irqsave(&ha->tgt.sess_lock, flags);
        if (sess->se_sess) {
                sess->se_sess = NULL;
@@ -1109,7 +1113,7 @@ void qlt_free_session_done(struct work_struct *work)
        spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
        sess->free_pending = 0;
 
-       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf001,
+       ql_dbg(ql_dbg_disc, vha, 0xf001,
            "Unregistration of sess %p %8phC finished fcp_cnt %d\n",
                sess, sess->port_name, vha->fcport_count);
 
@@ -1152,6 +1156,11 @@ void qlt_unreg_sess(struct fc_port *sess)
                return;
        }
        sess->free_pending = 1;
+       /*
+        * Use FCF_ASYNC_SENT flag to block other cmds used in sess
+        * management from being sent.
+        */
+       sess->flags |= FCF_ASYNC_SENT;
        spin_unlock_irqrestore(&sess->vha->work_lock, flags);
 
        if (sess->se_sess)
@@ -4581,7 +4590,7 @@ qlt_find_sess_invalidate_other(scsi_qla_host_t *vha, uint64_t wwn,
                /* find other sess with nport_id collision */
                if (port_id.b24 == other_sess->d_id.b24) {
                        if (loop_id != other_sess->loop_id) {
-                               ql_dbg(ql_dbg_tgt_tmr, vha, 0x1000c,
+                               ql_dbg(ql_dbg_disc, vha, 0x1000c,
                                    "Invalidating sess %p loop_id %d wwn %llx.\n",
                                    other_sess, other_sess->loop_id, other_wwn);
 
@@ -4597,7 +4606,7 @@ qlt_find_sess_invalidate_other(scsi_qla_host_t *vha, uint64_t wwn,
                                 * Another wwn used to have our s_id/loop_id
                                 * kill the session, but don't free the loop_id
                                 */
-                               ql_dbg(ql_dbg_tgt_tmr, vha, 0xf01b,
+                               ql_dbg(ql_dbg_disc, vha, 0xf01b,
                                    "Invalidating sess %p loop_id %d wwn %llx.\n",
                                    other_sess, other_sess->loop_id, other_wwn);
 
@@ -4612,7 +4621,7 @@ qlt_find_sess_invalidate_other(scsi_qla_host_t *vha, uint64_t wwn,
                /* find other sess with nport handle collision */
                if ((loop_id == other_sess->loop_id) &&
                        (loop_id != FC_NO_LOOP_ID)) {
-                       ql_dbg(ql_dbg_tgt_tmr, vha, 0x1000d,
+                       ql_dbg(ql_dbg_disc, vha, 0x1000d,
                               "Invalidating sess %p loop_id %d wwn %llx.\n",
                               other_sess, other_sess->loop_id, other_wwn);