]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
scsi: hisi_sas: Fix I/O errors caused by hardware port ID changes
authorXingui Yang <yangxingui@huawei.com>
Wed, 12 Mar 2025 09:51:35 +0000 (17:51 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 21 Mar 2025 00:46:31 +0000 (20:46 -0400)
The hw port ID of phy may change when inserting disks in batches, causing
the port ID in hisi_sas_port and itct to be inconsistent with the hardware,
resulting in I/O errors. The solution is to set the device state to gone to
intercept I/O sent to the device, and then execute linkreset to discard and
find the disk to re-update its information.

Signed-off-by: Xingui Yang <yangxingui@huawei.com>
Link: https://lore.kernel.org/r/20250312095135.3048379-3-yangxingui@huawei.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/hisi_sas/hisi_sas_main.c

index 3596414d970b24a07c42154454957259032dc618..7a484ad0f9abe6fe1e4b471b2eb0f960e2b9b02a 100644 (file)
@@ -935,8 +935,28 @@ static void hisi_sas_phyup_work_common(struct work_struct *work,
                container_of(work, typeof(*phy), works[event]);
        struct hisi_hba *hisi_hba = phy->hisi_hba;
        struct asd_sas_phy *sas_phy = &phy->sas_phy;
+       struct asd_sas_port *sas_port = sas_phy->port;
+       struct hisi_sas_port *port = phy->port;
+       struct device *dev = hisi_hba->dev;
+       struct domain_device *port_dev;
        int phy_no = sas_phy->id;
 
+       if (!test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags) &&
+           sas_port && port && (port->id != phy->port_id)) {
+               dev_info(dev, "phy%d's hw port id changed from %d to %llu\n",
+                               phy_no, port->id, phy->port_id);
+               port_dev = sas_port->port_dev;
+               if (port_dev && !dev_is_expander(port_dev->dev_type)) {
+                       /*
+                        * Set the device state to gone to block
+                        * sending IO to the device.
+                        */
+                       set_bit(SAS_DEV_GONE, &port_dev->state);
+                       hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET);
+                       return;
+               }
+       }
+
        phy->wait_phyup_cnt = 0;
        if (phy->identify.target_port_protocols == SAS_PROTOCOL_SSP)
                hisi_hba->hw->sl_notify_ssp(hisi_hba, phy_no);