266 lines
9.6 KiB
Diff
266 lines
9.6 KiB
Diff
From f594a4bb5169a6d2a35d273a58d2a6c657dc3f2f Mon Sep 17 00:00:00 2001
|
|
From: Xiang Chen <chenxiang66@hisilicon.com>
|
|
Date: Tue, 19 Apr 2022 17:06:52 +0800
|
|
Subject: [PATCH 083/108] scsi: hisi_sas: Wait for phyup in
|
|
hisi_sas_control_phy()
|
|
|
|
mainline inclusion
|
|
from mainline-v5.16-rc1
|
|
commit 046ab7d0f5943dd74c351e1f3a771dea785fe25d
|
|
category: feature
|
|
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8F803
|
|
|
|
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=046ab7d0f5943dd74c351e1f3a771dea785fe25d
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
When issuing a hardreset/linkreset/phy_set_linkrate from sysfs, the phy
|
|
will be disabled and re-enabled for the directly attached scenario.
|
|
|
|
It takes some time for the phy to come back up after re-enabling the phy.
|
|
If the controller becomes suspended while waiting for the phy to come back,
|
|
the phy up may be lost (along with the disk).
|
|
|
|
To solve this problem, wait for the phy up to occur with a timeout. Indeed
|
|
this is already done in hisi_sas_debug_I_T_nexus_reset() for local phys, so
|
|
just relocate the functionality to hisi_sas_control_phy().
|
|
|
|
Since the HA workqueue is drained when suspending the controller, and the
|
|
phy control function is called from the same workqueue, we can guarantee
|
|
that the controller will not be suspended during this period.
|
|
|
|
Link: https://lore.kernel.org/r/1634041588-74824-3-git-send-email-john.garry@huawei.com
|
|
Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
|
|
Signed-off-by: John Garry <john.garry@huawei.com>
|
|
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
|
|
Signed-off-by: Fujai Ni<nifuijia1@hisilicon.com>
|
|
Reviewed-by: Jason Yan <yanaijie@huawei.com>
|
|
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com>
|
|
Signed-off-by: YunYi Yang <yangyunyi2@huawei.com>
|
|
|
|
Conflicts:
|
|
drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
---
|
|
drivers/scsi/hisi_sas/hisi_sas_main.c | 44 +++++++++++++++++++-------
|
|
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 11 ++-----
|
|
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 17 ++--------
|
|
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 9 ++----
|
|
4 files changed, 39 insertions(+), 42 deletions(-)
|
|
|
|
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
index 749bc5498530..40bf4b6e30d4 100644
|
|
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
@@ -1179,9 +1179,17 @@ static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no,
|
|
static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
|
|
void *funcdata)
|
|
{
|
|
+ struct hisi_sas_phy *phy = container_of(sas_phy,
|
|
+ struct hisi_sas_phy, sas_phy);
|
|
struct sas_ha_struct *sas_ha = sas_phy->ha;
|
|
struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
|
|
+ struct device *dev = hisi_hba->dev;
|
|
+ DECLARE_COMPLETION_ONSTACK(completion);
|
|
int phy_no = sas_phy->id;
|
|
+ u8 sts = phy->phy_attached;
|
|
+ int ret = 0;
|
|
+
|
|
+ phy->reset_completion = &completion;
|
|
|
|
switch (func) {
|
|
case PHY_FUNC_HARD_RESET:
|
|
@@ -1197,21 +1205,35 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
|
|
|
|
case PHY_FUNC_DISABLE:
|
|
hisi_sas_phy_enable(hisi_hba, phy_no, 0);
|
|
- break;
|
|
+ goto out;
|
|
|
|
case PHY_FUNC_SET_LINK_RATE:
|
|
- return hisi_sas_phy_set_linkrate(hisi_hba, phy_no, funcdata);
|
|
+ ret = hisi_sas_phy_set_linkrate(hisi_hba, phy_no, funcdata);
|
|
+ break;
|
|
+
|
|
case PHY_FUNC_GET_EVENTS:
|
|
if (hisi_hba->hw->get_events) {
|
|
hisi_hba->hw->get_events(hisi_hba, phy_no);
|
|
- break;
|
|
+ goto out;
|
|
}
|
|
/* fallthru */
|
|
case PHY_FUNC_RELEASE_SPINUP_HOLD:
|
|
default:
|
|
- return -EOPNOTSUPP;
|
|
+ ret = -EOPNOTSUPP;
|
|
+ goto out;
|
|
}
|
|
- return 0;
|
|
+
|
|
+ if (sts && !wait_for_completion_timeout(&completion, 2 * HZ)) {
|
|
+ dev_warn(dev, "phy%d wait phyup timed out for func %d\n",
|
|
+ phy_no, func);
|
|
+ if (phy->in_reset)
|
|
+ ret = -ETIMEDOUT;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ phy->reset_completion = NULL;
|
|
+
|
|
+ return ret;
|
|
}
|
|
|
|
static void hisi_sas_task_done(struct sas_task *task)
|
|
@@ -1852,7 +1874,6 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
|
|
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
|
|
struct device *dev = hisi_hba->dev;
|
|
struct sas_ha_struct *sas_ha = &hisi_hba->sha;
|
|
- DECLARE_COMPLETION_ONSTACK(phyreset);
|
|
|
|
if (!local_phy->enabled) {
|
|
sas_put_local_phy(local_phy);
|
|
@@ -1864,8 +1885,11 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
|
|
sas_ha->sas_phy[local_phy->number];
|
|
struct hisi_sas_phy *phy =
|
|
container_of(sas_phy, struct hisi_sas_phy, sas_phy);
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&phy->lock, flags);
|
|
phy->in_reset = 1;
|
|
- phy->reset_completion = &phyreset;
|
|
+ spin_unlock_irqrestore(&phy->lock, flags);
|
|
}
|
|
|
|
rc = sas_phy_reset(local_phy, reset_type);
|
|
@@ -1876,18 +1900,14 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
|
|
sas_ha->sas_phy[local_phy->number];
|
|
struct hisi_sas_phy *phy =
|
|
container_of(sas_phy, struct hisi_sas_phy, sas_phy);
|
|
- /* Wait for I_T reset complete, time out after 2s */
|
|
- int ret = wait_for_completion_timeout(&phyreset,
|
|
- I_T_NEXUS_RESET_PHYUP_TIMEOUT);
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&phy->lock, flags);
|
|
- phy->reset_completion = NULL;
|
|
phy->in_reset = 0;
|
|
spin_unlock_irqrestore(&phy->lock, flags);
|
|
|
|
/* report PHY down if timed out */
|
|
- if (!ret) {
|
|
+ if (rc == -ETIMEDOUT) {
|
|
dev_warn(dev, "phy%d reset timeout\n", sas_phy->id);
|
|
hisi_sas_phy_down(hisi_hba, sas_phy->id, 0);
|
|
}
|
|
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
|
|
index 540ca255d65e..5c79e9962022 100644
|
|
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
|
|
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
|
|
@@ -1331,7 +1331,6 @@ static irqreturn_t int_phyup_v1_hw(int irq_no, void *p)
|
|
u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
|
|
struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
|
|
irqreturn_t res = IRQ_HANDLED;
|
|
- unsigned long flags;
|
|
|
|
irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2);
|
|
if (!(irq_value & CHL_INT2_SL_PHY_ENA_MSK)) {
|
|
@@ -1384,15 +1383,9 @@ static irqreturn_t int_phyup_v1_hw(int irq_no, void *p)
|
|
phy->identify.target_port_protocols =
|
|
SAS_PROTOCOL_SMP;
|
|
hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
|
|
-
|
|
- spin_lock_irqsave(&phy->lock, flags);
|
|
- if (phy->reset_completion) {
|
|
- phy->in_reset = 0;
|
|
- complete(phy->reset_completion);
|
|
- }
|
|
- spin_unlock_irqrestore(&phy->lock, flags);
|
|
-
|
|
end:
|
|
+ if (phy->reset_completion)
|
|
+ complete(phy->reset_completion);
|
|
hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
|
|
CHL_INT2_SL_PHY_ENA_MSK);
|
|
|
|
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
|
|
index f9381df36cfa..af330b313aed 100644
|
|
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
|
|
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
|
|
@@ -2662,7 +2662,6 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
|
|
struct device *dev = hisi_hba->dev;
|
|
u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
|
|
struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
|
|
- unsigned long flags;
|
|
|
|
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
|
|
|
|
@@ -2717,14 +2716,9 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
|
|
set_link_timer_quirk(hisi_hba);
|
|
}
|
|
hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
|
|
- spin_lock_irqsave(&phy->lock, flags);
|
|
- if (phy->reset_completion) {
|
|
- phy->in_reset = 0;
|
|
- complete(phy->reset_completion);
|
|
- }
|
|
- spin_unlock_irqrestore(&phy->lock, flags);
|
|
-
|
|
end:
|
|
+ if (phy->reset_completion)
|
|
+ complete(phy->reset_completion);
|
|
hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
|
|
CHL_INT0_SL_PHY_ENABLE_MSK);
|
|
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 0);
|
|
@@ -3218,7 +3212,6 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
|
|
u32 ent_tmp, ent_msk, ent_int, port_id, link_rate, hard_phy_linkrate;
|
|
irqreturn_t res = IRQ_HANDLED;
|
|
u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
|
|
- unsigned long flags;
|
|
int phy_no, offset;
|
|
|
|
del_timer(&phy->timer);
|
|
@@ -3294,12 +3287,8 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
|
|
phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
|
|
hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
|
|
|
|
- spin_lock_irqsave(&phy->lock, flags);
|
|
- if (phy->reset_completion) {
|
|
- phy->in_reset = 0;
|
|
+ if (phy->reset_completion)
|
|
complete(phy->reset_completion);
|
|
- }
|
|
- spin_unlock_irqrestore(&phy->lock, flags);
|
|
end:
|
|
hisi_sas_write32(hisi_hba, ENT_INT_SRC1 + offset, ent_tmp);
|
|
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1 + offset, ent_msk);
|
|
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
|
|
index 33882a4ef00a..04d2c8a54633 100644
|
|
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
|
|
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
|
|
@@ -1636,7 +1636,6 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
|
|
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
|
|
struct asd_sas_phy *sas_phy = &phy->sas_phy;
|
|
struct device *dev = hisi_hba->dev;
|
|
- unsigned long flags;
|
|
|
|
del_timer(&phy->timer);
|
|
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
|
|
@@ -1721,13 +1720,9 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
|
|
phy->phy_attached = 1;
|
|
hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
|
|
res = IRQ_HANDLED;
|
|
- spin_lock_irqsave(&phy->lock, flags);
|
|
- if (phy->reset_completion) {
|
|
- phy->in_reset = 0;
|
|
- complete(phy->reset_completion);
|
|
- }
|
|
- spin_unlock_irqrestore(&phy->lock, flags);
|
|
end:
|
|
+ if (phy->reset_completion)
|
|
+ complete(phy->reset_completion);
|
|
hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
|
|
CHL_INT0_SL_PHY_ENABLE_MSK);
|
|
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 0);
|
|
--
|
|
2.27.0
|
|
|