Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: lpfc: Fix lpfc_name struct packing

clang points out that the lpfc_name structure has an 8-byte alignment
requirement on most architectures, but is embedded in a number of other
structures that are forced to be only 1-byte aligned:

drivers/scsi/lpfc/lpfc_hw.h:1516:30: error: field pe within 'struct lpfc_fdmi_reg_port_list' is less aligned than 'struct lpfc_fdmi_port_entry' and is usually due to 'struct lpfc_fdmi_reg_port_list' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access]
struct lpfc_fdmi_port_entry pe;
drivers/scsi/lpfc/lpfc_hw.h:850:19: error: field portName within 'struct _ADISC' is less aligned than 'struct lpfc_name' and is usually due to 'struct _ADISC' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access]
drivers/scsi/lpfc/lpfc_hw.h:851:19: error: field nodeName within 'struct _ADISC' is less aligned than 'struct lpfc_name' and is usually due to 'struct _ADISC' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access]
drivers/scsi/lpfc/lpfc_hw.h:922:19: error: field portName within 'struct _RNID' is less aligned than 'struct lpfc_name' and is usually due to 'struct _RNID' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access]
drivers/scsi/lpfc/lpfc_hw.h:923:19: error: field nodeName within 'struct _RNID' is less aligned than 'struct lpfc_name' and is usually due to 'struct _RNID' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access]

From the git history, I can see that all the __packed annotations were done
specifically to avoid introducing implicit padding around the lpfc_name
instances, though this was probably the wrong approach.

To improve this, only annotate the one uint64_t field inside of lpfc_name
as packed, with an explicit 4-byte alignment, as is the default already on
the 32-bit x86 ABI but not on most others. With this, the other __packed
annotations can be removed again, as this avoids the incorrect padding.

Two other structures change their layout as a result of this change:

- struct _LOGO never gained a __packed annotation even though it has the
same alignment problem as the others but is not used anywhere in the
driver today.

- struct serv_param similarly has this issue, and it is used, my guess is
that this is only an internal structure rather than part of a binary
interface, so the padding has no negative effect here.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Link: https://lore.kernel.org/r/20230616090705.2623408-1-arnd@kernel.org
Reviewed-by: Justin Tee <justin.tee@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Arnd Bergmann and committed by
Martin K. Petersen
00c2cae6 af92c02f

+5 -5
+5 -5
drivers/scsi/lpfc/lpfc_hw.h
··· 365 365 uint8_t IEEE[6]; /* FC IEEE address */ 366 366 } s; 367 367 uint8_t wwn[8]; 368 - uint64_t name; 368 + uint64_t name __packed __aligned(4); 369 369 } u; 370 370 }; 371 371 ··· 850 850 struct lpfc_name portName; 851 851 struct lpfc_name nodeName; 852 852 uint32_t DID; 853 - } __packed ADISC; 853 + } ADISC; 854 854 855 855 typedef struct _FARP { /* Structure is in Big Endian format */ 856 856 uint32_t Mflags:8; ··· 880 880 uint32_t Fdid; 881 881 struct lpfc_name FportName; 882 882 struct lpfc_name FnodeName; 883 - } __packed FAN; 883 + } FAN; 884 884 885 885 typedef struct _SCR { /* Structure is in Big Endian format */ 886 886 uint8_t resvd1; ··· 924 924 union { 925 925 RNID_TOP_DISC topologyDisc; /* topology disc (0xdf) */ 926 926 } un; 927 - } __packed RNID; 927 + } RNID; 928 928 929 929 struct RLS { /* Structure is in Big Endian format */ 930 930 uint32_t rls; ··· 1514 1514 struct lpfc_fdmi_reg_port_list { 1515 1515 __be32 EntryCnt; 1516 1516 struct lpfc_fdmi_port_entry pe; 1517 - } __packed; 1517 + }; 1518 1518 1519 1519 /* 1520 1520 * Register HBA(RHBA)