From: Quinn Tran <qut...@marvell.com>

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-login with the same login parameters
that encountered the error. Ex: nport handle collision.

Signed-off-by: Quinn Tran <qut...@marvell.com>
Signed-off-by: Himanshu Madhani <hmadh...@marvell.com>
---
 drivers/scsi/qla2xxx/qla_iocb.c | 95 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 92 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 518eb954cf42..eeb526411536 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2740,6 +2740,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",
@@ -2751,14 +2755,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);
-- 
2.12.0

Reply via email to