scsi: qla2xxx: Fix N2N link reset
authorQuinn Tran <qutran@marvell.com>
Thu, 12 Sep 2019 18:09:09 +0000 (11:09 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 24 Sep 2019 03:09:43 +0000 (23:09 -0400)
Fix stalled link recovery for N2N with FC-NVMe connection.

Link: https://lore.kernel.org/r/20190912180918.6436-6-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_def.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c

index fa038568beb6f1bd59c16890abac700d6ada1d99..6ffa9877c28b46bbd371dd949835c06fae92bad3 100644 (file)
@@ -2396,6 +2396,7 @@ typedef struct fc_port {
        unsigned int query:1;
        unsigned int id_changed:1;
        unsigned int scan_needed:1;
+       unsigned int n2n_flag:1;
 
        struct completion nvme_del_done;
        uint32_t nvme_prli_service_param;
@@ -2446,7 +2447,6 @@ typedef struct fc_port {
        uint8_t fc4_type;
        uint8_t fc4f_nvme;
        uint8_t scan_state;
-       uint8_t n2n_flag;
 
        unsigned long last_queue_full;
        unsigned long last_ramp_up;
@@ -3036,6 +3036,7 @@ enum scan_flags_t {
 enum fc4type_t {
        FS_FC4TYPE_FCP  = BIT_0,
        FS_FC4TYPE_NVME = BIT_1,
+       FS_FCP_IS_N2N = BIT_7,
 };
 
 struct fab_scan_rp {
index f6a5d78f93c9bd714d95d64ae747daadaee5d906..67f522a8a9d47b9b8b4ec42db8476a623e72c5e4 100644 (file)
@@ -746,12 +746,15 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
                        break;
                default:
                        if ((id.b24 != fcport->d_id.b24 &&
-                           fcport->d_id.b24) ||
+                           fcport->d_id.b24 &&
+                           fcport->loop_id != FC_NO_LOOP_ID) ||
                            (fcport->loop_id != FC_NO_LOOP_ID &&
                                fcport->loop_id != loop_id)) {
                                ql_dbg(ql_dbg_disc, vha, 0x20e3,
                                    "%s %d %8phC post del sess\n",
                                    __func__, __LINE__, fcport->port_name);
+                               if (fcport->n2n_flag)
+                                       fcport->d_id.b24 = 0;
                                qlt_schedule_sess_for_deletion(fcport);
                                return;
                        }
@@ -759,6 +762,8 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
                }
 
                fcport->loop_id = loop_id;
+               if (fcport->n2n_flag)
+                       fcport->d_id.b24 = id.b24;
 
                wwn = wwn_to_u64(fcport->port_name);
                qlt_find_sess_invalidate_other(vha, wwn,
@@ -972,7 +977,7 @@ static void qla24xx_async_gnl_sp_done(srb_t *sp, int res)
                wwn = wwn_to_u64(e->port_name);
 
                ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x20e8,
-                   "%s %8phC %02x:%02x:%02x state %d/%d lid %x \n",
+                   "%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,
                    (loop_id & 0x7fff));
@@ -1499,7 +1504,8 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
             (fcport->fw_login_state == DSC_LS_PRLI_PEND)))
                return 0;
 
-       if (fcport->fw_login_state == DSC_LS_PLOGI_COMP) {
+       if (fcport->fw_login_state == DSC_LS_PLOGI_COMP &&
+           !N2N_TOPO(vha->hw)) {
                if (time_before_eq(jiffies, fcport->plogi_nack_done_deadline)) {
                        set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
                        return 0;
@@ -1570,8 +1576,9 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
                                qla24xx_post_gpdb_work(vha, fcport, 0);
                        }  else {
                                ql_dbg(ql_dbg_disc, vha, 0x2118,
-                                   "%s %d %8phC post NVMe PRLI\n",
-                                   __func__, __LINE__, fcport->port_name);
+                                   "%s %d %8phC post %s PRLI\n",
+                                   __func__, __LINE__, fcport->port_name,
+                                   fcport->fc4f_nvme ? "NVME" : "FC");
                                qla24xx_post_prli_work(vha, fcport);
                        }
                        break;
@@ -1853,17 +1860,38 @@ qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
                        break;
                }
 
-               if (ea->fcport->n2n_flag) {
+               if (ea->fcport->fc4f_nvme) {
                        ql_dbg(ql_dbg_disc, vha, 0x2118,
                                "%s %d %8phC post fc4 prli\n",
                                __func__, __LINE__, ea->fcport->port_name);
                        ea->fcport->fc4f_nvme = 0;
-                       ea->fcport->n2n_flag = 0;
                        qla24xx_post_prli_work(vha, ea->fcport);
+                       return;
+               }
+
+               /* at this point both PRLI NVME & PRLI FCP failed */
+               if (N2N_TOPO(vha->hw)) {
+                       if (ea->fcport->n2n_link_reset_cnt < 3) {
+                               ea->fcport->n2n_link_reset_cnt++;
+                               /*
+                                * remote port is not sending Plogi. Reset
+                                * link to kick start his state machine
+                                */
+                               set_bit(N2N_LINK_RESET, &vha->dpc_flags);
+                       } else {
+                               ql_log(ql_log_warn, vha, 0x2119,
+                                   "%s %d %8phC Unable to reconnect\n",
+                                   __func__, __LINE__, ea->fcport->port_name);
+                       }
+               } else {
+                       /*
+                        * switch connect. login failed. Take connection
+                        * down and allow relogin to retrigger
+                        */
+                       ea->fcport->flags &= ~FCF_ASYNC_SENT;
+                       ea->fcport->keep_nport_handle = 0;
+                       qlt_schedule_sess_for_deletion(ea->fcport);
                }
-               ql_dbg(ql_dbg_disc, vha, 0x2119,
-                   "%s %d %8phC unhandle event of %x\n",
-                   __func__, __LINE__, ea->fcport->port_name, ea->data[0]);
                break;
        }
 }
