]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
scsi: hisi_sas: workaround a v3 hw hilink bug
authorXiaofei Tan <tanxiaofei@huawei.com>
Wed, 2 May 2018 15:56:34 +0000 (23:56 +0800)
committerKhalid Elmously <khalid.elmously@canonical.com>
Wed, 6 Jun 2018 19:13:18 +0000 (15:13 -0400)
BugLink: https://bugs.launchpad.net/bugs/1774467
There is an SoC bug of v3 hw development version. When hot- unplugging a
directly attached disk, the PHY down interrupt may not happen. It is
very easy to appear on some boards.

When this issue occurs, the controller will receive many invalid dword
frames, and the "alos" fields of register HILINK_ERR_DFX can indicate
that disk was unplugged.

As an workaround solution, this patch detects this issue in the channel
interrupt, and workaround it by following steps:

 - Disable the PHY
 - Clear error code and interrupt
 - Enable the PHY

Then the HW will reissue PHY down interrupt.

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>
(cherry picked from commit f70c1251deb5ab17dec70119c03f2428288ebada linux-next)
Signed-off-by: dann frazier <dann.frazier@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

index 2fd09b101120308652f4aa734c7ce955f6be371c..a371af57089871d6624caebcef22a8abb2b4988b 100644 (file)
 #define COMPL_Q_0_RD_PTR               0x4f0
 #define AWQOS_AWCACHE_CFG      0xc84
 #define ARQOS_ARCACHE_CFG      0xc88
+#define HILINK_ERR_DFX         0xe04
 
 /* phy registers requiring init */
 #define PORT_BASE                      (0x2000)
 #define CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF        22
 #define CHL_INT2                       (PORT_BASE + 0x1bc)
 #define CHL_INT2_SL_IDAF_TOUT_CONF_OFF 0
+#define CHL_INT2_RX_INVLD_DW_OFF       30
 #define CHL_INT2_STP_LINK_TIMEOUT_OFF  31
 #define CHL_INT0_MSK                   (PORT_BASE + 0x1c0)
 #define CHL_INT1_MSK                   (PORT_BASE + 0x1c4)
@@ -1345,6 +1347,7 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
 {
        struct hisi_hba *hisi_hba = p;
        struct device *dev = hisi_hba->dev;
+       struct pci_dev *pci_dev = hisi_hba->pci_dev;
        u32 irq_msk;
        int phy_no = 0;
 
@@ -1410,8 +1413,28 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
 
                        hisi_sas_phy_write32(hisi_hba, phy_no,
                                             CHL_INT2, irq_value2);
-               }
 
+                       if ((irq_value2 & BIT(CHL_INT2_RX_INVLD_DW_OFF)) &&
+                           (pci_dev->revision == 0x20)) {
+                               u32 reg_value;
+                               int rc;
+
+                               rc = hisi_sas_read32_poll_timeout_atomic(
+                                       HILINK_ERR_DFX, reg_value,
+                                       !((reg_value >> 8) & BIT(phy_no)),
+                                       1000, 10000);
+                               if (rc) {
+                                       disable_phy_v3_hw(hisi_hba, phy_no);
+                                       hisi_sas_phy_write32(hisi_hba, phy_no,
+                                               CHL_INT2,
+                                               BIT(CHL_INT2_RX_INVLD_DW_OFF));
+                                       hisi_sas_phy_read32(hisi_hba, phy_no,
+                                               ERR_CNT_INVLD_DW);
+                                       mdelay(1);
+                                       enable_phy_v3_hw(hisi_hba, phy_no);
+                               }
+                       }
+               }
 
                if (irq_msk & (2 << (phy_no * 4)) && irq_value0) {
                        hisi_sas_phy_write32(hisi_hba, phy_no,