| From 396d3f5aac302a29a016422ba150c0329b676329 Mon Sep 17 00:00:00 2001 |
| From: James Smart <jsmart2021@gmail.com> |
| Date: Wed, 18 Dec 2019 15:58:02 -0800 |
| Subject: [PATCH] scsi: lpfc: Fix Fabric hostname registration if system |
| hostname changes |
| |
| commit e3ba04c9bad1d1c7f15df43da25e878045150777 upstream. |
| |
| 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> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h |
| index 6ecf4c2db174..fe1221c6ee4b 100644 |
| --- a/drivers/scsi/lpfc/lpfc.h |
| +++ b/drivers/scsi/lpfc/lpfc.h |
| @@ -1211,6 +1211,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 * |
| diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h |
| index f2074221354e..9892236ded14 100644 |
| --- a/drivers/scsi/lpfc/lpfc_crtn.h |
| +++ b/drivers/scsi/lpfc/lpfc_crtn.h |
| @@ -179,7 +179,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 *); |
| |
| diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c |
| index fe2565999527..6bc53d01d49e 100644 |
| --- a/drivers/scsi/lpfc/lpfc_ct.c |
| +++ b/drivers/scsi/lpfc/lpfc_ct.c |
| @@ -1457,7 +1457,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; |
| |
| @@ -1940,14 +1940,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; |
| @@ -1960,17 +1962,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); |
| @@ -2553,8 +2579,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; |
| diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c |
| index 3170f38e800c..e417a834f878 100644 |
| --- a/drivers/scsi/lpfc/lpfc_hbadisc.c |
| +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c |
| @@ -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> |
| @@ -3314,6 +3315,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); |
| diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c |
| index edac0fcf2d1f..2af227f31c20 100644 |
| --- a/drivers/scsi/lpfc/lpfc_init.c |
| +++ b/drivers/scsi/lpfc/lpfc_init.c |
| @@ -1381,7 +1381,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); |
| |
| -- |
| 2.7.4 |
| |