Merge tag 'md-3.10-fixes' of git://neil.brown.name/md
[firefly-linux-kernel-4.4.55.git] / drivers / scsi / lpfc / lpfc_vport.c
index 0fe188e66000da063c01feec76b557a075545258..e28e431564b08f5b90693c3dc49c5d218e67a262 100644 (file)
@@ -80,7 +80,7 @@ inline void lpfc_vport_set_state(struct lpfc_vport *vport,
        }
 }
 
-static int
+int
 lpfc_alloc_vpi(struct lpfc_hba *phba)
 {
        unsigned long vpi;
@@ -568,6 +568,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
        struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
        struct lpfc_hba   *phba = vport->phba;
        long timeout;
+       bool ns_ndlp_referenced = false;
 
        if (vport->port_type == LPFC_PHYSICAL_PORT) {
                lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
@@ -628,6 +629,18 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
 
        lpfc_debugfs_terminate(vport);
 
+       /*
+        * The call to fc_remove_host might release the NameServer ndlp. Since
+        * we might need to use the ndlp to send the DA_ID CT command,
+        * increment the reference for the NameServer ndlp to prevent it from
+        * being released.
+        */
+       ndlp = lpfc_findnode_did(vport, NameServer_DID);
+       if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
+               lpfc_nlp_get(ndlp);
+               ns_ndlp_referenced = true;
+       }
+
        /* Remove FC host and then SCSI host with the vport */
        fc_remove_host(lpfc_shost_from_vport(vport));
        scsi_remove_host(lpfc_shost_from_vport(vport));
@@ -734,6 +747,16 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
                lpfc_discovery_wait(vport);
 
 skip_logo:
+
+       /*
+        * If the NameServer ndlp has been incremented to allow the DA_ID CT
+        * command to be sent, decrement the ndlp now.
+        */
+       if (ns_ndlp_referenced) {
+               ndlp = lpfc_findnode_did(vport, NameServer_DID);
+               lpfc_nlp_put(ndlp);
+       }
+
        lpfc_cleanup(vport);
        lpfc_sli_host_down(vport);