summaryrefslogtreecommitdiff
path: root/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/hisi_sas/hisi_sas_v2_hw.c')
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v2_hw.c1599
1 files changed, 868 insertions, 731 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 2bfea7082e3a..f3516a0611dd 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -1,12 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2016 Linaro Ltd.
* Copyright (c) 2016 Hisilicon Limited.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
*/
#include "hisi_sas.h"
@@ -144,6 +139,7 @@
#define SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF 19
#define SAS_ECC_INTR_MSK 0x1ec
#define HGC_ERR_STAT_EN 0x238
+#define CQE_SEND_CNT 0x248
#define DLVRY_Q_0_BASE_ADDR_LO 0x260
#define DLVRY_Q_0_BASE_ADDR_HI 0x264
#define DLVRY_Q_0_DEPTH 0x268
@@ -240,7 +236,12 @@
#define CHL_INT1_DMAC_TX_ECC_ERR_MSK (0x1 << CHL_INT1_DMAC_TX_ECC_ERR_OFF)
#define CHL_INT1_DMAC_RX_ECC_ERR_OFF 17
#define CHL_INT1_DMAC_RX_ECC_ERR_MSK (0x1 << CHL_INT1_DMAC_RX_ECC_ERR_OFF)
+#define CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF 19
+#define CHL_INT1_DMAC_TX_AXI_RD_ERR_OFF 20
+#define CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF 21
+#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_INT0_MSK (PORT_BASE + 0x1c0)
#define CHL_INT1_MSK (PORT_BASE + 0x1c4)
#define CHL_INT2_MSK (PORT_BASE + 0x1c8)
@@ -256,6 +257,8 @@
#define LINK_DFX2_RCVR_HOLD_STS_MSK (0x1 << LINK_DFX2_RCVR_HOLD_STS_OFF)
#define LINK_DFX2_SEND_HOLD_STS_OFF 10
#define LINK_DFX2_SEND_HOLD_STS_MSK (0x1 << LINK_DFX2_SEND_HOLD_STS_OFF)
+#define SAS_ERR_CNT4_REG (PORT_BASE + 0x290)
+#define SAS_ERR_CNT6_REG (PORT_BASE + 0x298)
#define PHY_CTRL_RDY_MSK (PORT_BASE + 0x2b0)
#define PHYCTRL_NOT_RDY_MSK (PORT_BASE + 0x2b4)
#define PHYCTRL_DWS_RESET_MSK (PORT_BASE + 0x2b8)
@@ -288,6 +291,10 @@
#define CMD_HDR_RESP_REPORT_MSK (0x1 << CMD_HDR_RESP_REPORT_OFF)
#define CMD_HDR_TLR_CTRL_OFF 6
#define CMD_HDR_TLR_CTRL_MSK (0x3 << CMD_HDR_TLR_CTRL_OFF)
+#define CMD_HDR_PHY_ID_OFF 8
+#define CMD_HDR_PHY_ID_MSK (0x1ff << CMD_HDR_PHY_ID_OFF)
+#define CMD_HDR_FORCE_PHY_OFF 17
+#define CMD_HDR_FORCE_PHY_MSK (0x1 << CMD_HDR_FORCE_PHY_OFF)
#define CMD_HDR_PORT_OFF 18
#define CMD_HDR_PORT_MSK (0xf << CMD_HDR_PORT_OFF)
#define CMD_HDR_PRIORITY_OFF 27
@@ -399,6 +406,163 @@ struct hisi_sas_err_record_v2 {
__le32 dma_rx_err_type;
};
+struct signal_attenuation_s {
+ u32 de_emphasis;
+ u32 preshoot;
+ u32 boost;
+};
+
+struct sig_atten_lu_s {
+ const struct signal_attenuation_s *att;
+ u32 sas_phy_ctrl;
+};
+
+static const struct hisi_sas_hw_error one_bit_ecc_errors[] = {
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF),
+ .msk = HGC_DQE_ECC_1B_ADDR_MSK,
+ .shift = HGC_DQE_ECC_1B_ADDR_OFF,
+ .msg = "hgc_dqe_ecc1b_intr",
+ .reg = HGC_DQE_ECC_ADDR,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_1B_OFF),
+ .msk = HGC_IOST_ECC_1B_ADDR_MSK,
+ .shift = HGC_IOST_ECC_1B_ADDR_OFF,
+ .msg = "hgc_iost_ecc1b_intr",
+ .reg = HGC_IOST_ECC_ADDR,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_1B_OFF),
+ .msk = HGC_ITCT_ECC_1B_ADDR_MSK,
+ .shift = HGC_ITCT_ECC_1B_ADDR_OFF,
+ .msg = "hgc_itct_ecc1b_intr",
+ .reg = HGC_ITCT_ECC_ADDR,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF),
+ .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
+ .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
+ .msg = "hgc_iostl_ecc1b_intr",
+ .reg = HGC_LM_DFX_STATUS2,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF),
+ .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
+ .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
+ .msg = "hgc_itctl_ecc1b_intr",
+ .reg = HGC_LM_DFX_STATUS2,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_1B_OFF),
+ .msk = HGC_CQE_ECC_1B_ADDR_MSK,
+ .shift = HGC_CQE_ECC_1B_ADDR_OFF,
+ .msg = "hgc_cqe_ecc1b_intr",
+ .reg = HGC_CQE_ECC_ADDR,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF),
+ .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
+ .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
+ .msg = "rxm_mem0_ecc1b_intr",
+ .reg = HGC_RXM_DFX_STATUS14,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF),
+ .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
+ .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
+ .msg = "rxm_mem1_ecc1b_intr",
+ .reg = HGC_RXM_DFX_STATUS14,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF),
+ .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
+ .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
+ .msg = "rxm_mem2_ecc1b_intr",
+ .reg = HGC_RXM_DFX_STATUS14,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF),
+ .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
+ .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
+ .msg = "rxm_mem3_ecc1b_intr",
+ .reg = HGC_RXM_DFX_STATUS15,
+ },
+};
+
+static const struct hisi_sas_hw_error multi_bit_ecc_errors[] = {
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF),
+ .msk = HGC_DQE_ECC_MB_ADDR_MSK,
+ .shift = HGC_DQE_ECC_MB_ADDR_OFF,
+ .msg = "hgc_dqe_eccbad_intr",
+ .reg = HGC_DQE_ECC_ADDR,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF),
+ .msk = HGC_IOST_ECC_MB_ADDR_MSK,
+ .shift = HGC_IOST_ECC_MB_ADDR_OFF,
+ .msg = "hgc_iost_eccbad_intr",
+ .reg = HGC_IOST_ECC_ADDR,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF),
+ .msk = HGC_ITCT_ECC_MB_ADDR_MSK,
+ .shift = HGC_ITCT_ECC_MB_ADDR_OFF,
+ .msg = "hgc_itct_eccbad_intr",
+ .reg = HGC_ITCT_ECC_ADDR,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF),
+ .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
+ .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
+ .msg = "hgc_iostl_eccbad_intr",
+ .reg = HGC_LM_DFX_STATUS2,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF),
+ .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
+ .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
+ .msg = "hgc_itctl_eccbad_intr",
+ .reg = HGC_LM_DFX_STATUS2,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF),
+ .msk = HGC_CQE_ECC_MB_ADDR_MSK,
+ .shift = HGC_CQE_ECC_MB_ADDR_OFF,
+ .msg = "hgc_cqe_eccbad_intr",
+ .reg = HGC_CQE_ECC_ADDR,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF),
+ .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
+ .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
+ .msg = "rxm_mem0_eccbad_intr",
+ .reg = HGC_RXM_DFX_STATUS14,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF),
+ .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
+ .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
+ .msg = "rxm_mem1_eccbad_intr",
+ .reg = HGC_RXM_DFX_STATUS14,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF),
+ .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
+ .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
+ .msg = "rxm_mem2_eccbad_intr",
+ .reg = HGC_RXM_DFX_STATUS14,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF),
+ .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
+ .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
+ .msg = "rxm_mem3_eccbad_intr",
+ .reg = HGC_RXM_DFX_STATUS15,
+ },
+};
+
enum {
HISI_SAS_PHY_PHY_UPDOWN,
HISI_SAS_PHY_CHNL_INT,
@@ -560,7 +724,7 @@ enum {
#define ERR_ON_RX_PHASE(err_phase) (err_phase == 0x10 || \
err_phase == 0x20 || err_phase == 0x40)
-static void link_timeout_disable_link(unsigned long data);
+static void link_timeout_disable_link(struct timer_list *t);
static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
{
@@ -601,7 +765,7 @@ static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
/* This function needs to be protected from pre-emption. */
static int
-slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx,
+slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba,
struct domain_device *device)
{
int sata_dev = dev_is_sata(device);
@@ -632,22 +796,25 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx,
end = 64 * (sata_idx + 2);
}
+ spin_lock(&hisi_hba->lock);
while (1) {
start = find_next_zero_bit(bitmap,
hisi_hba->slot_index_count, start);
- if (start >= end)
+ if (start >= end) {
+ spin_unlock(&hisi_hba->lock);
return -SAS_QUEUE_FULL;
+ }
/*
- * SAS IPTT bit0 should be 1, and SATA IPTT bit0 should be 0.
- */
+ * SAS IPTT bit0 should be 1, and SATA IPTT bit0 should be 0.
+ */
if (sata_dev ^ (start & 1))
break;
start++;
}
set_bit(start, bitmap);
- *slot_idx = start;
- return 0;
+ spin_unlock(&hisi_hba->lock);
+ return start;
}
static bool sata_index_alloc_v2_hw(struct hisi_hba *hisi_hba, int *idx)
@@ -694,12 +861,13 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device)
hisi_hba->devices[i].device_id = i;
sas_dev = &hisi_hba->devices[i];
- sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+ sas_dev->dev_status = HISI_SAS_DEV_INIT;
sas_dev->dev_type = device->dev_type;
sas_dev->hisi_hba = hisi_hba;
sas_dev->sas_device = device;
sas_dev->sata_idx = sata_idx;
sas_dev->dq = dq;
+ spin_lock_init(&sas_dev->lock);
INIT_LIST_HEAD(&hisi_hba->devices[i].list);
break;
}
@@ -757,9 +925,9 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
struct device *dev = hisi_hba->dev;
u64 qw0, device_id = sas_dev->device_id;
struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
- struct domain_device *parent_dev = device->parent;
struct asd_sas_port *sas_port = device->port;
struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
+ u64 sas_addr;
memset(itct, 0, sizeof(*itct));
@@ -773,7 +941,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
break;
case SAS_SATA_DEV:
case SAS_SATA_PENDING:
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ if (dev_parent_is_expander(device))
qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF;
else
qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF;
@@ -792,8 +960,8 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
itct->qw0 = cpu_to_le64(qw0);
/* qw1 */
- memcpy(&itct->sas_addr, device->sas_addr, SAS_ADDR_SIZE);
- itct->sas_addr = __swab64(itct->sas_addr);
+ memcpy(&sas_addr, device->sas_addr, SAS_ADDR_SIZE);
+ itct->sas_addr = cpu_to_le64(__swab64(sas_addr));
/* qw2 */
if (!dev_is_sata(device))
@@ -803,47 +971,45 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
(0x1ULL << ITCT_HDR_RTOLT_OFF));
}
-static void free_device_v2_hw(struct hisi_hba *hisi_hba,
- struct hisi_sas_device *sas_dev)
+static int clear_itct_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
{
+ DECLARE_COMPLETION_ONSTACK(completion);
u64 dev_id = sas_dev->device_id;
- struct device *dev = hisi_hba->dev;
struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
+ struct device *dev = hisi_hba->dev;
int i;
- /* SoC bug workaround */
- if (dev_is_sata(sas_dev->sas_device))
- clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap);
+ sas_dev->completion = &completion;
/* clear the itct interrupt state */
if (ENT_INT_SRC3_ITC_INT_MSK & reg_val)
hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
ENT_INT_SRC3_ITC_INT_MSK);
- /* clear the itct int*/
+ /* need to set register twice to clear ITCT for v2 hw */
for (i = 0; i < 2; i++) {
- /* clear the itct table*/
- reg_val = hisi_sas_read32(hisi_hba, ITCT_CLR);
- reg_val |= ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
+ reg_val = ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val);
-
- udelay(10);
- reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
- if (ENT_INT_SRC3_ITC_INT_MSK & reg_val) {
- dev_dbg(dev, "got clear ITCT done interrupt\n");
-
- /* invalid the itct state*/
- memset(itct, 0, sizeof(struct hisi_sas_itct));
- hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
- ENT_INT_SRC3_ITC_INT_MSK);
-
- /* clear the itct */
- hisi_sas_write32(hisi_hba, ITCT_CLR, 0);
- dev_dbg(dev, "clear ITCT ok\n");
- break;
+ if (!wait_for_completion_timeout(sas_dev->completion,
+ HISI_SAS_CLEAR_ITCT_TIMEOUT)) {
+ dev_warn(dev, "failed to clear ITCT\n");
+ return -ETIMEDOUT;
}
+
+ memset(itct, 0, sizeof(struct hisi_sas_itct));
}
+ return 0;
+}
+
+static void free_device_v2_hw(struct hisi_sas_device *sas_dev)
+{
+ struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
+
+ /* SoC bug workaround */
+ if (dev_is_sata(sas_dev->sas_device))
+ clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap);
}
static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
@@ -939,8 +1105,10 @@ static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
dev_err(dev, "SAS de-reset fail.\n");
return -EIO;
}
- } else
- dev_warn(dev, "no reset method\n");
+ } else {
+ dev_err(dev, "no reset method\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -985,9 +1153,16 @@ static void phys_try_accept_stp_links_v2_hw(struct hisi_hba *hisi_hba)
}
}
+static const struct signal_attenuation_s x6000 = {9200, 0, 10476};
+static const struct sig_atten_lu_s sig_atten_lu[] = {
+ { &x6000, 0x3016a68 },
+};
+
static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
{
struct device *dev = hisi_hba->dev;
+ u32 sas_phy_ctrl = 0x30b9908;
+ u32 signal[3];
int i;
/* Global registers init */
@@ -1023,17 +1198,51 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 0xffffffff);
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0x7efefefe);
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0x7efefefe);
- hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0x7ffffffe);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0x7ffe20fe);
hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xfff00c30);
for (i = 0; i < hisi_hba->queue_count; i++)
- hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK+0x4*i, 0);
+ hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK + 0x4 * i, 0);
hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 1);
hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
+ /* Get sas_phy_ctrl value to deal with TX FFE issue. */
+ if (!device_property_read_u32_array(dev, "hisilicon,signal-attenuation",
+ signal, ARRAY_SIZE(signal))) {
+ for (i = 0; i < ARRAY_SIZE(sig_atten_lu); i++) {
+ const struct sig_atten_lu_s *lookup = &sig_atten_lu[i];
+ const struct signal_attenuation_s *att = lookup->att;
+
+ if ((signal[0] == att->de_emphasis) &&
+ (signal[1] == att->preshoot) &&
+ (signal[2] == att->boost)) {
+ sas_phy_ctrl = lookup->sas_phy_ctrl;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(sig_atten_lu))
+ dev_warn(dev, "unknown signal attenuation values, using default PHY ctrl config\n");
+ }
+
for (i = 0; i < hisi_hba->n_phy; i++) {
- hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855);
- hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, 0x30b9908);
+ struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ u32 prog_phy_link_rate = 0x800;
+
+ if (!sas_phy->phy || (sas_phy->phy->maximum_linkrate <
+ SAS_LINK_RATE_1_5_GBPS)) {
+ prog_phy_link_rate = 0x855;
+ } else {
+ enum sas_linkrate max = sas_phy->phy->maximum_linkrate;
+
+ prog_phy_link_rate =
+ hisi_sas_get_prog_phy_linkrate_mask(max) |
+ 0x800;
+ }
+ hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE,
+ prog_phy_link_rate);
+ hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, sas_phy_ctrl);
hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0);
hisi_sas_phy_write32(hisi_hba, i, TXID_AUTO, 0x2);
@@ -1042,8 +1251,8 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xfff87fff);
hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
- hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xffffffff);
- hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xff857fff);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbfe);
hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x13f801fc);
hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0);
hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0);
@@ -1116,9 +1325,9 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
upper_32_bits(hisi_hba->initial_fis_dma));
}
-static void link_timeout_enable_link(unsigned long data)
+static void link_timeout_enable_link(struct timer_list *t)
{
- struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
+ struct hisi_hba *hisi_hba = timer_container_of(hisi_hba, t, timer);
int i, reg_val;
for (i = 0; i < hisi_hba->n_phy; i++) {
@@ -1137,9 +1346,9 @@ static void link_timeout_enable_link(unsigned long data)
mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(900));
}
-static void link_timeout_disable_link(unsigned long data)
+static void link_timeout_disable_link(struct timer_list *t)
{
- struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
+ struct hisi_hba *hisi_hba = timer_container_of(hisi_hba, t, timer);
int i, reg_val;
reg_val = hisi_sas_read32(hisi_hba, PHY_STATE);
@@ -1160,7 +1369,6 @@ static void link_timeout_disable_link(unsigned long data)
static void set_link_timer_quirk(struct hisi_hba *hisi_hba)
{
- hisi_hba->timer.data = (unsigned long)hisi_hba;
hisi_hba->timer.function = link_timeout_disable_link;
hisi_hba->timer.expires = jiffies + msecs_to_jiffies(1000);
add_timer(&hisi_hba->timer);
@@ -1173,7 +1381,7 @@ static int hw_init_v2_hw(struct hisi_hba *hisi_hba)
rc = reset_hw_v2_hw(hisi_hba);
if (rc) {
- dev_err(dev, "hisi_sas_reset_hw failed, rc=%d", rc);
+ dev_err(dev, "hisi_sas_reset_hw failed, rc=%d\n", rc);
return rc;
}
@@ -1332,48 +1540,56 @@ static void start_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
enable_phy_v2_hw(hisi_hba, phy_no);
}
-static void stop_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
-{
- disable_phy_v2_hw(hisi_hba, phy_no);
-}
-
-static void stop_phys_v2_hw(struct hisi_hba *hisi_hba)
-{
- int i;
-
- for (i = 0; i < hisi_hba->n_phy; i++)
- stop_phy_v2_hw(hisi_hba, i);
-}
-
static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
{
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
u32 txid_auto;
- stop_phy_v2_hw(hisi_hba, phy_no);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 0);
if (phy->identify.device_type == SAS_END_DEVICE) {
txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO);
hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
txid_auto | TX_HARDRST_MSK);
}
msleep(100);
- start_phy_v2_hw(hisi_hba, phy_no);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 1);
}
-static void start_phys_v2_hw(struct hisi_hba *hisi_hba)
+static void phy_get_events_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
{
- int i;
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_phy *sphy = sas_phy->phy;
+ u32 err4_reg_val, err6_reg_val;
+
+ /* loss dword syn, phy reset problem */
+ err4_reg_val = hisi_sas_phy_read32(hisi_hba, phy_no, SAS_ERR_CNT4_REG);
+
+ /* disparity err, invalid dword */
+ err6_reg_val = hisi_sas_phy_read32(hisi_hba, phy_no, SAS_ERR_CNT6_REG);
- for (i = 0; i < hisi_hba->n_phy; i++)
- start_phy_v2_hw(hisi_hba, i);
+ sphy->loss_of_dword_sync_count += (err4_reg_val >> 16) & 0xFFFF;
+ sphy->phy_reset_problem_count += err4_reg_val & 0xFFFF;
+ sphy->invalid_dword_count += (err6_reg_val & 0xFF0000) >> 16;
+ sphy->running_disparity_error_count += err6_reg_val & 0xFF;
}
static void phys_init_v2_hw(struct hisi_hba *hisi_hba)
{
- start_phys_v2_hw(hisi_hba);
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+ if (!sas_phy->phy->enabled)
+ continue;
+
+ hisi_sas_phy_enable(hisi_hba, i, 1);
+ }
}
-static void sl_notify_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+static void sl_notify_ssp_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
{
u32 sl_control;
@@ -1394,39 +1610,12 @@ static enum sas_linkrate phy_get_max_linkrate_v2_hw(void)
static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no,
struct sas_phy_linkrates *r)
{
- u32 prog_phy_link_rate =
- hisi_sas_phy_read32(hisi_hba, phy_no, PROG_PHY_LINK_RATE);
- struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
- struct asd_sas_phy *sas_phy = &phy->sas_phy;
- int i;
- enum sas_linkrate min, max;
- u32 rate_mask = 0;
-
- if (r->maximum_linkrate == SAS_LINK_RATE_UNKNOWN) {
- max = sas_phy->phy->maximum_linkrate;
- min = r->minimum_linkrate;
- } else if (r->minimum_linkrate == SAS_LINK_RATE_UNKNOWN) {
- max = r->maximum_linkrate;
- min = sas_phy->phy->minimum_linkrate;
- } else
- return;
-
- sas_phy->phy->maximum_linkrate = max;
- sas_phy->phy->minimum_linkrate = min;
-
- min -= SAS_LINK_RATE_1_5_GBPS;
- max -= SAS_LINK_RATE_1_5_GBPS;
-
- for (i = 0; i <= max; i++)
- rate_mask |= 1 << (i * 2);
-
- prog_phy_link_rate &= ~0xff;
- prog_phy_link_rate |= rate_mask;
+ enum sas_linkrate max = r->maximum_linkrate;
+ u32 prog_phy_link_rate = 0x800;
+ prog_phy_link_rate |= hisi_sas_get_prog_phy_linkrate_mask(max);
hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE,
- prog_phy_link_rate);
-
- phy_hard_reset_v2_hw(hisi_hba, phy_no);
+ prog_phy_link_rate);
}
static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
@@ -1452,57 +1641,43 @@ static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
return bitmap;
}
-/*
- * The callpath to this function and upto writing the write
- * queue pointer should be safe from interruption.
- */
-static int
-get_free_slot_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
+/* DQ lock must be taken here */
+static void start_delivery_v2_hw(struct hisi_sas_dq *dq)
{
- struct device *dev = hisi_hba->dev;
- int queue = dq->id;
- u32 r, w;
+ struct hisi_hba *hisi_hba = dq->hisi_hba;
+ struct hisi_sas_slot *s, *s1, *s2 = NULL;
+ int dlvry_queue = dq->id;
+ int wp;
- w = dq->wr_point;
- r = hisi_sas_read32_relaxed(hisi_hba,
- DLVRY_Q_0_RD_PTR + (queue * 0x14));
- if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
- dev_warn(dev, "full queue=%d r=%d w=%d\n\n",
- queue, r, w);
- return -EAGAIN;
+ list_for_each_entry_safe(s, s1, &dq->list, delivery) {
+ if (!s->ready)
+ break;
+ s2 = s;
+ list_del(&s->delivery);
}
- return 0;
-}
+ if (!s2)
+ return;
-static void start_delivery_v2_hw(struct hisi_sas_dq *dq)
-{
- struct hisi_hba *hisi_hba = dq->hisi_hba;
- int dlvry_queue = dq->slot_prep->dlvry_queue;
- int dlvry_queue_slot = dq->slot_prep->dlvry_queue_slot;
+ /*
+ * Ensure that memories for slots built on other CPUs is observed.
+ */
+ smp_rmb();
+ wp = (s2->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS;
- dq->wr_point = ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS;
- hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
- dq->wr_point);
+ hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), wp);
}
-static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
+static void prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot,
struct hisi_sas_cmd_hdr *hdr,
struct scatterlist *scatter,
int n_elem)
{
struct hisi_sas_sge_page *sge_page = hisi_sas_sge_addr_mem(slot);
- struct device *dev = hisi_hba->dev;
struct scatterlist *sg;
int i;
- if (n_elem > HISI_SAS_SGE_PAGE_CNT) {
- dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
- n_elem);
- return -EINVAL;
- }
-
for_each_sg(scatter, sg, n_elem, i) {
struct hisi_sas_sge *entry = &sge_page->sge[i];
@@ -1515,47 +1690,24 @@ static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
hdr->prd_table_addr = cpu_to_le64(hisi_sas_sge_addr_dma(slot));
hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
-
- return 0;
}
-static int prep_smp_v2_hw(struct hisi_hba *hisi_hba,
+static void prep_smp_v2_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot)
{
struct sas_task *task = slot->task;
struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
struct domain_device *device = task->dev;
- struct device *dev = hisi_hba->dev;
struct hisi_sas_port *port = slot->port;
- struct scatterlist *sg_req, *sg_resp;
+ struct scatterlist *sg_req;
struct hisi_sas_device *sas_dev = device->lldd_dev;
dma_addr_t req_dma_addr;
- unsigned int req_len, resp_len;
- int elem, rc;
+ unsigned int req_len;
- /*
- * DMA-map SMP request, response buffers
- */
/* req */
sg_req = &task->smp_task.smp_req;
- elem = dma_map_sg(dev, sg_req, 1, DMA_TO_DEVICE);
- if (!elem)
- return -ENOMEM;
- req_len = sg_dma_len(sg_req);
req_dma_addr = sg_dma_address(sg_req);
-
- /* resp */
- sg_resp = &task->smp_task.smp_resp;
- elem = dma_map_sg(dev, sg_resp, 1, DMA_FROM_DEVICE);
- if (!elem) {
- rc = -ENOMEM;
- goto err_out_req;
- }
- resp_len = sg_dma_len(sg_resp);
- if ((req_len & 0x3) || (resp_len & 0x3)) {
- rc = -EINVAL;
- goto err_out_resp;
- }
+ req_len = sg_dma_len(&task->smp_task.smp_req);
/* create header */
/* dw0 */
@@ -1577,21 +1729,10 @@ static int prep_smp_v2_hw(struct hisi_hba *hisi_hba,
hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
-
- return 0;
-
-err_out_resp:
- dma_unmap_sg(dev, &slot->task->smp_task.smp_resp, 1,
- DMA_FROM_DEVICE);
-err_out_req:
- dma_unmap_sg(dev, &slot->task->smp_task.smp_req, 1,
- DMA_TO_DEVICE);
- return rc;
}
-static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
- struct hisi_sas_slot *slot, int is_tmf,
- struct hisi_sas_tmf_task *tmf)
+static void prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
{
struct sas_task *task = slot->task;
struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
@@ -1600,7 +1741,8 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_port *port = slot->port;
struct sas_ssp_task *ssp_task = &task->ssp_task;
struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
- int has_data = 0, rc, priority = is_tmf;
+ struct sas_tmf_task *tmf = slot->tmf;
+ int has_data = 0, priority = !!tmf;
u8 *buf_cmd;
u32 dw1 = 0, dw2 = 0;
@@ -1611,7 +1753,7 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
(1 << CMD_HDR_CMD_OFF)); /* ssp */
dw1 = 1 << CMD_HDR_VDTL_OFF;
- if (is_tmf) {
+ if (tmf) {
dw1 |= 2 << CMD_HDR_FRAME_TYPE_OFF;
dw1 |= DIR_NO_DATA << CMD_HDR_DIR_OFF;
} else {
@@ -1642,12 +1784,9 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
hdr->transfer_tags = cpu_to_le32(slot->idx);
- if (has_data) {
- rc = prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
+ if (has_data)
+ prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
slot->n_elem);
- if (rc)
- return rc;
- }
hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
@@ -1657,9 +1796,8 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
sizeof(struct ssp_frame_hdr);
memcpy(buf_cmd, &task->ssp_task.LUN, 8);
- if (!is_tmf) {
- buf_cmd[9] = task->ssp_task.task_attr |
- (task->ssp_task.task_prio << 3);
+ if (!tmf) {
+ buf_cmd[9] = task->ssp_task.task_attr;
memcpy(buf_cmd + 12, task->ssp_task.cmd->cmnd,
task->ssp_task.cmd->cmd_len);
} else {
@@ -1676,8 +1814,6 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
break;
}
}
-
- return 0;
}
#define TRANS_TX_ERR 0
@@ -1883,11 +2019,16 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
struct task_status_struct *ts = &task->task_status;
struct hisi_sas_err_record_v2 *err_record =
hisi_sas_status_buf_addr_mem(slot);
- u32 trans_tx_fail_type = cpu_to_le32(err_record->trans_tx_fail_type);
- u32 trans_rx_fail_type = cpu_to_le32(err_record->trans_rx_fail_type);
- u16 dma_tx_err_type = cpu_to_le16(err_record->dma_tx_err_type);
- u16 sipc_rx_err_type = cpu_to_le16(err_record->sipc_rx_err_type);
- u32 dma_rx_err_type = cpu_to_le32(err_record->dma_rx_err_type);
+ u32 trans_tx_fail_type = le32_to_cpu(err_record->trans_tx_fail_type);
+ u32 trans_rx_fail_type = le32_to_cpu(err_record->trans_rx_fail_type);
+ u16 dma_tx_err_type = le16_to_cpu(err_record->dma_tx_err_type);
+ u16 sipc_rx_err_type = le16_to_cpu(err_record->sipc_rx_err_type);
+ u32 dma_rx_err_type = le32_to_cpu(err_record->dma_rx_err_type);
+ struct hisi_sas_complete_v2_hdr *complete_queue =
+ hisi_hba->complete_hdr[slot->cmplt_queue];
+ struct hisi_sas_complete_v2_hdr *complete_hdr =
+ &complete_queue[slot->cmplt_queue_slot];
+ u32 dw0 = le32_to_cpu(complete_hdr->dw0);
int error = -1;
if (err_phase == 1) {
@@ -1898,8 +2039,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
trans_tx_fail_type);
} else if (err_phase == 2) {
/* error in RX phase, the priority is: DW1 > DW3 > DW2 */
- error = parse_trans_rx_err_code_v2_hw(
- trans_rx_fail_type);
+ error = parse_trans_rx_err_code_v2_hw(trans_rx_fail_type);
if (error == -1) {
error = parse_dma_rx_err_code_v2_hw(
dma_rx_err_type);
@@ -1965,7 +2105,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
}
case DMA_RX_DATA_LEN_UNDERFLOW:
{
- ts->residual = dma_rx_err_type;
+ ts->residual = trans_tx_fail_type;
ts->stat = SAS_DATA_UNDERRUN;
break;
}
@@ -2031,7 +2171,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
}
break;
case SAS_PROTOCOL_SMP:
- ts->stat = SAM_STAT_CHECK_CONDITION;
+ ts->stat = SAS_SAM_STAT_CHECK_CONDITION;
break;
case SAS_PROTOCOL_SATA:
@@ -2091,7 +2231,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
}
case DMA_RX_DATA_LEN_UNDERFLOW:
{
- ts->residual = dma_rx_err_type;
+ ts->residual = trans_tx_fail_type;
ts->stat = SAS_DATA_UNDERRUN;
break;
}
@@ -2173,7 +2313,8 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
break;
}
}
- hisi_sas_sata_done(task, slot);
+ if (dw0 & CMPLT_HDR_RSPNS_XFRD_MSK)
+ hisi_sas_sata_done(task, slot);
}
break;
default:
@@ -2181,44 +2322,38 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
}
}
-static int
-slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
+static void slot_complete_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
{
struct sas_task *task = slot->task;
struct hisi_sas_device *sas_dev;
struct device *dev = hisi_hba->dev;
struct task_status_struct *ts;
struct domain_device *device;
- enum exec_status sts;
+ struct sas_ha_struct *ha;
struct hisi_sas_complete_v2_hdr *complete_queue =
hisi_hba->complete_hdr[slot->cmplt_queue];
struct hisi_sas_complete_v2_hdr *complete_hdr =
&complete_queue[slot->cmplt_queue_slot];
unsigned long flags;
- int aborted;
+ bool is_internal = slot->is_internal;
+ u32 dw0;
if (unlikely(!task || !task->lldd_task || !task->dev))
- return -EINVAL;
+ return;
ts = &task->task_status;
device = task->dev;
+ ha = device->port->ha;
sas_dev = device->lldd_dev;
spin_lock_irqsave(&task->task_state_lock, flags);
- aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
- task->task_state_flags &=
- ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+ task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
spin_unlock_irqrestore(&task->task_state_lock, flags);
memset(ts, 0, sizeof(*ts));
ts->resp = SAS_TASK_COMPLETE;
- if (unlikely(aborted)) {
- ts->stat = SAS_ABORTED_TASK;
- hisi_sas_slot_task_free(hisi_hba, task, slot);
- return -1;
- }
-
if (unlikely(!sas_dev)) {
dev_dbg(dev, "slot complete: port has no device\n");
ts->stat = SAS_PHY_DOWN;
@@ -2226,8 +2361,9 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
}
/* Use SAS+TMF status codes */
- switch ((complete_hdr->dw0 & CMPLT_HDR_ABORT_STAT_MSK)
- >> CMPLT_HDR_ABORT_STAT_OFF) {
+ dw0 = le32_to_cpu(complete_hdr->dw0);
+ switch ((dw0 & CMPLT_HDR_ABORT_STAT_MSK) >>
+ CMPLT_HDR_ABORT_STAT_OFF) {
case STAT_IO_ABORTED:
/* this io has been aborted by abort command */
ts->stat = SAS_ABORTED_TASK;
@@ -2235,27 +2371,27 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
case STAT_IO_COMPLETE:
/* internal abort command complete */
ts->stat = TMF_RESP_FUNC_SUCC;
- del_timer(&slot->internal_abort_timer);
+ timer_delete_sync(&slot->internal_abort_timer);
goto out;
case STAT_IO_NO_DEVICE:
ts->stat = TMF_RESP_FUNC_COMPLETE;
- del_timer(&slot->internal_abort_timer);
+ timer_delete_sync(&slot->internal_abort_timer);
goto out;
case STAT_IO_NOT_VALID:
/* abort single io, controller don't find
* the io need to abort
*/
ts->stat = TMF_RESP_FUNC_FAILED;
- del_timer(&slot->internal_abort_timer);
+ timer_delete_sync(&slot->internal_abort_timer);
goto out;
default:
break;
}
- if ((complete_hdr->dw0 & CMPLT_HDR_ERX_MSK) &&
- (!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) {
- u32 err_phase = (complete_hdr->dw0 & CMPLT_HDR_ERR_PHASE_MSK)
+ if ((dw0 & CMPLT_HDR_ERX_MSK) && (!(dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) {
+ u32 err_phase = (dw0 & CMPLT_HDR_ERR_PHASE_MSK)
>> CMPLT_HDR_ERR_PHASE_OFF;
+ u32 *error_info = hisi_sas_status_buf_addr_mem(slot);
/* Analyse error happens on which phase TX or RX */
if (ERR_ON_TX_PHASE(err_phase))
@@ -2263,8 +2399,22 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
else if (ERR_ON_RX_PHASE(err_phase))
slot_err_v2_hw(hisi_hba, task, slot, 2);
- if (unlikely(slot->abort))
- return ts->stat;
+ if (ts->stat != SAS_DATA_UNDERRUN)
+ dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n",
+ slot->idx, task, sas_dev->device_id,
+ complete_hdr->dw0, complete_hdr->dw1,
+ complete_hdr->act, complete_hdr->dw3,
+ error_info[0], error_info[1],
+ error_info[2], error_info[3]);
+
+ if (unlikely(slot->abort)) {
+ if (dev_is_sata(device) && task->ata_task.use_ncq)
+ sas_ata_device_link_abort(device, true);
+ else
+ sas_task_abort(task);
+
+ return;
+ }
goto out;
}
@@ -2282,77 +2432,96 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
case SAS_PROTOCOL_SMP:
{
struct scatterlist *sg_resp = &task->smp_task.smp_resp;
- void *to;
+ void *to = page_address(sg_page(sg_resp));
- ts->stat = SAM_STAT_GOOD;
- to = kmap_atomic(sg_page(sg_resp));
+ ts->stat = SAS_SAM_STAT_GOOD;
- dma_unmap_sg(dev, &task->smp_task.smp_resp, 1,
- DMA_FROM_DEVICE);
- dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
- DMA_TO_DEVICE);
memcpy(to + sg_resp->offset,
hisi_sas_status_buf_addr_mem(slot) +
sizeof(struct hisi_sas_err_record),
- sg_dma_len(sg_resp));
- kunmap_atomic(to);
+ sg_resp->length);
break;
}
case SAS_PROTOCOL_SATA:
case SAS_PROTOCOL_STP:
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
{
- ts->stat = SAM_STAT_GOOD;
- hisi_sas_sata_done(task, slot);
+ ts->stat = SAS_SAM_STAT_GOOD;
+ if (dw0 & CMPLT_HDR_RSPNS_XFRD_MSK)
+ hisi_sas_sata_done(task, slot);
break;
}
default:
- ts->stat = SAM_STAT_CHECK_CONDITION;
+ ts->stat = SAS_SAM_STAT_CHECK_CONDITION;
break;
}
if (!slot->port->port_attached) {
- dev_err(dev, "slot complete: port %d has removed\n",
+ dev_warn(dev, "slot complete: port %d has removed\n",
slot->port->sas_port.id);
ts->stat = SAS_PHY_DOWN;
}
out:
spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ dev_info(dev, "slot complete: task(%p) aborted\n", task);
+ return;
+ }
task->task_state_flags |= SAS_TASK_STATE_DONE;
spin_unlock_irqrestore(&task->task_state_lock, flags);
- spin_lock_irqsave(&hisi_hba->lock, flags);
- hisi_sas_slot_task_free(hisi_hba, task, slot);
- spin_unlock_irqrestore(&hisi_hba->lock, flags);
- sts = ts->stat;
+ hisi_sas_slot_task_free(hisi_hba, task, slot, true);
+
+ if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) {
+ spin_lock_irqsave(&device->done_lock, flags);
+ if (test_bit(SAS_HA_FROZEN, &ha->state)) {
+ spin_unlock_irqrestore(&device->done_lock, flags);
+ dev_info(dev, "slot complete: task(%p) ignored\n",
+ task);
+ return;
+ }
+ spin_unlock_irqrestore(&device->done_lock, flags);
+ }
if (task->task_done)
task->task_done(task);
-
- return sts;
}
-static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
+static void prep_ata_v2_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot)
{
struct sas_task *task = slot->task;
struct domain_device *device = task->dev;
- struct domain_device *parent_dev = device->parent;
struct hisi_sas_device *sas_dev = device->lldd_dev;
struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
struct asd_sas_port *sas_port = device->port;
struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
+ struct sas_ata_task *ata_task = &task->ata_task;
+ struct sas_tmf_task *tmf = slot->tmf;
+ int phy_id;
u8 *buf_cmd;
- int has_data = 0, rc = 0, hdr_tag = 0;
- u32 dw1 = 0, dw2 = 0;
+ int has_data = 0, hdr_tag = 0;
+ u32 dw0, dw1 = 0, dw2 = 0;
/* create header */
/* dw0 */
- hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF);
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
- hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF);
- else
- hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF);
+ dw0 = port->id << CMD_HDR_PORT_OFF;
+ if (dev_parent_is_expander(device)) {
+ dw0 |= 3 << CMD_HDR_CMD_OFF;
+ } else {
+ phy_id = device->phy->identify.phy_identifier;
+ dw0 |= (1U << phy_id) << CMD_HDR_PHY_ID_OFF;
+ dw0 |= CMD_HDR_FORCE_PHY_MSK;
+ dw0 |= 4 << CMD_HDR_CMD_OFF;
+ }
+
+ if (tmf && ata_task->force_phy) {
+ dw0 |= CMD_HDR_FORCE_PHY_MSK;
+ dw0 |= (1 << ata_task->force_phy_id) << CMD_HDR_PHY_ID_OFF;
+ }
+
+ hdr->dw0 = cpu_to_le32(dw0);
/* dw1 */
switch (task->data_dir) {
@@ -2372,14 +2541,15 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
(task->ata_task.fis.control & ATA_SRST))
dw1 |= 1 << CMD_HDR_RESET_OFF;
- dw1 |= (hisi_sas_get_ata_protocol(
- task->ata_task.fis.command, task->data_dir))
- << CMD_HDR_FRAME_TYPE_OFF;
+ dw1 |= (hisi_sas_get_ata_protocol(task)) << CMD_HDR_FRAME_TYPE_OFF;
dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
hdr->dw1 = cpu_to_le32(dw1);
/* dw2 */
- if (task->ata_task.use_ncq && hisi_sas_get_ncq_tag(task, &hdr_tag)) {
+ if (task->ata_task.use_ncq) {
+ struct ata_queued_cmd *qc = task->uldd_task;
+
+ hdr_tag = qc->tag;
task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF;
}
@@ -2391,12 +2561,9 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
/* dw3 */
hdr->transfer_tags = cpu_to_le32(slot->idx);
- if (has_data) {
- rc = prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
+ if (has_data)
+ prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
slot->n_elem);
- if (rc)
- return rc;
- }
hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
@@ -2408,13 +2575,12 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
/* fill in command FIS */
memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
-
- return 0;
}
-static void hisi_sas_internal_abort_quirk_timeout(unsigned long data)
+static void hisi_sas_internal_abort_quirk_timeout(struct timer_list *t)
{
- struct hisi_sas_slot *slot = (struct hisi_sas_slot *)data;
+ struct hisi_sas_slot *slot = timer_container_of(slot, t,
+ internal_abort_timer);
struct hisi_sas_port *port = slot->port;
struct asd_sas_port *asd_sas_port;
struct asd_sas_phy *sas_phy;
@@ -2446,43 +2612,41 @@ static void hisi_sas_internal_abort_quirk_timeout(unsigned long data)
}
}
-static int prep_abort_v2_hw(struct hisi_hba *hisi_hba,
- struct hisi_sas_slot *slot,
- int device_id, int abort_flag, int tag_to_abort)
+static void prep_abort_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
{
struct sas_task *task = slot->task;
+ struct sas_internal_abort_task *abort = &task->abort_task;
struct domain_device *dev = task->dev;
struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
struct hisi_sas_port *port = slot->port;
struct timer_list *timer = &slot->internal_abort_timer;
+ struct hisi_sas_device *sas_dev = dev->lldd_dev;
/* setup the quirk timer */
- setup_timer(timer, hisi_sas_internal_abort_quirk_timeout,
- (unsigned long)slot);
+ timer_setup(timer, hisi_sas_internal_abort_quirk_timeout, 0);
/* Set the timeout to 10ms less than internal abort timeout */
mod_timer(timer, jiffies + msecs_to_jiffies(100));
/* dw0 */
hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
(port->id << CMD_HDR_PORT_OFF) |
- ((dev_is_sata(dev) ? 1:0) <<
+ (dev_is_sata(dev) <<
CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
- (abort_flag << CMD_HDR_ABORT_FLAG_OFF));
+ (abort->type << CMD_HDR_ABORT_FLAG_OFF));
/* dw1 */
- hdr->dw1 = cpu_to_le32(device_id << CMD_HDR_DEV_ID_OFF);
+ hdr->dw1 = cpu_to_le32(sas_dev->device_id << CMD_HDR_DEV_ID_OFF);
/* dw7 */
- hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF);
+ hdr->dw7 = cpu_to_le32(abort->tag << CMD_HDR_ABORT_IPTT_OFF);
hdr->transfer_tags = cpu_to_le32(slot->idx);
-
- return 0;
}
static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
{
int i, res = IRQ_HANDLED;
- u32 port_id, link_rate, hard_phy_linkrate;
+ u32 port_id, link_rate;
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;
@@ -2494,6 +2658,8 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
if (is_sata_phy_v2_hw(hisi_hba, phy_no))
goto end;
+ timer_delete(&phy->timer);
+
if (phy_no == 8) {
u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
@@ -2521,11 +2687,6 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
}
sas_phy->linkrate = link_rate;
- hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no,
- HARD_PHY_LINKRATE);
- phy->maximum_linkrate = hard_phy_linkrate & 0xf;
- phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf;
-
sas_phy->oob_mode = SAS_OOB_MODE;
memcpy(sas_phy->attached_sas_addr, &id->sas_addr, SAS_ADDR_SIZE);
dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate);
@@ -2544,9 +2705,10 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
if (!timer_pending(&hisi_hba->timer))
set_link_timer_quirk(hisi_hba);
}
- queue_work(hisi_hba->wq, &phy->phyup_ws);
-
+ hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
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);
@@ -2570,11 +2732,15 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
u32 phy_state, sl_ctrl, txid_auto;
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
struct hisi_sas_port *port = phy->port;
+ struct device *dev = hisi_hba->dev;
+ timer_delete(&phy->timer);
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
- hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0);
+ dev_info(dev, "phydown: phy%d phy_state=0x%x\n", phy_no, phy_state);
+ hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0,
+ GFP_ATOMIC);
sl_ctrl = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL,
@@ -2582,7 +2748,7 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
if (port && !get_wideport_bitmap_v2_hw(hisi_hba, port->id))
if (!check_any_wideports_v2_hw(hisi_hba) &&
timer_pending(&hisi_hba->timer))
- del_timer(&hisi_hba->timer);
+ timer_delete(&hisi_hba->timer);
txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO);
hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
@@ -2599,11 +2765,12 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
struct hisi_hba *hisi_hba = p;
u32 irq_msk;
int phy_no = 0;
+ irqreturn_t res = IRQ_NONE;
irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO)
>> HGC_INVLD_DQE_INFO_FB_CH0_OFF) & 0x1ff;
while (irq_msk) {
- if (irq_msk & 1) {
+ if (irq_msk & 1) {
u32 reg_value = hisi_sas_phy_read32(hisi_hba, phy_no,
CHL_INT0);
@@ -2613,15 +2780,15 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
case CHL_INT0_SL_PHY_ENABLE_MSK:
/* phy up */
if (phy_up_v2_hw(phy_no, hisi_hba) ==
- IRQ_NONE)
- return IRQ_NONE;
+ IRQ_HANDLED)
+ res = IRQ_HANDLED;
break;
case CHL_INT0_NOT_RDY_MSK:
/* phy down */
if (phy_down_v2_hw(phy_no, hisi_hba) ==
- IRQ_NONE)
- return IRQ_NONE;
+ IRQ_HANDLED)
+ res = IRQ_HANDLED;
break;
case (CHL_INT0_NOT_RDY_MSK |
@@ -2631,13 +2798,13 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
if (reg_value & BIT(phy_no)) {
/* phy up */
if (phy_up_v2_hw(phy_no, hisi_hba) ==
- IRQ_NONE)
- return IRQ_NONE;
+ IRQ_HANDLED)
+ res = IRQ_HANDLED;
} else {
/* phy down */
if (phy_down_v2_hw(phy_no, hisi_hba) ==
- IRQ_NONE)
- return IRQ_NONE;
+ IRQ_HANDLED)
+ res = IRQ_HANDLED;
}
break;
@@ -2650,25 +2817,50 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
phy_no++;
}
- return IRQ_HANDLED;
+ return res;
}
static void phy_bcast_v2_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 sas_ha_struct *sas_ha = &hisi_hba->sha;
u32 bcast_status;
hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1);
bcast_status = hisi_sas_phy_read32(hisi_hba, phy_no, RX_PRIMS_STATUS);
if (bcast_status & RX_BCAST_CHG_MSK)
- sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+ hisi_sas_phy_bcast(phy);
hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
CHL_INT0_SL_RX_BCST_ACK_MSK);
hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0);
}
+static const struct hisi_sas_hw_error port_ecc_axi_error[] = {
+ {
+ .irq_msk = BIT(CHL_INT1_DMAC_TX_ECC_ERR_OFF),
+ .msg = "dmac_tx_ecc_bad_err",
+ },
+ {
+ .irq_msk = BIT(CHL_INT1_DMAC_RX_ECC_ERR_OFF),
+ .msg = "dmac_rx_ecc_bad_err",
+ },
+ {
+ .irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF),
+ .msg = "dma_tx_axi_wr_err",
+ },
+ {
+ .irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_RD_ERR_OFF),
+ .msg = "dma_tx_axi_rd_err",
+ },
+ {
+ .irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF),
+ .msg = "dma_rx_axi_wr_err",
+ },
+ {
+ .irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF),
+ .msg = "dma_rx_axi_rd_err",
+ },
+};
+
static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
{
struct hisi_hba *hisi_hba = p;
@@ -2685,40 +2877,58 @@ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
HGC_INVLD_DQE_INFO_FB_CH3_OFF) & 0x1ff;
while (irq_msk) {
- if (irq_msk & (1 << phy_no)) {
- u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
- CHL_INT0);
- u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no,
- CHL_INT1);
- u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no,
- CHL_INT2);
-
- if (irq_value1) {
- if (irq_value1 & (CHL_INT1_DMAC_RX_ECC_ERR_MSK |
- CHL_INT1_DMAC_TX_ECC_ERR_MSK))
- panic("%s: DMAC RX/TX ecc bad error!\
- (0x%x)",
- dev_name(dev), irq_value1);
-
- hisi_sas_phy_write32(hisi_hba, phy_no,
- CHL_INT1, irq_value1);
- }
+ u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
+ CHL_INT0);
+ u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no,
+ CHL_INT1);
+ u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no,
+ CHL_INT2);
+
+ if ((irq_msk & (1 << phy_no)) && irq_value1) {
+ int i;
- if (irq_value2)
- hisi_sas_phy_write32(hisi_hba, phy_no,
- CHL_INT2, irq_value2);
+ for (i = 0; i < ARRAY_SIZE(port_ecc_axi_error); i++) {
+ const struct hisi_sas_hw_error *error =
+ &port_ecc_axi_error[i];
+ if (!(irq_value1 & error->irq_msk))
+ continue;
- if (irq_value0) {
- if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
- phy_bcast_v2_hw(phy_no, hisi_hba);
+ dev_warn(dev, "%s error (phy%d 0x%x) found!\n",
+ error->msg, phy_no, irq_value1);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+ }
- hisi_sas_phy_write32(hisi_hba, phy_no,
- CHL_INT0, irq_value0
- & (~CHL_INT0_HOTPLUG_TOUT_MSK)
- & (~CHL_INT0_SL_PHY_ENABLE_MSK)
- & (~CHL_INT0_NOT_RDY_MSK));
+ hisi_sas_phy_write32(hisi_hba, phy_no,
+ CHL_INT1, irq_value1);
+ }
+
+ if ((irq_msk & (1 << phy_no)) && irq_value2) {
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+
+ if (irq_value2 & BIT(CHL_INT2_SL_IDAF_TOUT_CONF_OFF)) {
+ dev_warn(dev, "phy%d identify timeout\n",
+ phy_no);
+ hisi_sas_notify_phy_event(phy,
+ HISI_PHYE_LINK_RESET);
}
+
+ hisi_sas_phy_write32(hisi_hba, phy_no,
+ CHL_INT2, irq_value2);
+ }
+
+ if ((irq_msk & (1 << phy_no)) && irq_value0) {
+ if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
+ phy_bcast_v2_hw(phy_no, hisi_hba);
+
+ if (irq_value0 & CHL_INT0_PHY_RDY_MSK)
+ hisi_sas_phy_oob_ready(hisi_hba, phy_no);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no,
+ CHL_INT0, irq_value0
+ & (~CHL_INT0_HOTPLUG_TOUT_MSK)
+ & (~CHL_INT0_SL_PHY_ENABLE_MSK)
+ & (~CHL_INT0_NOT_RDY_MSK));
}
irq_msk &= ~(1 << phy_no);
phy_no++;
@@ -2733,194 +2943,40 @@ static void
one_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba, u32 irq_value)
{
struct device *dev = hisi_hba->dev;
- u32 reg_val;
-
- if (irq_value & BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_DQE_ECC_ADDR);
- dev_warn(dev, "hgc_dqe_acc1b_intr found: \
- Ram address is 0x%08X\n",
- (reg_val & HGC_DQE_ECC_1B_ADDR_MSK) >>
- HGC_DQE_ECC_1B_ADDR_OFF);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_IOST_ECC_1B_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_IOST_ECC_ADDR);
- dev_warn(dev, "hgc_iost_acc1b_intr found: \
- Ram address is 0x%08X\n",
- (reg_val & HGC_IOST_ECC_1B_ADDR_MSK) >>
- HGC_IOST_ECC_1B_ADDR_OFF);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_ITCT_ECC_1B_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_ITCT_ECC_ADDR);
- dev_warn(dev, "hgc_itct_acc1b_intr found: \
- Ram address is 0x%08X\n",
- (reg_val & HGC_ITCT_ECC_1B_ADDR_MSK) >>
- HGC_ITCT_ECC_1B_ADDR_OFF);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_LM_DFX_STATUS2);
- dev_warn(dev, "hgc_iostl_acc1b_intr found: \
- memory address is 0x%08X\n",
- (reg_val & HGC_LM_DFX_STATUS2_IOSTLIST_MSK) >>
- HGC_LM_DFX_STATUS2_IOSTLIST_OFF);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_LM_DFX_STATUS2);
- dev_warn(dev, "hgc_itctl_acc1b_intr found: \
- memory address is 0x%08X\n",
- (reg_val & HGC_LM_DFX_STATUS2_ITCTLIST_MSK) >>
- HGC_LM_DFX_STATUS2_ITCTLIST_OFF);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_CQE_ECC_1B_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_CQE_ECC_ADDR);
- dev_warn(dev, "hgc_cqe_acc1b_intr found: \
- Ram address is 0x%08X\n",
- (reg_val & HGC_CQE_ECC_1B_ADDR_MSK) >>
- HGC_CQE_ECC_1B_ADDR_OFF);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
- dev_warn(dev, "rxm_mem0_acc1b_intr found: \
- memory address is 0x%08X\n",
- (reg_val & HGC_RXM_DFX_STATUS14_MEM0_MSK) >>
- HGC_RXM_DFX_STATUS14_MEM0_OFF);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
- dev_warn(dev, "rxm_mem1_acc1b_intr found: \
- memory address is 0x%08X\n",
- (reg_val & HGC_RXM_DFX_STATUS14_MEM1_MSK) >>
- HGC_RXM_DFX_STATUS14_MEM1_OFF);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
- dev_warn(dev, "rxm_mem2_acc1b_intr found: \
- memory address is 0x%08X\n",
- (reg_val & HGC_RXM_DFX_STATUS14_MEM2_MSK) >>
- HGC_RXM_DFX_STATUS14_MEM2_OFF);
- }
+ const struct hisi_sas_hw_error *ecc_error;
+ u32 val;
+ int i;
- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS15);
- dev_warn(dev, "rxm_mem3_acc1b_intr found: \
- memory address is 0x%08X\n",
- (reg_val & HGC_RXM_DFX_STATUS15_MEM3_MSK) >>
- HGC_RXM_DFX_STATUS15_MEM3_OFF);
+ for (i = 0; i < ARRAY_SIZE(one_bit_ecc_errors); i++) {
+ ecc_error = &one_bit_ecc_errors[i];
+ if (irq_value & ecc_error->irq_msk) {
+ val = hisi_sas_read32(hisi_hba, ecc_error->reg);
+ val &= ecc_error->msk;
+ val >>= ecc_error->shift;
+ dev_warn(dev, "%s found: mem addr is 0x%08X\n",
+ ecc_error->msg, val);
+ }
}
-
}
static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba,
u32 irq_value)
{
- u32 reg_val;
struct device *dev = hisi_hba->dev;
+ const struct hisi_sas_hw_error *ecc_error;
+ u32 val;
+ int i;
- if (irq_value & BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_DQE_ECC_ADDR);
- dev_warn(dev, "hgc_dqe_accbad_intr (0x%x) found: \
- Ram address is 0x%08X\n",
- irq_value,
- (reg_val & HGC_DQE_ECC_MB_ADDR_MSK) >>
- HGC_DQE_ECC_MB_ADDR_OFF);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_IOST_ECC_ADDR);
- dev_warn(dev, "hgc_iost_accbad_intr (0x%x) found: \
- Ram address is 0x%08X\n",
- irq_value,
- (reg_val & HGC_IOST_ECC_MB_ADDR_MSK) >>
- HGC_IOST_ECC_MB_ADDR_OFF);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_ITCT_ECC_ADDR);
- dev_warn(dev,"hgc_itct_accbad_intr (0x%x) found: \
- Ram address is 0x%08X\n",
- irq_value,
- (reg_val & HGC_ITCT_ECC_MB_ADDR_MSK) >>
- HGC_ITCT_ECC_MB_ADDR_OFF);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_LM_DFX_STATUS2);
- dev_warn(dev, "hgc_iostl_accbad_intr (0x%x) found: \
- memory address is 0x%08X\n",
- irq_value,
- (reg_val & HGC_LM_DFX_STATUS2_IOSTLIST_MSK) >>
- HGC_LM_DFX_STATUS2_IOSTLIST_OFF);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_LM_DFX_STATUS2);
- dev_warn(dev, "hgc_itctl_accbad_intr (0x%x) found: \
- memory address is 0x%08X\n",
- irq_value,
- (reg_val & HGC_LM_DFX_STATUS2_ITCTLIST_MSK) >>
- HGC_LM_DFX_STATUS2_ITCTLIST_OFF);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_CQE_ECC_ADDR);
- dev_warn(dev, "hgc_cqe_accbad_intr (0x%x) found: \
- Ram address is 0x%08X\n",
- irq_value,
- (reg_val & HGC_CQE_ECC_MB_ADDR_MSK) >>
- HGC_CQE_ECC_MB_ADDR_OFF);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
- dev_warn(dev, "rxm_mem0_accbad_intr (0x%x) found: \
- memory address is 0x%08X\n",
- irq_value,
- (reg_val & HGC_RXM_DFX_STATUS14_MEM0_MSK) >>
- HGC_RXM_DFX_STATUS14_MEM0_OFF);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
- dev_warn(dev, "rxm_mem1_accbad_intr (0x%x) found: \
- memory address is 0x%08X\n",
- irq_value,
- (reg_val & HGC_RXM_DFX_STATUS14_MEM1_MSK) >>
- HGC_RXM_DFX_STATUS14_MEM1_OFF);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
- dev_warn(dev, "rxm_mem2_accbad_intr (0x%x) found: \
- memory address is 0x%08X\n",
- irq_value,
- (reg_val & HGC_RXM_DFX_STATUS14_MEM2_MSK) >>
- HGC_RXM_DFX_STATUS14_MEM2_OFF);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
-
- if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF)) {
- reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS15);
- dev_warn(dev, "rxm_mem3_accbad_intr (0x%x) found: \
- memory address is 0x%08X\n",
- irq_value,
- (reg_val & HGC_RXM_DFX_STATUS15_MEM3_MSK) >>
- HGC_RXM_DFX_STATUS15_MEM3_OFF);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+ for (i = 0; i < ARRAY_SIZE(multi_bit_ecc_errors); i++) {
+ ecc_error = &multi_bit_ecc_errors[i];
+ if (irq_value & ecc_error->irq_msk) {
+ val = hisi_sas_read32(hisi_hba, ecc_error->reg);
+ val &= ecc_error->msk;
+ val >>= ecc_error->shift;
+ dev_err(dev, "%s (0x%x) found: mem addr is 0x%08X\n",
+ ecc_error->msg, irq_value, val);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+ }
}
return;
@@ -2946,25 +3002,58 @@ static irqreturn_t fatal_ecc_int_v2_hw(int irq_no, void *p)
return IRQ_HANDLED;
}
-#define AXI_ERR_NR 8
-static const char axi_err_info[AXI_ERR_NR][32] = {
- "IOST_AXI_W_ERR",
- "IOST_AXI_R_ERR",
- "ITCT_AXI_W_ERR",
- "ITCT_AXI_R_ERR",
- "SATA_AXI_W_ERR",
- "SATA_AXI_R_ERR",
- "DQE_AXI_R_ERR",
- "CQE_AXI_W_ERR"
+static const struct hisi_sas_hw_error axi_error[] = {
+ { .msk = BIT(0), .msg = "IOST_AXI_W_ERR" },
+ { .msk = BIT(1), .msg = "IOST_AXI_R_ERR" },
+ { .msk = BIT(2), .msg = "ITCT_AXI_W_ERR" },
+ { .msk = BIT(3), .msg = "ITCT_AXI_R_ERR" },
+ { .msk = BIT(4), .msg = "SATA_AXI_W_ERR" },
+ { .msk = BIT(5), .msg = "SATA_AXI_R_ERR" },
+ { .msk = BIT(6), .msg = "DQE_AXI_R_ERR" },
+ { .msk = BIT(7), .msg = "CQE_AXI_W_ERR" },
+ {}
};
-#define FIFO_ERR_NR 5
-static const char fifo_err_info[FIFO_ERR_NR][32] = {
- "CQE_WINFO_FIFO",
- "CQE_MSG_FIFIO",
- "GETDQE_FIFO",
- "CMDP_FIFO",
- "AWTCTRL_FIFO"
+static const struct hisi_sas_hw_error fifo_error[] = {
+ { .msk = BIT(8), .msg = "CQE_WINFO_FIFO" },
+ { .msk = BIT(9), .msg = "CQE_MSG_FIFIO" },
+ { .msk = BIT(10), .msg = "GETDQE_FIFO" },
+ { .msk = BIT(11), .msg = "CMDP_FIFO" },
+ { .msk = BIT(12), .msg = "AWTCTRL_FIFO" },
+ {}
+};
+
+static const struct hisi_sas_hw_error fatal_axi_errors[] = {
+ {
+ .irq_msk = BIT(ENT_INT_SRC3_WP_DEPTH_OFF),
+ .msg = "write pointer and depth",
+ },
+ {
+ .irq_msk = BIT(ENT_INT_SRC3_IPTT_SLOT_NOMATCH_OFF),
+ .msg = "iptt no match slot",
+ },
+ {
+ .irq_msk = BIT(ENT_INT_SRC3_RP_DEPTH_OFF),
+ .msg = "read pointer and depth",
+ },
+ {
+ .irq_msk = BIT(ENT_INT_SRC3_AXI_OFF),
+ .reg = HGC_AXI_FIFO_ERR_INFO,
+ .sub = axi_error,
+ },
+ {
+ .irq_msk = BIT(ENT_INT_SRC3_FIFO_OFF),
+ .reg = HGC_AXI_FIFO_ERR_INFO,
+ .sub = fifo_error,
+ },
+ {
+ .irq_msk = BIT(ENT_INT_SRC3_LM_OFF),
+ .msg = "LM add/fetch list",
+ },
+ {
+ .irq_msk = BIT(ENT_INT_SRC3_ABT_OFF),
+ .msg = "SAS_HGC_ABT fetch LM list",
+ },
};
static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
@@ -2972,111 +3061,70 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
struct hisi_hba *hisi_hba = p;
u32 irq_value, irq_msk, err_value;
struct device *dev = hisi_hba->dev;
+ const struct hisi_sas_hw_error *axi_error;
+ int i;
irq_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK3);
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, irq_msk | 0xfffffffe);
irq_value = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
- if (irq_value) {
- if (irq_value & BIT(ENT_INT_SRC3_WP_DEPTH_OFF)) {
- hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
- 1 << ENT_INT_SRC3_WP_DEPTH_OFF);
- dev_warn(dev, "write pointer and depth error (0x%x) \
- found!\n",
- irq_value);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
-
- if (irq_value & BIT(ENT_INT_SRC3_IPTT_SLOT_NOMATCH_OFF)) {
- hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
- 1 <<
- ENT_INT_SRC3_IPTT_SLOT_NOMATCH_OFF);
- dev_warn(dev, "iptt no match slot error (0x%x) found!\n",
- irq_value);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
- if (irq_value & BIT(ENT_INT_SRC3_RP_DEPTH_OFF)) {
- dev_warn(dev, "read pointer and depth error (0x%x) \
- found!\n",
- irq_value);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
-
- if (irq_value & BIT(ENT_INT_SRC3_AXI_OFF)) {
- int i;
-
- hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
- 1 << ENT_INT_SRC3_AXI_OFF);
- err_value = hisi_sas_read32(hisi_hba,
- HGC_AXI_FIFO_ERR_INFO);
-
- for (i = 0; i < AXI_ERR_NR; i++) {
- if (err_value & BIT(i)) {
- dev_warn(dev, "%s (0x%x) found!\n",
- axi_err_info[i], irq_value);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
- }
- }
-
- if (irq_value & BIT(ENT_INT_SRC3_FIFO_OFF)) {
- int i;
-
- hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
- 1 << ENT_INT_SRC3_FIFO_OFF);
- err_value = hisi_sas_read32(hisi_hba,
- HGC_AXI_FIFO_ERR_INFO);
+ for (i = 0; i < ARRAY_SIZE(fatal_axi_errors); i++) {
+ axi_error = &fatal_axi_errors[i];
+ if (!(irq_value & axi_error->irq_msk))
+ continue;
- for (i = 0; i < FIFO_ERR_NR; i++) {
- if (err_value & BIT(AXI_ERR_NR + i)) {
- dev_warn(dev, "%s (0x%x) found!\n",
- fifo_err_info[i], irq_value);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
+ 1 << axi_error->shift);
+ if (axi_error->sub) {
+ const struct hisi_sas_hw_error *sub = axi_error->sub;
+
+ err_value = hisi_sas_read32(hisi_hba, axi_error->reg);
+ for (; sub->msk || sub->msg; sub++) {
+ if (!(err_value & sub->msk))
+ continue;
+ dev_err(dev, "%s (0x%x) found!\n",
+ sub->msg, irq_value);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
-
- }
-
- if (irq_value & BIT(ENT_INT_SRC3_LM_OFF)) {
- hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
- 1 << ENT_INT_SRC3_LM_OFF);
- dev_warn(dev, "LM add/fetch list error (0x%x) found!\n",
- irq_value);
+ } else {
+ dev_err(dev, "%s (0x%x) found!\n",
+ axi_error->msg, irq_value);
queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
+ }
- if (irq_value & BIT(ENT_INT_SRC3_ABT_OFF)) {
- hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
- 1 << ENT_INT_SRC3_ABT_OFF);
- dev_warn(dev, "SAS_HGC_ABT fetch LM list error (0x%x) found!\n",
- irq_value);
- queue_work(hisi_hba->wq, &hisi_hba->rst_work);
- }
+ if (irq_value & BIT(ENT_INT_SRC3_ITC_INT_OFF)) {
+ u32 reg_val = hisi_sas_read32(hisi_hba, ITCT_CLR);
+ u32 dev_id = reg_val & ITCT_DEV_MSK;
+ struct hisi_sas_device *sas_dev = &hisi_hba->devices[dev_id];
+
+ hisi_sas_write32(hisi_hba, ITCT_CLR, 0);
+ dev_dbg(dev, "clear ITCT ok\n");
+ complete(sas_dev->completion);
}
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC3, irq_value);
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, irq_msk);
return IRQ_HANDLED;
}
-static void cq_tasklet_v2_hw(unsigned long val)
+static irqreturn_t cq_thread_v2_hw(int irq_no, void *p)
{
- struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val;
+ struct hisi_sas_cq *cq = p;
struct hisi_hba *hisi_hba = cq->hisi_hba;
struct hisi_sas_slot *slot;
struct hisi_sas_itct *itct;
struct hisi_sas_complete_v2_hdr *complete_queue;
u32 rd_point = cq->rd_point, wr_point, dev_id;
int queue = cq->id;
- struct hisi_sas_dq *dq = &hisi_hba->dq[queue];
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(&dq->lock);
wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR +
(0x14 * queue));
@@ -3088,20 +3136,24 @@ static void cq_tasklet_v2_hw(unsigned long val)
/* Check for NCQ completion */
if (complete_hdr->act) {
- u32 act_tmp = complete_hdr->act;
+ u32 act_tmp = le32_to_cpu(complete_hdr->act);
int ncq_tag_count = ffs(act_tmp);
+ u32 dw1 = le32_to_cpu(complete_hdr->dw1);
- dev_id = (complete_hdr->dw1 & CMPLT_HDR_DEV_ID_MSK) >>
+ dev_id = (dw1 & CMPLT_HDR_DEV_ID_MSK) >>
CMPLT_HDR_DEV_ID_OFF;
itct = &hisi_hba->itct[dev_id];
/* The NCQ tags are held in the itct header */
while (ncq_tag_count) {
- __le64 *ncq_tag = &itct->qw4_15[0];
+ __le64 *_ncq_tag = &itct->qw4_15[0], __ncq_tag;
+ u64 ncq_tag;
- ncq_tag_count -= 1;
- iptt = (ncq_tag[ncq_tag_count / 5]
- >> (ncq_tag_count % 5) * 12) & 0xfff;
+ ncq_tag_count--;
+ __ncq_tag = _ncq_tag[ncq_tag_count / 5];
+ ncq_tag = le64_to_cpu(__ncq_tag);
+ iptt = (ncq_tag >> (ncq_tag_count % 5) * 12) &
+ 0xfff;
slot = &hisi_hba->slot_info[iptt];
slot->cmplt_queue_slot = rd_point;
@@ -3112,7 +3164,9 @@ static void cq_tasklet_v2_hw(unsigned long val)
ncq_tag_count = ffs(act_tmp);
}
} else {
- iptt = (complete_hdr->dw1) & CMPLT_HDR_IPTT_MSK;
+ u32 dw1 = le32_to_cpu(complete_hdr->dw1);
+
+ iptt = dw1 & CMPLT_HDR_IPTT_MSK;
slot = &hisi_hba->slot_info[iptt];
slot->cmplt_queue_slot = rd_point;
slot->cmplt_queue = queue;
@@ -3126,7 +3180,8 @@ static void cq_tasklet_v2_hw(unsigned long val)
/* update rd_point */
cq->rd_point = rd_point;
hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
- spin_unlock(&dq->lock);
+
+ return IRQ_HANDLED;
}
static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
@@ -3137,9 +3192,7 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
- tasklet_schedule(&cq->tasklet);
-
- return IRQ_HANDLED;
+ return IRQ_WAKE_THREAD;
}
static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
@@ -3155,6 +3208,8 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
int phy_no, offset;
+ timer_delete(&phy->timer);
+
phy_no = sas_phy->id;
initial_fis = &hisi_hba->initial_fis[phy_no];
fis = &initial_fis->fis;
@@ -3177,9 +3232,8 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
/* check ERR bit of Status Register */
if (fis->status & ATA_ERR) {
dev_warn(dev, "sata int: phy%d FIS status: 0x%x\n", phy_no,
- fis->status);
- disable_phy_v2_hw(hisi_hba, phy_no);
- enable_phy_v2_hw(hisi_hba, phy_no);
+ fis->status);
+ hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET);
res = IRQ_NONE;
goto end;
}
@@ -3213,6 +3267,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
sas_phy->oob_mode = SATA_OOB_MODE;
/* Make up some unique SAS address */
attached_sas_addr[0] = 0x50;
+ attached_sas_addr[6] = hisi_hba->shost->host_no;
attached_sas_addr[7] = phy_no;
memcpy(sas_phy->attached_sas_addr, attached_sas_addr, SAS_ADDR_SIZE);
memcpy(sas_phy->frame_rcvd, fis, sizeof(struct dev_to_host_fis));
@@ -3224,8 +3279,10 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
phy->identify.device_type = SAS_SATA_DEV;
phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
- queue_work(hisi_hba->wq, &phy->phyup_ws);
+ hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
+ if (phy->reset_completion)
+ complete(phy->reset_completion);
end:
hisi_sas_write32(hisi_hba, ENT_INT_SRC1 + offset, ent_tmp);
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1 + offset, ent_msk);
@@ -3243,7 +3300,29 @@ static irq_handler_t fatal_interrupts[HISI_SAS_FATAL_INT_NR] = {
fatal_axi_int_v2_hw
};
-/**
+#define CQ0_IRQ_INDEX (96)
+
+static int hisi_sas_v2_interrupt_preinit(struct hisi_hba *hisi_hba)
+{
+ struct platform_device *pdev = hisi_hba->platform_dev;
+ struct Scsi_Host *shost = hisi_hba->shost;
+ struct irq_affinity desc = {
+ .pre_vectors = CQ0_IRQ_INDEX,
+ .post_vectors = 16,
+ };
+ int resv = desc.pre_vectors + desc.post_vectors, minvec = resv + 1, nvec;
+
+ nvec = devm_platform_get_irqs_affinity(pdev, &desc, minvec, 128,
+ &hisi_hba->irq_map);
+ if (nvec < 0)
+ return nvec;
+
+ shost->nr_hw_queues = hisi_hba->cq_nvecs = nvec - resv;
+
+ return 0;
+}
+
+/*
* There is a limitation in the hip06 chipset that we need
* to map in all mbigen interrupts, even if they are not used.
*/
@@ -3251,97 +3330,65 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
{
struct platform_device *pdev = hisi_hba->platform_dev;
struct device *dev = &pdev->dev;
- int i, irq, rc, irq_map[128];
-
-
- for (i = 0; i < 128; i++)
- irq_map[i] = platform_get_irq(pdev, i);
+ int irq, rc = 0;
+ int i, phy_no, fatal_no, queue_no;
for (i = 0; i < HISI_SAS_PHY_INT_NR; i++) {
- int idx = i;
-
- irq = irq_map[idx + 1]; /* Phy up/down is irq1 */
- if (!irq) {
- dev_err(dev, "irq init: fail map phy interrupt %d\n",
- idx);
- return -ENOENT;
- }
-
+ irq = hisi_hba->irq_map[i + 1]; /* Phy up/down is irq1 */
rc = devm_request_irq(dev, irq, phy_interrupts[i], 0,
DRV_NAME " phy", hisi_hba);
if (rc) {
- dev_err(dev, "irq init: could not request "
- "phy interrupt %d, rc=%d\n",
+ dev_err(dev, "irq init: could not request phy interrupt %d, rc=%d\n",
irq, rc);
- return -ENOENT;
+ rc = -ENOENT;
+ goto err_out;
}
}
- for (i = 0; i < hisi_hba->n_phy; i++) {
- struct hisi_sas_phy *phy = &hisi_hba->phy[i];
- int idx = i + 72; /* First SATA interrupt is irq72 */
-
- irq = irq_map[idx];
- if (!irq) {
- dev_err(dev, "irq init: fail map phy interrupt %d\n",
- idx);
- return -ENOENT;
- }
+ for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ irq = hisi_hba->irq_map[phy_no + 72];
rc = devm_request_irq(dev, irq, sata_int_v2_hw, 0,
DRV_NAME " sata", phy);
if (rc) {
- dev_err(dev, "irq init: could not request "
- "sata interrupt %d, rc=%d\n",
+ dev_err(dev, "irq init: could not request sata interrupt %d, rc=%d\n",
irq, rc);
- return -ENOENT;
+ rc = -ENOENT;
+ goto err_out;
}
}
- for (i = 0; i < HISI_SAS_FATAL_INT_NR; i++) {
- int idx = i;
-
- irq = irq_map[idx + 81];
- if (!irq) {
- dev_err(dev, "irq init: fail map fatal interrupt %d\n",
- idx);
- return -ENOENT;
- }
-
- rc = devm_request_irq(dev, irq, fatal_interrupts[i], 0,
+ for (fatal_no = 0; fatal_no < HISI_SAS_FATAL_INT_NR; fatal_no++) {
+ irq = hisi_hba->irq_map[fatal_no + 81];
+ rc = devm_request_irq(dev, irq, fatal_interrupts[fatal_no], 0,
DRV_NAME " fatal", hisi_hba);
if (rc) {
- dev_err(dev,
- "irq init: could not request fatal interrupt %d, rc=%d\n",
+ dev_err(dev, "irq init: could not request fatal interrupt %d, rc=%d\n",
irq, rc);
- return -ENOENT;
+ rc = -ENOENT;
+ goto err_out;
}
}
- for (i = 0; i < hisi_hba->queue_count; i++) {
- int idx = i + 96; /* First cq interrupt is irq96 */
- struct hisi_sas_cq *cq = &hisi_hba->cq[i];
- struct tasklet_struct *t = &cq->tasklet;
-
- irq = irq_map[idx];
- if (!irq) {
- dev_err(dev,
- "irq init: could not map cq interrupt %d\n",
- idx);
- return -ENOENT;
- }
- rc = devm_request_irq(dev, irq, cq_interrupt_v2_hw, 0,
- DRV_NAME " cq", &hisi_hba->cq[i]);
+ for (queue_no = 0; queue_no < hisi_hba->cq_nvecs; queue_no++) {
+ struct hisi_sas_cq *cq = &hisi_hba->cq[queue_no];
+
+ cq->irq_no = hisi_hba->irq_map[queue_no + 96];
+ rc = devm_request_threaded_irq(dev, cq->irq_no,
+ cq_interrupt_v2_hw,
+ cq_thread_v2_hw, IRQF_ONESHOT,
+ DRV_NAME " cq", cq);
if (rc) {
- dev_err(dev,
- "irq init: could not request cq interrupt %d, rc=%d\n",
- irq, rc);
- return -ENOENT;
+ dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n",
+ cq->irq_no, rc);
+ rc = -ENOENT;
+ goto err_out;
}
- tasklet_init(t, cq_tasklet_v2_hw, (unsigned long)cq);
+ cq->irq_mask = irq_get_affinity_mask(cq->irq_no);
}
-
- return 0;
+err_out:
+ return rc;
}
static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
@@ -3383,19 +3430,21 @@ static void interrupt_disable_v2_hw(struct hisi_hba *hisi_hba)
synchronize_irq(platform_get_irq(pdev, i));
}
+
+static u32 get_phys_state_v2_hw(struct hisi_hba *hisi_hba)
+{
+ return hisi_sas_read32(hisi_hba, PHY_STATE);
+}
+
static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
{
struct device *dev = hisi_hba->dev;
- u32 old_state, state;
int rc, cnt;
- int phy_no;
-
- old_state = hisi_sas_read32(hisi_hba, PHY_STATE);
interrupt_disable_v2_hw(hisi_hba);
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
- stop_phys_v2_hw(hisi_hba);
+ hisi_sas_stop_phys(hisi_hba);
mdelay(10);
@@ -3412,7 +3461,7 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
udelay(10);
if (cnt++ > 10) {
- dev_info(dev, "wait axi bus state to idle timeout!\n");
+ dev_err(dev, "wait axi bus state to idle timeout!\n");
return -1;
}
}
@@ -3425,79 +3474,167 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
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];
- struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ return 0;
+}
- if (sas_phy->enabled)
- start_phy_v2_hw(hisi_hba, phy_no);
+static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type,
+ u8 reg_index, u8 reg_count, u8 *write_data)
+{
+ struct device *dev = hisi_hba->dev;
+ int phy_no, count;
+
+ if (!hisi_hba->sgpio_regs)
+ return -EOPNOTSUPP;
+
+ switch (reg_type) {
+ case SAS_GPIO_REG_TX:
+ count = reg_count * 4;
+ count = min(count, hisi_hba->n_phy);
+
+ for (phy_no = 0; phy_no < count; phy_no++) {
+ /*
+ * GPIO_TX[n] register has the highest numbered drive
+ * of the four in the first byte and the lowest
+ * numbered drive in the fourth byte.
+ * See SFF-8485 Rev. 0.7 Table 24.
+ */
+ void __iomem *reg_addr = hisi_hba->sgpio_regs +
+ reg_index * 4 + phy_no;
+ int data_idx = phy_no + 3 - (phy_no % 4) * 2;
+
+ writeb(write_data[data_idx], reg_addr);
+ }
+
+ break;
+ default:
+ dev_err(dev, "write gpio: unsupported or bad reg type %d\n",
+ reg_type);
+ return -EINVAL;
}
- /* Wait for the PHYs to come up and read the PHY state */
- msleep(1000);
+ return 0;
+}
- state = hisi_sas_read32(hisi_hba, PHY_STATE);
+static void wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba,
+ int delay_ms, int timeout_ms)
+{
+ struct device *dev = hisi_hba->dev;
+ int entries, entries_old = 0, time;
- hisi_sas_rescan_topology(hisi_hba, old_state, state);
+ for (time = 0; time < timeout_ms; time += delay_ms) {
+ entries = hisi_sas_read32(hisi_hba, CQE_SEND_CNT);
+ if (entries == entries_old)
+ break;
+
+ entries_old = entries;
+ msleep(delay_ms);
+ }
+
+ if (time >= timeout_ms) {
+ dev_dbg(dev, "Wait commands complete timeout!\n");
+ return;
+ }
+
+ dev_dbg(dev, "wait commands complete %dms\n", time);
+
+}
+
+static struct attribute *host_v2_hw_attrs[] = {
+ &dev_attr_phy_event_threshold.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS(host_v2_hw);
+
+static const struct attribute_group *sdev_groups_v2_hw[] = {
+ &sas_ata_sdev_attr_group,
+ NULL
+};
+
+static void map_queues_v2_hw(struct Scsi_Host *shost)
+{
+ struct hisi_hba *hisi_hba = shost_priv(shost);
+ struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
+ const struct cpumask *mask;
+ unsigned int queue, cpu;
+
+ for (queue = 0; queue < qmap->nr_queues; queue++) {
+ mask = irq_get_affinity_mask(hisi_hba->irq_map[96 + queue]);
+ if (!mask)
+ continue;
+
+ for_each_cpu(cpu, mask)
+ qmap->mq_map[cpu] = qmap->queue_offset + queue;
+ }
+}
+
+static int check_fw_info_v2_hw(struct hisi_hba *hisi_hba)
+{
+ struct device *dev = hisi_hba->dev;
+
+ if (hisi_hba->n_phy < 0 || hisi_hba->n_phy > 9) {
+ dev_err(dev, "invalid phy number from FW\n");
+ return -EINVAL;
+ }
+
+ if (hisi_hba->queue_count < 0 || hisi_hba->queue_count > 16) {
+ dev_err(dev, "invalid queue count from FW\n");
+ return -EINVAL;
+ }
return 0;
}
+static const struct scsi_host_template sht_v2_hw = {
+ LIBSAS_SHT_BASE_NO_SLAVE_INIT
+ .sdev_configure = hisi_sas_sdev_configure,
+ .scan_finished = hisi_sas_scan_finished,
+ .scan_start = hisi_sas_scan_start,
+ .sg_tablesize = HISI_SAS_SGE_PAGE_CNT,
+ .sdev_init = hisi_sas_sdev_init,
+ .shost_groups = host_v2_hw_groups,
+ .sdev_groups = sdev_groups_v2_hw,
+ .host_reset = hisi_sas_host_reset,
+ .map_queues = map_queues_v2_hw,
+ .host_tagset = 1,
+};
+
static const struct hisi_sas_hw hisi_sas_v2_hw = {
.hw_init = hisi_sas_v2_init,
+ .fw_info_check = check_fw_info_v2_hw,
+ .interrupt_preinit = hisi_sas_v2_interrupt_preinit,
.setup_itct = setup_itct_v2_hw,
.slot_index_alloc = slot_index_alloc_quirk_v2_hw,
.alloc_dev = alloc_dev_quirk_v2_hw,
- .sl_notify = sl_notify_v2_hw,
+ .sl_notify_ssp = sl_notify_ssp_v2_hw,
.get_wideport_bitmap = get_wideport_bitmap_v2_hw,
+ .clear_itct = clear_itct_v2_hw,
.free_device = free_device_v2_hw,
.prep_smp = prep_smp_v2_hw,
.prep_ssp = prep_ssp_v2_hw,
.prep_stp = prep_ata_v2_hw,
.prep_abort = prep_abort_v2_hw,
- .get_free_slot = get_free_slot_v2_hw,
.start_delivery = start_delivery_v2_hw,
- .slot_complete = slot_complete_v2_hw,
.phys_init = phys_init_v2_hw,
- .phy_enable = enable_phy_v2_hw,
+ .phy_start = start_phy_v2_hw,
.phy_disable = disable_phy_v2_hw,
.phy_hard_reset = phy_hard_reset_v2_hw,
+ .get_events = phy_get_events_v2_hw,
.phy_set_linkrate = phy_set_linkrate_v2_hw,
.phy_get_max_linkrate = phy_get_max_linkrate_v2_hw,
- .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V2_HW,
.complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr),
.soft_reset = soft_reset_v2_hw,
+ .get_phys_state = get_phys_state_v2_hw,
+ .write_gpio = write_gpio_v2_hw,
+ .wait_cmds_complete_timeout = wait_cmds_complete_timeout_v2_hw,
+ .sht = &sht_v2_hw,
};
static int hisi_sas_v2_probe(struct platform_device *pdev)
{
- /*
- * Check if we should defer the probe before we probe the
- * upper layer, as it's hard to defer later on.
- */
- int ret = platform_get_irq(pdev, 0);
-
- if (ret < 0) {
- if (ret != -EPROBE_DEFER)
- dev_err(&pdev->dev, "cannot obtain irq\n");
- return ret;
- }
-
return hisi_sas_probe(pdev, &hisi_sas_v2_hw);
}
-static int hisi_sas_v2_remove(struct platform_device *pdev)
-{
- struct sas_ha_struct *sha = platform_get_drvdata(pdev);
- struct hisi_hba *hisi_hba = sha->lldd_ha;
-
- if (timer_pending(&hisi_hba->timer))
- del_timer(&hisi_hba->timer);
-
- return hisi_sas_remove(pdev);
-}
-
static const struct of_device_id sas_v2_of_match[] = {
{ .compatible = "hisilicon,hip06-sas-v2",},
{ .compatible = "hisilicon,hip07-sas-v2",},
@@ -3514,11 +3651,11 @@ MODULE_DEVICE_TABLE(acpi, sas_v2_acpi_match);
static struct platform_driver hisi_sas_v2_driver = {
.probe = hisi_sas_v2_probe,
- .remove = hisi_sas_v2_remove,
+ .remove = hisi_sas_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = sas_v2_of_match,
- .acpi_match_table = ACPI_PTR(sas_v2_acpi_match),
+ .acpi_match_table = sas_v2_acpi_match,
},
};