From: Quinn Tran <quinn.t...@cavium.com>

In case of N2N connect, when sg_regset for bus/device/host
was causing driver and firmware state to go out of sync.
This patch fixes this link instablity when reconnect is
attempted after link flap.

Signed-off-by: Quinn Tran <quinn.t...@cavium.com>
Signed-off-by: Himanshu Madhani <himanshu.madh...@cavium.com>
---
 drivers/scsi/qla2xxx/qla_def.h    |   3 +-
 drivers/scsi/qla2xxx/qla_init.c   | 223 +++++++++++++++++++++++++-------------
 drivers/scsi/qla2xxx/qla_iocb.c   |  15 ++-
 drivers/scsi/qla2xxx/qla_isr.c    |   3 +-
 drivers/scsi/qla2xxx/qla_mbx.c    |  27 +----
 drivers/scsi/qla2xxx/qla_os.c     |   5 +
 drivers/scsi/qla2xxx/qla_target.c |   9 ++
 7 files changed, 179 insertions(+), 106 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 0f94b1d62d3f..b595479d445b 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -379,6 +379,7 @@ struct srb_iocb {
 #define SRB_LOGIN_COND_PLOGI   BIT_1
 #define SRB_LOGIN_SKIP_PRLI    BIT_2
 #define SRB_LOGIN_NVME_PRLI    BIT_3
+#define SRB_LOGIN_PRLI_ONLY    BIT_4
                        uint16_t data[2];
                        u32 iop[2];
                } logio;
@@ -4238,7 +4239,7 @@ typedef struct scsi_qla_host {
 #define FCOE_CTX_RESET_NEEDED  18      /* Initiate FCoE context reset */
 #define MPI_RESET_NEEDED       19      /* Initiate MPI FW reset */
 #define ISP_QUIESCE_NEEDED     20      /* Driver need some quiescence */
-#define FREE_BIT 21
+#define N2N_LINK_RESET         21
 #define PORT_UPDATE_NEEDED     22
 #define FX00_RESET_RECOVERY    23
 #define FX00_TARGET_SCAN       24
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index f7d03cddb583..258f95c79c06 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -160,6 +160,22 @@ qla2x00_async_login_sp_done(void *ptr, int res)
        sp->free(sp);
 }
 
+static inline bool
+fcport_is_smaller(fc_port_t *fcport)
+{
+       if (wwn_to_u64(fcport->port_name) <
+           wwn_to_u64(fcport->vha->port_name))
+               return true;
+       else
+               return false;
+}
+
+static inline bool
+fcport_is_bigger(fc_port_t *fcport)
+{
+       return !fcport_is_smaller(fcport);
+}
+
 int
 qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
     uint16_t *data)
@@ -189,13 +205,18 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t 
*fcport,
        qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
 
        sp->done = qla2x00_async_login_sp_done;
-       lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;
+       if (N2N_TOPO(fcport->vha->hw) && fcport_is_bigger(fcport)) {
+               lio->u.logio.flags |= SRB_LOGIN_PRLI_ONLY;
+       } else {
+               lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;
 
-       if (fcport->fc4f_nvme)
-               lio->u.logio.flags |= SRB_LOGIN_SKIP_PRLI;
+               if (fcport->fc4f_nvme)
+                       lio->u.logio.flags |= SRB_LOGIN_SKIP_PRLI;
+
+               if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
+                       lio->u.logio.flags |= SRB_LOGIN_RETRIED;
+       }
 
