scsi: lpfc: Fix Fabric hostname registration if system hostname changes
authorJames Smart <jsmart2021@gmail.com>
Wed, 18 Dec 2019 23:58:02 +0000 (15:58 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sat, 21 Dec 2019 18:42:42 +0000 (13:42 -0500)
There are reports of multiple ports on the same system displaying different
hostnames in fabric FDMI displays.

Currently, the driver registers the hostname at initialization and obtains
the hostname via init_utsname()->nodename queried at the time the FC link
comes up. Unfortunately, if the machine hostname is updated after
initialization, such as via DHCP or admin command, the value registered
initially will be incorrect.

Fix by having the driver save the hostname that was registered with FDMI.
The driver then runs a heartbeat action that will check the hostname.  If
the name changes, reregister the FMDI data.

The hostname is used in RSNN_NN, FDMI RPA and FDMI RHBA.

Link: https://lore.kernel.org/r/20191218235808.31922-5-jsmart2021@gmail.com
Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_init.c

index 935f988..04d73e2 100644 (file)
@@ -1223,6 +1223,8 @@ struct lpfc_hba {
 #define LPFC_POLL_HB   1               /* slowpath heartbeat */
 #define LPFC_POLL_FASTPATH     0       /* called from fastpath */
 #define LPFC_POLL_SLOWPATH     1       /* called from slowpath */
+
+       char os_host_name[MAXHOSTNAMELEN];
 };
 
 static inline struct Scsi_Host *
index ee353c8..25d3dd3 100644 (file)
@@ -180,7 +180,7 @@ int lpfc_issue_gidft(struct lpfc_vport *vport);
 int lpfc_get_gidft_type(struct lpfc_vport *vport, struct lpfc_iocbq *iocbq);
 int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
 int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int, uint32_t);
-void lpfc_fdmi_num_disc_check(struct lpfc_vport *);
+void lpfc_fdmi_change_check(struct lpfc_vport *vport);
 void lpfc_delayed_disc_tmo(struct timer_list *);
 void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *);
 
index 1b4dbb2..58b35a1 100644 (file)
@@ -1511,7 +1511,7 @@ lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
        if (strlcat(symbol, tmp, size) >= size)
                goto buffer_done;
 
-       scnprintf(tmp, sizeof(tmp), " HN:%s", init_utsname()->nodename);
+       scnprintf(tmp, sizeof(tmp), " HN:%s", vport->phba->os_host_name);
        if (strlcat(symbol, tmp, size) >= size)
                goto buffer_done;
 
@@ -2000,14 +2000,16 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
 
 /**
- * lpfc_fdmi_num_disc_check - Check how many mapped NPorts we are connected to
+ * lpfc_fdmi_change_check - Check for changed FDMI parameters
  * @vport: pointer to a host virtual N_Port data structure.
  *
- * Called from hbeat timeout routine to check if the number of discovered
- * ports has changed. If so, re-register thar port Attribute.
+ * Check how many mapped NPorts we are connected to
+ * Check if our hostname changed
+ * Called from hbeat timeout routine to check if any FDMI parameters
+ * changed. If so, re-register those Attributes.
  */
 void
-lpfc_fdmi_num_disc_check(struct lpfc_vport *vport)
+lpfc_fdmi_change_check(struct lpfc_vport *vport)
 {
        struct lpfc_hba *phba = vport->phba;
        struct lpfc_nodelist *ndlp;
@@ -2020,17 +2022,41 @@ lpfc_fdmi_num_disc_check(struct lpfc_vport *vport)
        if (!(vport->fc_flag & FC_FABRIC))
                return;
 
+       ndlp = lpfc_findnode_did(vport, FDMI_DID);
+       if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
+               return;
+
+       /* Check if system hostname changed */
+       if (strcmp(phba->os_host_name, init_utsname()->nodename)) {
+               memset(phba->os_host_name, 0, sizeof(phba->os_host_name));
+               scnprintf(phba->os_host_name, sizeof(phba->os_host_name), "%s",
+                         init_utsname()->nodename);
+               lpfc_ns_cmd(vport, SLI_CTNS_RSNN_NN, 0, 0);
+
+               /* Since this effects multiple HBA and PORT attributes, we need
+                * de-register and go thru the whole FDMI registration cycle.
+                * DHBA -> DPRT -> RHBA -> RPA  (physical port)
+                * DPRT -> RPRT (vports)
+                */
+               if (vport->port_type == LPFC_PHYSICAL_PORT)
+                       lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
+               else
+                       lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
+
+               /* Since this code path registers all the port attributes
+                * we can just return without further checking.
+                */
+               return;
+       }
+
        if (!(vport->fdmi_port_mask & LPFC_FDMI_PORT_ATTR_num_disc))
                return;
 
+       /* Check if the number of mapped NPorts changed */
        cnt = lpfc_find_map_node(vport);
        if (cnt == vport->fdmi_num_disc)
                return;
 
-       ndlp = lpfc_findnode_did(vport, FDMI_DID);
-       if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
-               return;
-
        if (vport->port_type == LPFC_PHYSICAL_PORT) {
                lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA,
                              LPFC_FDMI_PORT_ATTR_num_disc);
@@ -2618,8 +2644,8 @@ lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport,
        ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
        memset(ae, 0, 256);
 
-       snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s",
-                init_utsname()->nodename);
+       scnprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s",
+                 vport->phba->os_host_name);
 
        len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
        len += (len & 3) ? (4 - (len & 3)) : 4;
index 85ada3d..dcc8999 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/kthread.h>
 #include <linux/interrupt.h>
 #include <linux/lockdep.h>
+#include <linux/utsname.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
@@ -3315,6 +3316,10 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
                lpfc_sli4_clear_fcf_rr_bmask(phba);
        }
 
+       /* Prepare for LINK up registrations */
+       memset(phba->os_host_name, 0, sizeof(phba->os_host_name));
+       scnprintf(phba->os_host_name, sizeof(phba->os_host_name), "%s",
+                 init_utsname()->nodename);
        return;
 out:
        lpfc_vport_set_state(vport, FC_VPORT_FAILED);
index 6298b17..633ca46 100644 (file)
@@ -1362,7 +1362,7 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
        if (vports != NULL)
                for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        lpfc_rcv_seq_check_edtov(vports[i]);
-                       lpfc_fdmi_num_disc_check(vports[i]);
+                       lpfc_fdmi_change_check(vports[i]);
                }
        lpfc_destroy_vport_work_array(phba, vports);