Commit c3752f44 authored by Damien Le Moal's avatar Damien Le Moal Committed by Martin K. Petersen

scsi: libsas: Introduce struct smp_disc_resp

When compiling with gcc 12, several warnings are thrown by gcc when
compiling drivers/scsi/libsas/sas_expander.c, e.g.:

In function ‘sas_get_phy_change_count’,
    inlined from ‘sas_find_bcast_phy.constprop’ at
drivers/scsi/libsas/sas_expander.c:1737:9:
drivers/scsi/libsas/sas_expander.c:1697:39: warning: array subscript
‘struct smp_resp[0]’ is partly outside array bounds of ‘unsigned
char[56]’ [-Warray-bounds]
 1697 |                 *pcc = disc_resp->disc.change_count;
      |                        ~~~~~~~~~~~~~~~^~~~~~~~~~~~~

This is due to the use of the struct smp_resp to aggregate all possible
response types using a union but allocating a response buffer with a size
exactly equal to the size of the response type needed. This leads to access
to fields of struct smp_resp from an allocated memory area that is smaller
than the size of struct smp_resp.

Fix this by defining struct smp_disc_resp for sas discovery operations.
Since this structure and the generic struct smp_resp are identical for
the little endian and big endian archs, move the definition of these
structures at the end of include/scsi/sas.h to avoid repeating their
definition.