-       if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
-               lio->u.logio.flags |= SRB_LOGIN_RETRIED;
        rval = qla2x00_start_sp(sp);
        if (rval != QLA_SUCCESS) {
                fcport->flags |= FCF_LOGIN_NEEDED;
@@ -497,15 +518,18 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t 
*vha,
        for (i = 0; i < n; i++) {
                e = &vha->gnl.l[i];
                wwn = wwn_to_u64(e->port_name);
+               id.b.domain = e->port_id[2];
+               id.b.area = e->port_id[1];
+               id.b.al_pa = e->port_id[0];
+               id.b.rsvd_1 = 0;
 
                if (memcmp((u8 *)&wwn, fcport->port_name, WWN_SIZE))
                        continue;
 
+               if (IS_SW_RESV_ADDR(id))
+                       continue;
+
                found = 1;
-               id.b.domain = e->port_id[2];
-               id.b.area = e->port_id[1];
-               id.b.al_pa = e->port_id[0];
-               id.b.rsvd_1 = 0;
 
                loop_id = le16_to_cpu(e->nport_handle);
                loop_id = (loop_id & 0x7fff);
@@ -518,14 +542,18 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t 
*vha,
                    fcport->d_id.b.domain, fcport->d_id.b.area,
                    fcport->d_id.b.al_pa, loop_id, fcport->loop_id);
 
-               if ((id.b24 != fcport->d_id.b24) ||
-                   ((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);
-                       qlt_schedule_sess_for_deletion(fcport);
-                       return;
+               switch (fcport->disc_state) {
+               case DSC_DELETE_PEND:
+               case DSC_DELETED:
+                       break;
+               default:
+                       if ((id.b24 != fcport->d_id.b24) ||
+                           ((fcport->loop_id != FC_NO_LOOP_ID) &&
+                               (fcport->loop_id != loop_id))) {
+                               qlt_schedule_sess_for_deletion(fcport);
+                               return;
+                       }
+                       break;
                }
 
                fcport->loop_id = loop_id;
@@ -544,68 +572,124 @@ static void 
qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
                        fcport->login_pause = 1;
                }
 
-               if  (fcport->fc4f_nvme)
+               if (fcport->fc4f_nvme)
                        current_login_state = e->current_login_state >> 4;
                else
                        current_login_state = e->current_login_state & 0xf;
 
-               switch (current_login_state) {
-               case DSC_LS_PRLI_COMP:
-                       ql_dbg(ql_dbg_disc, vha, 0x20e4,
-                           "%s %d %8phC post gpdb\n",
-                           __func__, __LINE__, fcport->port_name);
+               switch (vha->hw->current_topology) {
+               default:
+                       switch (current_login_state) {
+                       case DSC_LS_PRLI_COMP:
+                               ql_dbg(ql_dbg_disc + ql_dbg_verbose,
+                                   vha, 0x20e4, "%s %d %8phC post gpdb\n",
+                                   __func__, __LINE__, fcport->port_name);
 
-                       if ((e->prli_svc_param_word_3[0] & BIT_4) == 0)
-                               fcport->port_type = FCT_INITIATOR;
-                       else
-                               fcport->port_type = FCT_TARGET;
+                               if ((e->prli_svc_param_word_3[0] & BIT_4) == 0)
+                                       fcport->port_type = FCT_INITIATOR;
+                               else
+                                       fcport->port_type = FCT_TARGET;
 
-                       data[0] = data[1] = 0;
-                       qla2x00_post_async_adisc_work(vha, fcport, data);
-                       break;
-               case DSC_LS_PORT_UNAVAIL:
-               default:
-                       if (fcport->loop_id == FC_NO_LOOP_ID) {
-                               qla2x00_find_new_loop_id(vha, fcport);
+                               data[0] = data[1] = 0;
+                               qla2x00_post_async_adisc_work(vha, fcport,
+                                   data);
+                               break;
+                       case DSC_LS_PORT_UNAVAIL:
+                       default:
+                               if (fcport->loop_id != FC_NO_LOOP_ID)
+                                       qla2x00_clear_loop_id(fcport);
+
+                               fcport->loop_id = loop_id;
                                fcport->fw_login_state = DSC_LS_PORT_UNAVAIL;
+                               qla24xx_fcport_handle_login(vha, fcport);
+                               break;
                        }
-                       ql_dbg(ql_dbg_disc, vha, 0x20e5,
-                           "%s %d %8phC\n",
-                           __func__, __LINE__, fcport->port_name);
-                       qla24xx_fcport_handle_login(vha, fcport);
                        break;
-               }
+               case ISP_CFG_N:
+                       switch (current_login_state) {
+                       case DSC_LS_PRLI_COMP:
+                               if ((e->prli_svc_param_word_3[0] & BIT_4) == 0)
+                                       fcport->port_type = FCT_INITIATOR;
+                               else
+                                       fcport->port_type = FCT_TARGET;
+
+                               data[0] = data[1] = 0;
+                               qla2x00_post_async_adisc_work(vha, fcport,
+                                   data);
+                               break;
+                       case DSC_LS_PLOGI_COMP:
+                               if (fcport_is_bigger(fcport)) {
+                                       /* local adapter is smaller */
+                                       if (fcport->loop_id != FC_NO_LOOP_ID)
+                                               qla2x00_clear_loop_id(fcport);
+
+                                       fcport->loop_id = loop_id;
+                                       qla24xx_fcport_handle_login(vha,
+                                           fcport);
+                                       break;
+                               }
+                               /* drop through */
+                       default:
+                               if (fcport_is_smaller(fcport)) {
+                                       /* local adapter is bigger */
+                                       if (fcport->loop_id != FC_NO_LOOP_ID)
+                                               qla2x00_clear_loop_id(fcport);
+
+                                       fcport->loop_id = loop_id;
+                                       qla24xx_fcport_handle_login(vha,
+                                           fcport);
+                               }
+                               break;
+                       }
+                       break;
+               } /* switch (ha->current_topology) */
        }
 
        if (!found) {
-               /* fw has no record of this port */
-               for (i = 0; i < n; i++) {
-                       e = &vha->gnl.l[i];
-                       id.b.domain = e->port_id[0];
-                       id.b.area = e->port_id[1];
-                       id.b.al_pa = e->port_id[2];
-                       id.b.rsvd_1 = 0;
-                       loop_id = le16_to_cpu(e->nport_handle);
-
-                       if (fcport->d_id.b24 == id.b24) {
-                               conflict_fcport =
-                                       qla2x00_find_fcport_by_wwpn(vha,
-                                           e->port_name, 0);
-                               if (conflict_fcport) {
-                                       qlt_schedule_sess_for_deletion
-                                               (conflict_fcport);
-                                       ql_dbg(ql_dbg_disc, vha, 0x20e6,
+               switch (vha->hw->current_topology) {
+               case ISP_CFG_F:
+               case ISP_CFG_FL:
+                       for (i = 0; i < n; i++) {
+                               e = &vha->gnl.l[i];
+                               id.b.domain = e->port_id[0];
+                               id.b.area = e->port_id[1];
+                               id.b.al_pa = e->port_id[2];
+                               id.b.rsvd_1 = 0;
+                               loop_id = le16_to_cpu(e->nport_handle);
+
+                               if (fcport->d_id.b24 == id.b24) {
+                                       conflict_fcport =
+                                           qla2x00_find_fcport_by_wwpn(vha,
+                                               e->port_name, 0);
+                                       ql_dbg(ql_dbg_disc + ql_dbg_verbose,
+                                           vha, 0x20e6,
                                            "%s %d %8phC post del sess\n",
                                            __func__, __LINE__,
                                            conflict_fcport->port_name);
+                                       qlt_schedule_sess_for_deletion
+                                               (conflict_fcport);
                                }
-                       }
 
-                       /* FW already picked this loop id for another fcport */
-                       if (fcport->loop_id == loop_id)
-                               fcport->loop_id = FC_NO_LOOP_ID;
+                               /*
+                                * FW already picked this loop id for
+                                * another fcport
+                                */
+                               if (fcport->loop_id == loop_id)
+                                       fcport->loop_id = FC_NO_LOOP_ID;
+                       }
+                       qla24xx_fcport_handle_login(vha, fcport);
+                       break;
+               case ISP_CFG_N:
+                       /*
+                        * FW handles the initial login for n2n.
+                        * Do link reinit to trigger this auto login.
+                        */
+                       set_bit(N2N_LINK_RESET, &vha->dpc_flags);
+                       qla2xxx_wake_dpc(vha);
+                       break;
+               default:
+                       break;
                }
-               qla24xx_fcport_handle_login(vha, fcport);
        }
 } /* gnl_event */
 
@@ -4591,20 +4675,10 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
 
        } else if (ha->current_topology == ISP_CFG_N) {
                clear_bit(RSCN_UPDATE, &flags);
-               if (ha->flags.rida_fmt2) {
-                       /* With Rida Format 2, the login is already triggered.
-                        * We know who is on the other side of the wire.
-                        * No need to login to do login to find out or drop into
-                        * qla2x00_configure_local_loop().
-                        */
+               if (qla_tgt_mode_enabled(vha)) {
+                       /* allow the other side to start the login */
                        clear_bit(LOCAL_LOOP_UPDATE, &flags);
                        set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
-               } else {
-                       if (qla_tgt_mode_enabled(vha)) {
-                               /* allow the other side to start the login */
-                               clear_bit(LOCAL_LOOP_UPDATE, &flags);
-                               set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
-                       }
                }
        } else if (ha->current_topology == ISP_CFG_NL) {
                clear_bit(RSCN_UPDATE, &flags);
@@ -7930,8 +8004,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
        }
 
         /* enable RIDA Format2 */
-       if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha))
-               icb->firmware_options_3 |= BIT_0;
+       icb->firmware_options_3 |= BIT_0;
 
        if (IS_QLA27XX(ha)) {
                icb->firmware_options_3 |= BIT_8;
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index b349e9b94c08..e1ff2e27e59f 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2240,12 +2240,15 @@ qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx 
*logio)
        struct srb_iocb *lio = &sp->u.iocb_cmd;
 
        logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
-       logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI);
-
-       if (lio->u.logio.flags & SRB_LOGIN_COND_PLOGI)
-               logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI);
-       if (lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI)
-               logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI);
+       if (lio->u.logio.flags & SRB_LOGIN_PRLI_ONLY) {
+               logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI);
+       } else {
+               logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI);
+               if (lio->u.logio.flags & SRB_LOGIN_COND_PLOGI)
+                       logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI);
+               if (lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI)
+                       logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI);
+       }
        logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
        logio->port_id[0] = sp->fcport->d_id.b.al_pa;
        logio->port_id[1] = sp->fcport->d_id.b.area;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 7756106d4555..36cbb29c84f6 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -911,7 +911,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que 
