scsi: qla2xxx: Fix losing target when it reappears during delete
authorArun Easi <aeasi@marvell.com>
Thu, 16 Jun 2022 05:35:04 +0000 (22:35 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 Aug 2022 12:24:18 +0000 (14:24 +0200)
commit 118b0c863c8f5629cc5271fc24d72d926e0715d9 upstream.

FC target disappeared during port perturbation tests due to a race that
tramples target state.  Fix the issue by adding state checks before
proceeding.

Link: https://lore.kernel.org/r/20220616053508.27186-8-njavali@marvell.com
Fixes: 44c57f205876 ("scsi: qla2xxx: Changes to support FCP2 Target")
Cc: stable@vger.kernel.org
Signed-off-by: Arun Easi <aeasi@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/scsi/qla2xxx/qla_attr.c

index bd4ebc1b5c1e0e37ef80bda75444cfc657c77496..a302ed8b610fb3ed814068becce480f0cb175afa 100644 (file)
@@ -2705,17 +2705,24 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
        if (!fcport)
                return;
 
-       /* Now that the rport has been deleted, set the fcport state to
-          FCS_DEVICE_DEAD */
-       qla2x00_set_fcport_state(fcport, FCS_DEVICE_DEAD);
+
+       /*
+        * Now that the rport has been deleted, set the fcport state to
+        * FCS_DEVICE_DEAD, if the fcport is still lost.
+        */
+       if (fcport->scan_state != QLA_FCPORT_FOUND)
+               qla2x00_set_fcport_state(fcport, FCS_DEVICE_DEAD);
 
        /*
         * Transport has effectively 'deleted' the rport, clear
         * all local references.
         */
        spin_lock_irqsave(host->host_lock, flags);
-       fcport->rport = fcport->drport = NULL;
-       *((fc_port_t **)rport->dd_data) = NULL;
+       /* Confirm port has not reappeared before clearing pointers. */
+       if (rport->port_state != FC_PORTSTATE_ONLINE) {
+               fcport->rport = fcport->drport = NULL;
+               *((fc_port_t **)rport->dd_data) = NULL;
+       }
        spin_unlock_irqrestore(host->host_lock, flags);
 
        if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags))
@@ -2748,9 +2755,12 @@ qla2x00_terminate_rport_io(struct fc_rport *rport)
        /*
         * At this point all fcport's software-states are cleared.  Perform any
         * final cleanup of firmware resources (PCBs and XCBs).
+        *
+        * Attempt to cleanup only lost devices.
         */
        if (fcport->loop_id != FC_NO_LOOP_ID) {
-               if (IS_FWI2_CAPABLE(fcport->vha->hw)) {
+               if (IS_FWI2_CAPABLE(fcport->vha->hw) &&
+                   fcport->scan_state != QLA_FCPORT_FOUND) {
                        if (fcport->loop_id != FC_NO_LOOP_ID)
                                fcport->logout_on_delete = 1;
 
@@ -2760,7 +2770,7 @@ qla2x00_terminate_rport_io(struct fc_rport *rport)
                                       __LINE__);
                                qlt_schedule_sess_for_deletion(fcport);
                        }
-               } else {
+               } else if (!IS_FWI2_CAPABLE(fcport->vha->hw)) {
                        qla2x00_port_logout(fcport->vha, fcport);
                }
        }