Link: https://lore.kernel.org/r/20220609022456.409087-2-damien.lemoal@opensource.wdc.comReviewed-by: default avatarJohn Garry <john.garry@huawei.com>
Signed-off-by: default avatarDamien Le Moal <damien.lemoal@opensource.wdc.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 0f4d7d55
...@@ -175,13 +175,13 @@ static enum sas_device_type to_dev_type(struct discover_resp *dr) ...@@ -175,13 +175,13 @@ static enum sas_device_type to_dev_type(struct discover_resp *dr)
return dr->attached_dev_type; return dr->attached_dev_type;
} }
static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
struct smp_disc_resp *disc_resp)
{ {
enum sas_device_type dev_type; enum sas_device_type dev_type;
enum sas_linkrate linkrate; enum sas_linkrate linkrate;
u8 sas_addr[SAS_ADDR_SIZE]; u8 sas_addr[SAS_ADDR_SIZE];
struct smp_resp *resp = rsp; struct discover_resp *dr = &disc_resp->disc;
struct discover_resp *dr = &resp->disc;
struct sas_ha_struct *ha = dev->port->ha; struct sas_ha_struct *ha = dev->port->ha;
struct expander_device *ex = &dev->ex_dev; struct expander_device *ex = &dev->ex_dev;
struct ex_phy *phy = &ex->ex_phy[phy_id]; struct ex_phy *phy = &ex->ex_phy[phy_id];
...@@ -198,7 +198,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) ...@@ -198,7 +198,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)
BUG_ON(!phy->phy); BUG_ON(!phy->phy);
} }
switch (resp->result) { switch (disc_resp->result) {
case SMP_RESP_PHY_VACANT: case SMP_RESP_PHY_VACANT:
phy->phy_state = PHY_VACANT; phy->phy_state = PHY_VACANT;
break; break;
...@@ -347,12 +347,13 @@ struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id) ...@@ -347,12 +347,13 @@ struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id)
} }
#define DISCOVER_REQ_SIZE 16 #define DISCOVER_REQ_SIZE 16
#define DISCOVER_RESP_SIZE 56 #define DISCOVER_RESP_SIZE sizeof(struct smp_disc_resp)
static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
u8 *disc_resp, int single) struct smp_disc_resp *disc_resp,
int single)
{ {
struct discover_resp *dr; struct discover_resp *dr = &disc_resp->disc;
int res; int res;
disc_req[9] = single; disc_req[9] = single;
...@@ -361,7 +362,6 @@ static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, ...@@ -361,7 +362,6 @@ static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
disc_resp, DISCOVER_RESP_SIZE); disc_resp, DISCOVER_RESP_SIZE);
if (res) if (res)
return res; return res;
dr = &((struct smp_resp *)disc_resp)->disc;
if (memcmp(dev->sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE) == 0) { if (memcmp(dev->sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE) == 0) {
pr_notice("Found loopback topology, just ignore it!\n"); pr_notice("Found loopback topology, just ignore it!\n");
return 0; return 0;
...@@ -375,7 +375,7 @@ int sas_ex_phy_discover(struct domain_device *dev, int single) ...@@ -375,7 +375,7 @@ int sas_ex_phy_discover(struct domain_device *dev, int single)
struct expander_device *ex = &dev->ex_dev; struct expander_device *ex = &dev->ex_dev;
int res = 0; int res = 0;
u8 *disc_req; u8 *disc_req;
u8 *disc_resp; struct smp_disc_resp *disc_resp;
disc_req = alloc_smp_req(DISCOVER_REQ_SIZE); disc_req = alloc_smp_req(DISCOVER_REQ_SIZE);
if (!disc_req) if (!disc_req)
...@@ -1657,7 +1657,7 @@ int sas_discover_root_expander(struct domain_device *dev) ...@@ -1657,7 +1657,7 @@ int sas_discover_root_expander(struct domain_device *dev)
/* ---------- Domain revalidation ---------- */ /* ---------- Domain revalidation ---------- */
static int sas_get_phy_discover(struct domain_device *dev, static int sas_get_phy_discover(struct domain_device *dev,
int phy_id, struct smp_resp *disc_resp) int phy_id, struct smp_disc_resp *disc_resp)
{ {
int res; int res;
u8 *disc_req; u8 *disc_req;
...@@ -1673,10 +1673,8 @@ static int sas_get_phy_discover(struct domain_device *dev, ...@@ -1673,10 +1673,8 @@ static int sas_get_phy_discover(struct domain_device *dev,
disc_resp, DISCOVER_RESP_SIZE); disc_resp, DISCOVER_RESP_SIZE);
if (res) if (res)
goto out; goto out;
else if (disc_resp->result != SMP_RESP_FUNC_ACC) { if (disc_resp->result != SMP_RESP_FUNC_ACC)
res = disc_resp->result; res = disc_resp->result;
goto out;
}
out: out:
kfree(disc_req); kfree(disc_req);
return res; return res;
...@@ -1686,7 +1684,7 @@ static int sas_get_phy_change_count(struct domain_device *dev, ...@@ -1686,7 +1684,7 @@ static int sas_get_phy_change_count(struct domain_device *dev,
int phy_id, int *pcc) int phy_id, int *pcc)
{ {
int res; int res;
struct smp_resp *disc_resp; struct smp_disc_resp *disc_resp;
disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE); disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
if (!disc_resp) if (!disc_resp)
...@@ -1704,19 +1702,17 @@ static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id, ...@@ -1704,19 +1702,17 @@ static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id,
u8 *sas_addr, enum sas_device_type *type) u8 *sas_addr, enum sas_device_type *type)
{ {
int res; int res;
struct smp_resp *disc_resp; struct smp_disc_resp *disc_resp;
struct discover_resp *dr;
disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE); disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
if (!disc_resp) if (!disc_resp)
return -ENOMEM; return -ENOMEM;
dr = &disc_resp->disc;
res = sas_get_phy_discover(dev, phy_id, disc_resp); res = sas_get_phy_discover(dev, phy_id, disc_resp);
if (res == 0) { if (res == 0) {
memcpy(sas_addr, disc_resp->disc.attached_sas_addr, memcpy(sas_addr, disc_resp->disc.attached_sas_addr,
SAS_ADDR_SIZE); SAS_ADDR_SIZE);
*type = to_dev_type(dr); *type = to_dev_type(&disc_resp->disc);
if (*type == 0) if (*type == 0)
memset(sas_addr, 0, SAS_ADDR_SIZE); memset(sas_addr, 0, SAS_ADDR_SIZE);
} }
......
...@@ -471,18 +471,6 @@ struct report_phy_sata_resp { ...@@ -471,18 +471,6 @@ struct report_phy_sata_resp {
__be32 crc; __be32 crc;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct smp_resp {
u8 frame_type;
u8 function;
u8 result;
u8 reserved;
union {
struct report_general_resp rg;
struct discover_resp disc;
struct report_phy_sata_resp rps;
};
} __attribute__ ((packed));
#elif defined(__BIG_ENDIAN_BITFIELD) #elif defined(__BIG_ENDIAN_BITFIELD)
struct sas_identify_frame { struct sas_identify_frame {
/* Byte 0 */ /* Byte 0 */
...@@ -704,6 +692,18 @@ struct report_phy_sata_resp { ...@@ -704,6 +692,18 @@ struct report_phy_sata_resp {
__be32 crc; __be32 crc;
} __attribute__ ((packed)); } __attribute__ ((packed));
#else
#error "Bitfield order not defined!"
#endif
struct smp_disc_resp {
u8 frame_type;
u8 function;
u8 result;
u8 reserved;
struct discover_resp disc;
} __attribute__ ((packed));
struct smp_resp { struct smp_resp {
u8 frame_type; u8 frame_type;
u8 function; u8 function;
...@@ -716,8 +716,4 @@ struct smp_resp { ...@@ -716,8 +716,4 @@ struct smp_resp {
}; };
} __attribute__ ((packed)); } __attribute__ ((packed));
#else
#error "Bitfield order not defined!"
#endif
#endif /* _SAS_H_ */ #endif /* _SAS_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment