scsi: qla2xxx: Fix re-login for Nport Handle in use
authorQuinn Tran <quinn.tran@cavium.com>
Mon, 4 Dec 2017 22:45:00 +0000 (14:45 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 15 Mar 2018 09:54:25 +0000 (10:54 +0100)
commit a084fd68e1d26174c4cc1a13fbb0112f468ff7f4 upstream.

When NPort Handle is in use, driver needs to mark the handle as used and
pick another. Instead, the code clears the handle and re-pick the same
handle.

Fixes: 726b85487067d ("qla2xxx: Add framework for async fabric discovery")
Cc: <stable@vger.kernel.org> # 4.10+
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c

index ddc69d36877eaff7412236df5be2df03198aa094..8984f857bb3466da57f6c5dc451215cb19a25422 100644 (file)
@@ -2833,7 +2833,7 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea)
                                }
                        } else { /* fcport->d_id.b24 != ea->id.b24 */
                                fcport->d_id.b24 = ea->id.b24;
-                               if (fcport->deleted == QLA_SESS_DELETED) {
+                               if (fcport->deleted != QLA_SESS_DELETED) {
                                        ql_dbg(ql_dbg_disc, vha, 0x2021,
                                            "%s %d %8phC post del sess\n",
                                            __func__, __LINE__, fcport->port_name);
@@ -3206,10 +3206,16 @@ static void qla2x00_async_gpnid_sp_done(void *s, int res)
        struct event_arg ea;
        struct qla_work_evt *e;
 
-       ql_dbg(ql_dbg_disc, vha, 0x2066,
-           "Async done-%s res %x ID %3phC. %8phC\n",
-           sp->name, res, ct_req->req.port_id.port_id,
-           ct_rsp->rsp.gpn_id.port_name);
+       if (res)
+               ql_dbg(ql_dbg_disc, vha, 0x2066,
+                   "Async done-%s fail res %x ID %3phC. %8phC\n",
+                   sp->name, res, ct_req->req.port_id.port_id,
+                   ct_rsp->rsp.gpn_id.port_name);
+       else
+               ql_dbg(ql_dbg_disc, vha, 0x2066,
+                   "Async done-%s good ID %3phC. %8phC\n",
+                   sp->name, ct_req->req.port_id.port_id,
+                   ct_rsp->rsp.gpn_id.port_name);
 
        if (res) {
                sp->free(sp);
index b5b48ddca9621d82bb9b7b674b8eb9f79f083fbe..36379b8174f3d587b8c6c5ff93a762604524989e 100644 (file)
@@ -1445,6 +1445,8 @@ static void
 qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
 {
        port_id_t cid;  /* conflict Nport id */
+       u16 lid;
+       struct fc_port *conflict_fcport;
 
        switch (ea->data[0]) {
        case MBS_COMMAND_COMPLETE:
@@ -1460,8 +1462,12 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
                        qla24xx_post_prli_work(vha, ea->fcport);
                } else {
                        ql_dbg(ql_dbg_disc, vha, 0x20ea,
-                               "%s %d %8phC post gpdb\n",
-                               __func__, __LINE__, ea->fcport->port_name);
+                           "%s %d %8phC LoopID 0x%x in use with %06x. post gnl\n",
+                           __func__, __LINE__, ea->fcport->port_name,
+                           ea->fcport->loop_id, ea->fcport->d_id.b24);
+
+                       set_bit(ea->fcport->loop_id, vha->hw->loop_id_map);
+                       ea->fcport->loop_id = FC_NO_LOOP_ID;
                        ea->fcport->chip_reset = vha->hw->base_qpair->chip_reset;
                        ea->fcport->logout_on_delete = 1;
                        ea->fcport->send_els_logo = 0;
@@ -1506,8 +1512,38 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
                    ea->fcport->d_id.b.domain, ea->fcport->d_id.b.area,
                    ea->fcport->d_id.b.al_pa);
 
-               qla2x00_clear_loop_id(ea->fcport);
-               qla24xx_post_gidpn_work(vha, ea->fcport);
+               lid = ea->iop[1] & 0xffff;
+               qlt_find_sess_invalidate_other(vha,
+                   wwn_to_u64(ea->fcport->port_name),
+                   ea->fcport->d_id, lid, &conflict_fcport);
+
+               if (conflict_fcport) {
+                       /*
+                        * Another fcport share the same loop_id/nport id.
+                        * Conflict fcport needs to finish cleanup before this
+                        * fcport can proceed to login.
+                        */
+                       conflict_fcport->conflict = ea->fcport;
+                       ea->fcport->login_pause = 1;
+
+                       ql_dbg(ql_dbg_disc, vha, 0x20ed,
+                           "%s %d %8phC NPortId %06x inuse with loopid 0x%x. post gidpn\n",
+                           __func__, __LINE__, ea->fcport->port_name,
+                           ea->fcport->d_id.b24, lid);
+                       qla2x00_clear_loop_id(ea->fcport);
+                       qla24xx_post_gidpn_work(vha, ea->fcport);
+               } else {
+                       ql_dbg(ql_dbg_disc, vha, 0x20ed,
+                           "%s %d %8phC NPortId %06x inuse with loopid 0x%x. sched delete\n",
+                           __func__, __LINE__, ea->fcport->port_name,
+                           ea->fcport->d_id.b24, lid);
+
+                       qla2x00_clear_loop_id(ea->fcport);
+                       set_bit(lid, vha->hw->loop_id_map);
+                       ea->fcport->loop_id = lid;
+                       ea->fcport->keep_nport_handle = 0;
+                       qlt_schedule_sess_for_deletion(ea->fcport, false);
+               }
                break;
        }
        return;
index 9d9668aac6f6c479144a73428fac6049c5a9ac09..0d87010198849ff0634b0dd358ce3cca53ceb375 100644 (file)
@@ -2341,7 +2341,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
        int res = 0;
        uint16_t state_flags = 0;
        uint16_t retry_delay = 0;
-       uint8_t no_logout = 0;
 
        sts = (sts_entry_t *) pkt;
        sts24 = (struct sts_entry_24xx *) pkt;
@@ -2612,7 +2611,6 @@ check_scsi_status:
                break;
 
        case CS_PORT_LOGGED_OUT:
-               no_logout = 1;
        case CS_PORT_CONFIG_CHG:
        case CS_PORT_BUSY:
        case CS_INCOMPLETE:
@@ -2643,9 +2641,6 @@ check_scsi_status:
                                port_state_str[atomic_read(&fcport->state)],
                                comp_status);
 
-                       if (no_logout)
-                               fcport->logout_on_delete = 0;
-
                        qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
                        qlt_schedule_sess_for_deletion_lock(fcport);
                }