scsi: qla2xxx: Add error handling for PLOGI ELS passthrough

[ Upstream commit c76ae845ea ]

Add error handling logic to ELS Passthrough relating to NVME devices.
Current code does not parse error code to take proper recovery action,
instead it re-logins with the same login parameters that encountered the
error. Ex: nport handle collision.

Link: https://lore.kernel.org/r/20190912180918.6436-10-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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Quinn Tran 2019-09-12 11:09:13 -07:00 committed by Greg Kroah-Hartman
parent ac55936905
commit abc15be19f
1 changed files with 92 additions and 3 deletions

View File

@ -2749,6 +2749,10 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res)
struct scsi_qla_host *vha = sp->vha;
struct event_arg ea;
struct qla_work_evt *e;
struct fc_port *conflict_fcport;
port_id_t cid; /* conflict Nport id */
u32 *fw_status = sp->u.iocb_cmd.u.els_plogi.fw_status;
u16 lid;
ql_dbg(ql_dbg_disc, vha, 0x3072,
"%s ELS done rc %d hdl=%x, portid=%06x %8phC\n",
@ -2760,14 +2764,99 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res)
if (sp->flags & SRB_WAKEUP_ON_COMP)
complete(&lio->u.els_plogi.comp);
else {
if (res) {
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
} else {
switch (fw_status[0]) {
case CS_DATA_UNDERRUN:
case CS_COMPLETE:
memset(&ea, 0, sizeof(ea));
ea.fcport = fcport;
ea.data[0] = MBS_COMMAND_COMPLETE;
ea.sp = sp;
qla24xx_handle_plogi_done_event(vha, &ea);
break;
case CS_IOCB_ERROR:
switch (fw_status[1]) {
case LSC_SCODE_PORTID_USED:
lid = fw_status[2] & 0xffff;
qlt_find_sess_invalidate_other(vha,
wwn_to_u64(fcport->port_name),
fcport->d_id, lid, &conflict_fcport);
if (conflict_fcport) {
/*
* Another fcport shares the same
* loop_id & nport id; conflict
* fcport needs to finish cleanup
* before this fcport can proceed
* to login.
*/
conflict_fcport->conflict = fcport;
fcport->login_pause = 1;
ql_dbg(ql_dbg_disc, vha, 0x20ed,
"%s %d %8phC pid %06x inuse with lid %#x post gidpn\n",
__func__, __LINE__,
fcport->port_name,
fcport->d_id.b24, lid);
} else {
ql_dbg(ql_dbg_disc, vha, 0x20ed,
"%s %d %8phC pid %06x inuse with lid %#x sched del\n",
__func__, __LINE__,
fcport->port_name,
fcport->d_id.b24, lid);
qla2x00_clear_loop_id(fcport);
set_bit(lid, vha->hw->loop_id_map);
fcport->loop_id = lid;
fcport->keep_nport_handle = 0;
qlt_schedule_sess_for_deletion(fcport);
}
break;
case LSC_SCODE_NPORT_USED:
cid.b.domain = (fw_status[2] >> 16) & 0xff;
cid.b.area = (fw_status[2] >> 8) & 0xff;
cid.b.al_pa = fw_status[2] & 0xff;
cid.b.rsvd_1 = 0;
ql_dbg(ql_dbg_disc, vha, 0x20ec,
"%s %d %8phC lid %#x in use with pid %06x post gnl\n",
__func__, __LINE__, fcport->port_name,
fcport->loop_id, cid.b24);
set_bit(fcport->loop_id,
vha->hw->loop_id_map);
fcport->loop_id = FC_NO_LOOP_ID;
qla24xx_post_gnl_work(vha, fcport);
break;
case LSC_SCODE_NOXCB:
vha->hw->exch_starvation++;
if (vha->hw->exch_starvation > 5) {
ql_log(ql_log_warn, vha, 0xd046,
"Exchange starvation. Resetting RISC\n");
vha->hw->exch_starvation = 0;
set_bit(ISP_ABORT_NEEDED,
&vha->dpc_flags);
qla2xxx_wake_dpc(vha);
}
/* fall through */
default:
ql_dbg(ql_dbg_disc, vha, 0x20eb,
"%s %8phC cmd error fw_status 0x%x 0x%x 0x%x\n",
__func__, sp->fcport->port_name,
fw_status[0], fw_status[1], fw_status[2]);
fcport->flags &= ~FCF_ASYNC_SENT;
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
break;
}
break;
default:
ql_dbg(ql_dbg_disc, vha, 0x20eb,
"%s %8phC cmd error 2 fw_status 0x%x 0x%x 0x%x\n",
__func__, sp->fcport->port_name,
fw_status[0], fw_status[1], fw_status[2]);
sp->fcport->flags &= ~FCF_ASYNC_SENT;
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
break;
}
e = qla2x00_alloc_work(vha, QLA_EVT_UNMAP);