diff mbox series

[2/2] scsi: libsas: Add sas_check_port_linkrate()

Message ID 20221020141635.2479412-3-liyihang9@huawei.com
State New
Headers show
Series Check and update the device link rate during discovery | expand

Commit Message

Yihang Li Oct. 20, 2022, 2:16 p.m. UTC
We found that in the scenario where the expander device is connected to
a wide port, a physical link connected to the wide port link down and
re-establish the link at a lower link rate, while the expander device
link rate and all expander PHY link rates maintain the original link rate,
the following error occurs:

[175712.419423] hisi_sas_v3_hw 0000:74:02.0: erroneous completion iptt=2985 task=00000000268357f1 dev id=10 exp 0x500e004aaaaaaa1f phy9 addr=500e004aaaaaaa09 CQ hdr: 0x102b 0xa0ba9 0x1000 0x20000 Error info: 0x200 0x0 0x0 0x0

After analysis, it is concluded that: when the physical link is
re-established, the link rate of the expander device and the expander PHY
are not updated. As a result, the expander PHY attached to a SATA PHY is
using link rate greater than the physical PHY link rate.

Therefore, add support for check whether the link rate of physical PHY
which is connected to the port changes after the phy up occur, if the
link rate of the newly established physical phy is lower than the link
rate of the port, a smaller link rate is transmitted to the port and
update the device link rate that needs to be updated in port->dev_list.

Signed-off-by: Yihang Li <liyihang9@huawei.com>
---
 drivers/scsi/libsas/sas_discover.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 6998560812f2..e453d94fbd30 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -164,6 +164,20 @@  static int sas_get_port_device(struct asd_sas_port *port)
 	return 0;
 }
 
+static void sas_check_port_linkrate(struct asd_sas_port *port)
+{
+	struct asd_sas_phy *phy;
+	u32 link_rate = port->linkrate;
+
+	list_for_each_entry(phy, &port->phy_list, port_phy_el)
+		link_rate = min(link_rate, phy->linkrate);
+
+	if (port->linkrate != link_rate) {
+		port->linkrate = link_rate;
+		sas_update_linkrate(port);
+	}
+}
+
 /* ---------- Discover and Revalidate ---------- */
 
 int sas_notify_lldd_dev_found(struct domain_device *dev)
@@ -435,8 +449,10 @@  static void sas_discover_domain(struct work_struct *work)
 
 	clear_bit(DISCE_DISCOVER_DOMAIN, &port->disc.pending);
 
-	if (port->port_dev)
+	if (port->port_dev) {
+		sas_check_port_linkrate(port);
 		return;
+	}
 
 	error = sas_get_port_device(port);
 	if (error)