diff mbox series

[1/6] scsi: hisi_sas: workaround STP link SoC bug

Message ID 1491830521-21437-2-git-send-email-john.garry@huawei.com
State New
Headers show
Series hisi_sas: v2 hw SoC bug workarounds | expand

Commit Message

John Garry April 10, 2017, 1:21 p.m. UTC
From: Xiaofei Tan <tanxiaofei@huawei.com>


After resetting the controller, the process of scanning SATA disks
attached to an expander may fail occasionally. The issue is that
the controller can't close the STP link created by target if the
max link time is 0.

To workaround this issue, we reject STP link after resetting the
controller, and change the corresponding PHY to accept STP link
only after receiving data.

We do this check in cq interrupt handler. In order not to reduce
efficiency, we use an variable to control whether we should check
and change PHY to accept STP link.

The function phys_reject_stp_links_v2_hw() should be called after
resetting the controller.

The solution of another SoC bug "SATA IO timeout", that also uses
the same register to control STP link, is not effective before
the PHY accepts STP link.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>

Signed-off-by: John Garry <john.garry@huawei.com>

---
 drivers/scsi/hisi_sas/hisi_sas.h       |  1 +
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 60 +++++++++++++++++++++++++++++++++-
 2 files changed, 60 insertions(+), 1 deletion(-)

-- 
1.9.1

Comments

Johannes Thumshirn April 10, 2017, 1:16 p.m. UTC | #1
On Mon, Apr 10, 2017 at 09:21:56PM +0800, John Garry wrote:
> From: Xiaofei Tan <tanxiaofei@huawei.com>

> 

> After resetting the controller, the process of scanning SATA disks

> attached to an expander may fail occasionally. The issue is that

> the controller can't close the STP link created by target if the

> max link time is 0.

> 

> To workaround this issue, we reject STP link after resetting the

> controller, and change the corresponding PHY to accept STP link

> only after receiving data.

> 

> We do this check in cq interrupt handler. In order not to reduce

> efficiency, we use an variable to control whether we should check

> and change PHY to accept STP link.

> 

> The function phys_reject_stp_links_v2_hw() should be called after

> resetting the controller.

> 

> The solution of another SoC bug "SATA IO timeout", that also uses

> the same register to control STP link, is not effective before

> the PHY accepts STP link.

> 

> Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>

> Signed-off-by: John Garry <john.garry@huawei.com>

> ---


Looks good,
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>


-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850
diff mbox series

Patch

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 6aa0b62..72347b6 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -203,6 +203,7 @@  struct hisi_hba {
 
 	int slot_index_count;
 	unsigned long *slot_index_tags;
+	unsigned long reject_stp_links_msk;
 
 	/* SCSI/SAS glue */
 	struct sas_ha_struct sha;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 66c2de8..c550cc4 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -218,6 +218,9 @@ 
 #define RX_IDAF_DWORD6			(PORT_BASE + 0xdc)
 #define RXOP_CHECK_CFG_H		(PORT_BASE + 0xfc)
 #define CON_CONTROL			(PORT_BASE + 0x118)
+#define CON_CONTROL_CFG_OPEN_ACC_STP_OFF	0
+#define CON_CONTROL_CFG_OPEN_ACC_STP_MSK	\
+		(0x01 << CON_CONTROL_CFG_OPEN_ACC_STP_OFF)
 #define DONE_RECEIVED_TIME		(PORT_BASE + 0x11c)
 #define CHL_INT0			(PORT_BASE + 0x1b4)
 #define CHL_INT0_HOTPLUG_TOUT_OFF	0
@@ -240,6 +243,9 @@ 
 #define CHL_INT1_MSK			(PORT_BASE + 0x1c4)
 #define CHL_INT2_MSK			(PORT_BASE + 0x1c8)
 #define CHL_INT_COAL_EN			(PORT_BASE + 0x1d0)
+#define DMA_TX_DFX1			(PORT_BASE + 0x204)
+#define DMA_TX_DFX1_IPTT_OFF		0
+#define DMA_TX_DFX1_IPTT_MSK		(0xffff << DMA_TX_DFX1_IPTT_OFF)
 #define PHY_CTRL_RDY_MSK		(PORT_BASE + 0x2b0)
 #define PHYCTRL_NOT_RDY_MSK		(PORT_BASE + 0x2b4)
 #define PHYCTRL_DWS_RESET_MSK		(PORT_BASE + 0x2b8)
@@ -593,7 +599,8 @@  static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
 slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx,
 		       struct domain_device *device)
 {
-	unsigned int index = 0;
+	/* STP link chip bug workaround:index start from 1 */
+	unsigned int index = 1;
 	void *bitmap = hisi_hba->slot_index_tags;
 	int sata_dev = dev_is_sata(device);
 
@@ -875,6 +882,46 @@  static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
 	return 0;
 }
 
