aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/hisi_sas/hisi_sas_main.c
diff options
context:
space:
mode:
authorXiaofei Tan <tanxiaofei@huawei.com>2019-01-25 22:22:35 +0800
committerMartin K. Petersen <martin.petersen@oracle.com>2019-01-29 01:41:20 -0500
commitb6c9b15e44090aee2a7fba646b06ff166f595b16 (patch)
tree4ba183b6c4c5dad712df4150884e31c80d0f1c51 /drivers/scsi/hisi_sas/hisi_sas_main.c
parentscsi: hisi_sas: Reject setting programmed minimum linkrate > 1.5G (diff)
downloadlinux-dev-b6c9b15e44090aee2a7fba646b06ff166f595b16.tar.xz
linux-dev-b6c9b15e44090aee2a7fba646b06ff166f595b16.zip
scsi: hisi_sas: Fix losing directly attached disk when hot-plug
Hot-plugging SAS wire of direct hard disk backplane may cause disk lost. We have done this test with several types of SATA disk from different venders, and only two models from Seagate has this problem, ST4000NM0035-1V4107 and ST3000VM002-1ET166. The root cause is that the disk doesn't send D2H frame after OOB finished. SAS controller will issue phyup interrupt only when D2H frame is received, otherwise, will be waiting there all the time. When this issue happen, we can find the disk again with link reset. To fix this issue, we setup an timer after OOB finished. If the PHY is not up in 20s, do link reset. Notes: the 20s is an experience value. Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com> Signed-off-by: John Garry <john.garry@huawei.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/hisi_sas/hisi_sas_main.c')
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index e44d2cd69de7..98ea029e5a35 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -808,6 +808,30 @@ bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
}
EXPORT_SYMBOL_GPL(hisi_sas_notify_phy_event);
+static void hisi_sas_wait_phyup_timedout(struct timer_list *t)
+{
+ struct hisi_sas_phy *phy = from_timer(phy, t, timer);
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct device *dev = hisi_hba->dev;
+ int phy_no = phy->sas_phy.id;
+
+ dev_warn(dev, "phy%d wait phyup timeout, issuing link reset\n", phy_no);
+ hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET);
+}
+
+void hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no)
+{
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct device *dev = hisi_hba->dev;
+
+ if (!timer_pending(&phy->timer)) {
+ dev_dbg(dev, "phy%d OOB ready\n", phy_no);
+ phy->timer.expires = jiffies + HISI_SAS_WAIT_PHYUP_TIMEOUT * HZ;
+ add_timer(&phy->timer);
+ }
+}
+EXPORT_SYMBOL_GPL(hisi_sas_phy_oob_ready);
+
static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
{
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
@@ -836,6 +860,8 @@ static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
INIT_WORK(&phy->works[i], hisi_sas_phye_fns[i]);
spin_lock_init(&phy->lock);
+
+ timer_setup(&phy->timer, hisi_sas_wait_phyup_timedout, 0);
}
static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)