*rsp, uint16_t *mb)
                        if (!atomic_read(&vha->loop_down_timer))
                                atomic_set(&vha->loop_down_timer,
                                    LOOP_DOWN_TIME);
-                       qla2x00_mark_all_devices_lost(vha, 1);
+                       if (!N2N_TOPO(ha))
+                               qla2x00_mark_all_devices_lost(vha, 1);
                }
 
                if (vha->vp_idx) {
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index f0ec13d48bf3..59cc02c946d7 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -2177,7 +2177,10 @@ qla2x00_lip_reset(scsi_qla_host_t *vha)
                mcp->out_mb = MBX_2|MBX_1|MBX_0;
        } else if (IS_FWI2_CAPABLE(vha->hw)) {
                mcp->mb[0] = MBC_LIP_FULL_LOGIN;
-               mcp->mb[1] = BIT_6;
+               if (N2N_TOPO(vha->hw))
+                       mcp->mb[1] = BIT_4; /* re-init */
+               else
+                       mcp->mb[1] = BIT_6; /* LIP */
                mcp->mb[2] = 0;
                mcp->mb[3] = vha->hw->loop_reset_delay;
                mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
@@ -3911,28 +3914,6 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
                if (fcport) {
                        fcport->plogi_nack_done_deadline = jiffies + HZ;
                        fcport->scan_state = QLA_FCPORT_FOUND;
-                       switch (fcport->disc_state) {
-                       case DSC_DELETED:
-                               ql_dbg(ql_dbg_disc, vha, 0x210d,
-                                   "%s %d %8phC login\n",
-                                   __func__, __LINE__, fcport->port_name);
-                               qla24xx_fcport_handle_login(vha, fcport);
-                               break;
-                       case DSC_DELETE_PEND:
-                               break;
-                       default:
-                               qlt_schedule_sess_for_deletion(fcport);
-                               break;
-                       }
-               } else {
-                       id.b.al_pa  = rptid_entry->u.f2.remote_nport_id[0];
-                       id.b.area   = rptid_entry->u.f2.remote_nport_id[1];
-                       id.b.domain = rptid_entry->u.f2.remote_nport_id[2];
-                       qla24xx_post_newsess_work(vha, &id,
-                           rptid_entry->u.f2.port_name,
-                           rptid_entry->u.f2.node_name,
-                           NULL,
-                           FC4_TYPE_UNKNOWN);
                }
        }
 }
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 1fbd16c8c9a7..d42ad3a1f9ef 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -6179,6 +6179,11 @@ qla2x00_do_dpc(void *data)
                if (!IS_QLAFX00(ha))
                        qla2x00_do_dpc_all_vps(base_vha);
 