+/* This function needs to be called after resetting SAS controller. */
+static void phys_reject_stp_links_v2_hw(struct hisi_hba *hisi_hba)
+{
+	u32 cfg;
+	int phy_no;
+
+	hisi_hba->reject_stp_links_msk = (1 << hisi_hba->n_phy) - 1;
+	for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+		cfg = hisi_sas_phy_read32(hisi_hba, phy_no, CON_CONTROL);
+		if (!(cfg & CON_CONTROL_CFG_OPEN_ACC_STP_MSK))
+			continue;
+
+		cfg &= ~CON_CONTROL_CFG_OPEN_ACC_STP_MSK;
+		hisi_sas_phy_write32(hisi_hba, phy_no, CON_CONTROL, cfg);
+	}
+}
+
+static void phys_try_accept_stp_links_v2_hw(struct hisi_hba *hisi_hba)
+{
+	int phy_no;
+	u32 dma_tx_dfx1;
+
+	for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+		if (!(hisi_hba->reject_stp_links_msk & BIT(phy_no)))
+			continue;
+
+		dma_tx_dfx1 = hisi_sas_phy_read32(hisi_hba, phy_no,
+						DMA_TX_DFX1);
+		if (dma_tx_dfx1 & DMA_TX_DFX1_IPTT_MSK) {
+			u32 cfg = hisi_sas_phy_read32(hisi_hba,
+				phy_no, CON_CONTROL);
+
+			cfg |= CON_CONTROL_CFG_OPEN_ACC_STP_MSK;
+			hisi_sas_phy_write32(hisi_hba, phy_no,
+				CON_CONTROL, cfg);
+			clear_bit(phy_no, &hisi_hba->reject_stp_links_msk);
+		}
+	}
+}
+
 static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
 {
 	struct device *dev = &hisi_hba->pdev->dev;
@@ -1012,6 +1059,9 @@  static void link_timeout_enable_link(unsigned long data)
 	int i, reg_val;
 
 	for (i = 0; i < hisi_hba->n_phy; i++) {
+		if (hisi_hba->reject_stp_links_msk & BIT(i))
+			continue;
+
 		reg_val = hisi_sas_phy_read32(hisi_hba, i, CON_CONTROL);
 		if (!(reg_val & BIT(0))) {
 			hisi_sas_phy_write32(hisi_hba, i,
@@ -1031,6 +1081,9 @@  static void link_timeout_disable_link(unsigned long data)
 
 	reg_val = hisi_sas_read32(hisi_hba, PHY_STATE);
 	for (i = 0; i < hisi_hba->n_phy && reg_val; i++) {
+		if (hisi_hba->reject_stp_links_msk & BIT(i))
+			continue;
+
 		if (reg_val & BIT(i)) {
 			hisi_sas_phy_write32(hisi_hba, i,
 					CON_CONTROL, 0x6);
@@ -2867,6 +2920,9 @@  static void cq_tasklet_v2_hw(unsigned long val)
 	u32 rd_point = cq->rd_point, wr_point, dev_id;
 	int queue = cq->id;
 
+	if (unlikely(hisi_hba->reject_stp_links_msk))
+		phys_try_accept_stp_links_v2_hw(hisi_hba);
+
 	complete_queue = hisi_hba->complete_hdr[queue];
 
 	spin_lock(&hisi_hba->lock);
@@ -3214,6 +3270,8 @@  static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
 	if (rc)
 		return rc;
 
+	phys_reject_stp_links_v2_hw(hisi_hba);
+
 	/* Re-enable the PHYs */
 	for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
 		struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];