scsi: qla2xxx: Fix N2N link re-connect
In case of N2N connect, sg_reset 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.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
4ae5716b41
commit
48acad0990
@ -377,6 +377,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;
|
||||
@ -4236,7 +4237,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
|
||||
|
@ -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,16 +518,19 @@ 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);
|
||||
|
||||
if (memcmp((u8 *)&wwn, fcport->port_name, WWN_SIZE))
|
||||
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;
|
||||
|
||||
if (memcmp((u8 *)&wwn, fcport->port_name, WWN_SIZE))
|
||||
continue;
|
||||
|
||||
if (IS_SW_RESV_ADDR(id))
|
||||
continue;
|
||||
|
||||
found = 1;
|
||||
|
||||
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,66 +572,122 @@ 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);
|
||||
|
||||
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:
|
||||
switch (vha->hw->current_topology) {
|
||||
default:
|
||||
if (fcport->loop_id == FC_NO_LOOP_ID) {
|
||||
qla2x00_find_new_loop_id(vha, fcport);
|
||||
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;
|
||||
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);
|
||||
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, vha, 0x20e6,
|
||||
"%s %d %8phC post del sess\n",
|
||||
__func__, __LINE__,
|
||||
conflict_fcport->port_name);
|
||||
qlt_schedule_sess_for_deletion
|
||||
(conflict_fcport);
|
||||
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, 0x20e5,
|
||||
"%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 */
|
||||
|
||||
@ -4590,20 +4674,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);
|
||||
@ -7929,8 +8003,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;
|
||||
|
@ -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;
|
||||
|
@ -908,7 +908,8 @@ skip_rio:
|
||||
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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6186,6 +6186,11 @@ intr_on_check:
|
||||
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);
|
||||
|
@ -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;
|
||||
@ -4716,6 +4721,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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user