+               if (test_and_clear_bit(N2N_LINK_RESET,
+                       &base_vha->dpc_flags)) {
+                       qla2x00_lip_reset(base_vha);
+               }
+
                ha->dpc_active = 0;
 end_loop:
                set_current_state(TASK_INTERRUPTIBLE);
diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index 9952e51f2e90..5fad046f8a93 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -805,6 +805,10 @@ qlt_plogi_ack_find_add(struct scsi_qla_host *vha, 
port_id_t *id,
 
        list_for_each_entry(pla, &vha->plogi_ack_list, list) {
                if (pla->id.b24 == id->b24) {
+                       ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x210d,
+                           "%s %d %8phC Term INOT due to new INOT",
+                           __func__, __LINE__,
+                           pla->iocb.u.isp24.port_name);
                        qlt_send_term_imm_notif(vha, &pla->iocb, 1);
                        memcpy(&pla->iocb, iocb, sizeof(pla->iocb));
                        return pla;
@@ -1073,6 +1077,7 @@ void qlt_free_session_done(struct work_struct *work)
                struct qlt_plogi_ack_t *con =
                    sess->plogi_link[QLT_PLOGI_LINK_CONFLICT];
                struct imm_ntfy_from_isp *iocb;
+               own = sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN];
 
                if (con) {
                        iocb = &con->iocb;
@@ -4715,6 +4720,10 @@ static int qlt_handle_login(struct scsi_qla_host *vha,
 
        pla = qlt_plogi_ack_find_add(vha, &port_id, iocb);
        if (!pla) {
+               ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff,
+                   "%s %d %8phC Term INOT due to mem alloc fail",
+                   __func__, __LINE__,
+                   iocb->u.isp24.port_name);
                qlt_send_term_imm_notif(vha, iocb, 1);
                goto out;
        }
-- 
2.12.0

Reply via email to