@@ -5000,28 +5028,47 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
        unsigned long flags;
 
        /* Inititae N2N login. */
-       if (test_and_clear_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags)) {
-               /* borrowing */
-               u32 *bp, i, sz;
-
-               memset(ha->init_cb, 0, ha->init_cb_size);
-               sz = min_t(int, sizeof(struct els_plogi_payload),
-                   ha->init_cb_size);
-               rval = qla24xx_get_port_login_templ(vha, ha->init_cb_dma,
-                   (void *)ha->init_cb, sz);
-               if (rval == QLA_SUCCESS) {
-                       bp = (uint32_t *)ha->init_cb;
-                       for (i = 0; i < sz/4 ; i++, bp++)
-                               *bp = cpu_to_be32(*bp);
+       if (N2N_TOPO(ha)) {
+               if (test_and_clear_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags)) {
+                       /* borrowing */
+                       u32 *bp, i, sz;
+
+                       memset(ha->init_cb, 0, ha->init_cb_size);
+                       sz = min_t(int, sizeof(struct els_plogi_payload),
+                           ha->init_cb_size);
+                       rval = qla24xx_get_port_login_templ(vha,
+                           ha->init_cb_dma, (void *)ha->init_cb, sz);
+                       if (rval == QLA_SUCCESS) {
+                               bp = (uint32_t *)ha->init_cb;
+                               for (i = 0; i < sz/4 ; i++, bp++)
+                                       *bp = cpu_to_be32(*bp);
 
-                       memcpy(&ha->plogi_els_payld.data, (void *)ha->init_cb,
-                           sizeof(ha->plogi_els_payld.data));
-                       set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
-               } else {
-                       ql_dbg(ql_dbg_init, vha, 0x00d1,
-                           "PLOGI ELS param read fail.\n");
+                               memcpy(&ha->plogi_els_payld.data,
+                                   (void *)ha->init_cb,
+                                   sizeof(ha->plogi_els_payld.data));
+                               set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
+                       } else {
+                               ql_dbg(ql_dbg_init, vha, 0x00d1,
+                                   "PLOGI ELS param read fail.\n");
+                               goto skip_login;
+                       }
+               }
+
+               list_for_each_entry(fcport, &vha->vp_fcports, list) {
+                       if (fcport->n2n_flag) {
+                               qla24xx_fcport_handle_login(vha, fcport);
+                               return QLA_SUCCESS;
+                       }
+               }
+skip_login:
+               spin_lock_irqsave(&vha->work_lock, flags);
+               vha->scan.scan_retry++;
+               spin_unlock_irqrestore(&vha->work_lock, flags);
+
+               if (vha->scan.scan_retry < MAX_SCAN_RETRIES) {
+                       set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
+                       set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
                }
-               return QLA_SUCCESS;
        }
 
        found_devs = 0;
index 4c858e2d0ea8f5a3cddb8bd53890fdc88478ab9b..6d6e10812b427e961b538b19b5f8630750fbdb26 100644 (file)
@@ -2249,7 +2249,7 @@ qla2x00_lip_reset(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x105a,
+       ql_dbg(ql_dbg_disc, vha, 0x105a,
            "Entered %s.\n", __func__);
 
        if (IS_CNA_CAPABLE(vha->hw)) {
@@ -3883,14 +3883,23 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
                case TOPO_N2N:
                        ha->current_topology = ISP_CFG_N;
                        spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
+                       list_for_each_entry(fcport, &vha->vp_fcports, list) {
+                               fcport->scan_state = QLA_FCPORT_SCAN;
+                               fcport->n2n_flag = 0;
+                       }
+
                        fcport = qla2x00_find_fcport_by_wwpn(vha,
                            rptid_entry->u.f1.port_name, 1);
                        spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 
                        if (fcport) {
                                fcport->plogi_nack_done_deadline = jiffies + HZ;
-                               fcport->dm_login_expire = jiffies + 3*HZ;
+                               fcport->dm_login_expire = jiffies + 2*HZ;
                                fcport->scan_state = QLA_FCPORT_FOUND;
+                               fcport->n2n_flag = 1;
+                               if (vha->flags.nvme_enabled)
+                                       fcport->fc4f_nvme = 1;
+
                                switch (fcport->disc_state) {
                                case DSC_DELETED:
                                        set_bit(RELOGIN_NEEDED,
@@ -3924,7 +3933,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
                                    rptid_entry->u.f1.port_name,
                                    rptid_entry->u.f1.node_name,
                                    NULL,
-                                   FC4_TYPE_UNKNOWN);
+                                   FS_FCP_IS_N2N);
                        }
 
                        /* if our portname is higher then initiate N2N login */
@@ -4023,6 +4032,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
 
                list_for_each_entry(fcport, &vha->vp_fcports, list) {
                        fcport->scan_state = QLA_FCPORT_SCAN;
+                       fcport->n2n_flag = 0;
                }
 
                fcport = qla2x00_find_fcport_by_wwpn(vha,
@@ -4032,6 +4042,13 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
                        fcport->login_retry = vha->hw->login_retry_count;
                        fcport->plogi_nack_done_deadline = jiffies + HZ;
                        fcport->scan_state = QLA_FCPORT_FOUND;
+                       fcport->n2n_flag = 1;
+                       fcport->d_id.b.domain =
+                               rptid_entry->u.f2.remote_nport_id[2];
+                       fcport->d_id.b.area =
+                               rptid_entry->u.f2.remote_nport_id[1];
+                       fcport->d_id.b.al_pa =
+                               rptid_entry->u.f2.remote_nport_id[0];
                }
        }
 }
index 5eda86ff6606d1fbf5f7389677c673f9e007bd1b..8411dd5acd439a69e13deef19bc8c1170991d85e 100644 (file)
@@ -5033,6 +5033,10 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
 
                        memcpy(fcport->port_name, e->u.new_sess.port_name,
                            WWN_SIZE);
+
+                       if (e->u.new_sess.fc4_type & FS_FCP_IS_N2N)
+                               fcport->n2n_flag = 1;
+
                } else {
                        ql_dbg(ql_dbg_disc, vha, 0xffff,
                                   "%s %8phC mem alloc fail.\n",