scsi: lpfc: Fix removal of SCSI transport device get and put on dev structure
authorJames Smart <james.smart@broadcom.com>
Sun, 15 Nov 2020 19:26:32 +0000 (11:26 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 17 Nov 2020 05:43:54 +0000 (00:43 -0500)
The lpfc driver is calling get_device and put_device on scsi_fc_transport
device structure. When this code was removed, the driver triggered an oops
in "scsi_is_host_dev" when the first SCSI target was unregistered from the
transport.

The reason the calls were necessary is that the driver is calling
scsi_remove_host too early, before the target rports are unregistered and
the scsi devices disconnected from the scsi_host.  The fc_host was torn
down during fc_remove_host.

Fix by moving the lpfc_pci_remove_one_s3/s4 calls to scsi_remove_host to
after the nodes are cleaned up.  Remove the get_device and put_device calls
and the supporting code.

Link: https://lore.kernel.org/r/20201115192646.12977-4-james.smart@broadcom.com
Co-developed-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <james.smart@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_vport.c

index 44e99e7..c778e48 100644 (file)
@@ -1601,7 +1601,6 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
        u32 keep_nlp_fc4_type = 0;
        struct lpfc_nvme_rport *keep_nrport = NULL;
        int  put_node;
-       int  put_rport;
        unsigned long *active_rrqs_xri_bitmap = NULL;
 
        /* Fabric nodes can have the same WWPN so we don't bother searching
@@ -1804,13 +1803,10 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
                if (rport) {
                        rdata = rport->dd_data;
                        put_node = rdata->pnode != NULL;
-                       put_rport = ndlp->rport != NULL;
                        rdata->pnode = NULL;
                        ndlp->rport = NULL;
                        if (put_node)
                                lpfc_nlp_put(ndlp);
-                       if (put_rport)
-                               put_device(&rport->dev);
                }
        }
 
index 9d387fb..71ef50c 100644 (file)
@@ -117,7 +117,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
        struct lpfc_hba   *phba;
        struct lpfc_work_evt *evtp;
        int  put_node;
-       int  put_rport;
        unsigned long iflags;
 
        rdata = rport->dd_data;
@@ -142,13 +141,10 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
         */
        if (vport->load_flag & FC_UNLOADING) {
                put_node = rdata->pnode != NULL;
-               put_rport = ndlp->rport != NULL;
                rdata->pnode = NULL;
                ndlp->rport = NULL;
                if (put_node)
                        lpfc_nlp_put(ndlp);
-               if (put_rport)
-                       put_device(&rport->dev);
                return;
        }
 
@@ -263,7 +259,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
                ndlp->rport = NULL;
                if (put_node)
                        lpfc_nlp_put(ndlp);
-               put_device(&rport->dev);
 
                return fcf_inuse;
        }
@@ -284,7 +279,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
        ndlp->rport = NULL;
        if (put_node)
                lpfc_nlp_put(ndlp);
-       put_device(&rport->dev);
 
        if (ndlp->nlp_type & NLP_FABRIC)
                return fcf_inuse;
@@ -4190,8 +4184,6 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
                                lpfc_nlp_put(ndlp);
                        rdata->pnode = NULL;
                }
-               /* drop reference for earlier registeration */
-               put_device(&rport->dev);
        }
 
        lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
@@ -4203,7 +4195,7 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
                return;
 
        ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids);
-       if (!rport || !get_device(&rport->dev)) {
+       if (!rport) {
                dev_printk(KERN_WARNING, &phba->pcidev->dev,
                           "Warning: fc_remote_port_add failed\n");
                return;
@@ -4244,6 +4236,7 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
            (rport->scsi_target_id < LPFC_MAX_TARGET)) {
                ndlp->nlp_sid = rport->scsi_target_id;
        }
+
        return;
 }
 
@@ -5217,7 +5210,6 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
                rdata = rport->dd_data;
                rdata->pnode = NULL;
                ndlp->rport = NULL;
-               put_device(&rport->dev);
        }
 }
 
index add2eb0..7244828 100644 (file)
@@ -12499,12 +12499,15 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
                }
        lpfc_destroy_vport_work_array(phba, vports);
 
-       /* Remove FC host and then SCSI host with the physical port */
+       /* Remove FC host with the physical port */
        fc_remove_host(shost);
-       scsi_remove_host(shost);
 
+       /* Clean up all nodes, mailboxes and IOs. */
        lpfc_cleanup(vport);
 
+       /* Remove the shost now that the devices connections are lost. */
+       scsi_remove_host(shost);
+
        /*
         * Bring down the SLI Layer. This step disable all interrupts,
         * clears the rings, discards all mailbox commands, and resets
@@ -13342,7 +13345,6 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
        vport->load_flag |= FC_UNLOADING;
        spin_unlock_irq(&phba->hbalock);
 
-       /* Free the HBA sysfs attributes */
        lpfc_free_sysfs_attr(vport);
 
        /* Release all the vports against this physical port */
@@ -13355,9 +13357,8 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
                }
        lpfc_destroy_vport_work_array(phba, vports);
 
-       /* Remove FC host and then SCSI host with the physical port */
+       /* Remove FC host with the physical port */
        fc_remove_host(shost);
-       scsi_remove_host(shost);
 
        /* Perform ndlp cleanup on the physical port.  The nvme and nvmet
         * localports are destroyed after to cleanup all transport memory.
@@ -13370,6 +13371,9 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
        if (phba->cfg_xri_rebalancing)
                lpfc_destroy_multixri_pools(phba);
 
+       /* Remove the shost now that the devices connections are lost. */
+       scsi_remove_host(shost);
+
        /*
         * Bring down the SLI Layer. This step disables all interrupts,
         * clears the rings, discards all mailbox commands, and resets
index 6ab7813..0261495 100644 (file)
@@ -664,9 +664,8 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
                ns_ndlp_referenced = true;
        }
 
-       /* Remove FC host and then SCSI host with the vport */
+       /* Remove FC host to break driver binding. */
        fc_remove_host(shost);
-       scsi_remove_host(shost);
 
        ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
 
@@ -747,6 +746,9 @@ skip_logo:
        }
 
        lpfc_cleanup(vport);
+
+       /* Remove scsi host now.  The nodes are cleaned up. */
+       scsi_remove_host(shost);
        lpfc_sli_host_down(vport);
 
        lpfc_stop_vport_timers(vport);