forked from Minki/linux
scsi: hisi_sas: add v3 hw support for AXI fatal error
Add support for processing AXI bus fatal errors. If AXI bus fatal error happen, do controller reset to recover. 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>
This commit is contained in:
parent
571295f805
commit
fa23140815
@ -53,6 +53,11 @@
|
||||
#define HGC_IOMB_PROC1_STATUS 0x104
|
||||
#define CFG_1US_TIMER_TRSH 0xcc
|
||||
#define CHNL_INT_STATUS 0x148
|
||||
#define HGC_AXI_FIFO_ERR_INFO 0x154
|
||||
#define AXI_ERR_INFO_OFF 0
|
||||
#define AXI_ERR_INFO_MSK (0xff << AXI_ERR_INFO_OFF)
|
||||
#define FIFO_ERR_INFO_OFF 8
|
||||
#define FIFO_ERR_INFO_MSK (0xff << FIFO_ERR_INFO_OFF)
|
||||
#define INT_COAL_EN 0x19c
|
||||
#define OQ_INT_COAL_TIME 0x1a0
|
||||
#define OQ_INT_COAL_CNT 0x1a4
|
||||
@ -1315,6 +1320,114 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
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" },
|
||||
{},
|
||||
};
|
||||
|
||||
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_error[] = {
|
||||
{
|
||||
.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_v3_hw(int irq_no, void *p)
|
||||
{
|
||||
u32 irq_value, irq_msk;
|
||||
struct hisi_hba *hisi_hba = p;
|
||||
struct device *dev = hisi_hba->dev;
|
||||
int i;
|
||||
|
||||
irq_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK3);
|
||||
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, irq_msk | 0x1df00);
|
||||
|
||||
irq_value = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fatal_axi_error); i++) {
|
||||
const struct hisi_sas_hw_error *error = &fatal_axi_error[i];
|
||||
|
||||
if (!(irq_value & error->irq_msk))
|
||||
continue;
|
||||
|
||||
if (error->sub) {
|
||||
const struct hisi_sas_hw_error *sub = error->sub;
|
||||
u32 err_value = hisi_sas_read32(hisi_hba, error->reg);
|
||||
|
||||
for (; sub->msk || sub->msg; sub++) {
|
||||
if (!(err_value & sub->msk))
|
||||
continue;
|
||||
|
||||
dev_warn(dev, "%s error (0x%x) found!\n",
|
||||
sub->msg, irq_value);
|
||||
queue_work(hisi_hba->wq, &hisi_hba->rst_work);
|
||||
}
|
||||
} else {
|
||||
dev_warn(dev, "%s error (0x%x) found!\n",
|
||||
error->msg, 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 & 0x1df00);
|
||||
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, irq_msk);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void
|
||||
slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
|
||||
struct hisi_sas_slot *slot)
|
||||
@ -1615,6 +1728,15 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
|
||||
goto free_phy_irq;
|
||||
}
|
||||
|
||||
rc = devm_request_irq(dev, pci_irq_vector(pdev, 11),
|
||||
fatal_axi_int_v3_hw, 0,
|
||||
DRV_NAME " fatal", hisi_hba);
|
||||
if (rc) {
|
||||
dev_err(dev, "could not request fatal interrupt, rc=%d\n", rc);
|
||||
rc = -ENOENT;
|
||||
goto free_chnl_interrupt;
|
||||
}
|
||||
|
||||
/* Init tasklets for cq only */
|
||||
for (i = 0; i < hisi_hba->queue_count; i++) {
|
||||
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
|
||||
@ -1642,6 +1764,8 @@ free_cq_irqs:
|
||||
|
||||
free_irq(pci_irq_vector(pdev, k+16), cq);
|
||||
}
|
||||
free_irq(pci_irq_vector(pdev, 11), hisi_hba);
|
||||
free_chnl_interrupt:
|
||||
free_irq(pci_irq_vector(pdev, 2), hisi_hba);
|
||||
free_phy_irq:
|
||||
free_irq(pci_irq_vector(pdev, 1), hisi_hba);
|
||||
@ -1974,6 +2098,7 @@ hisi_sas_v3_destroy_irqs(struct pci_dev *pdev, struct hisi_hba *hisi_hba)
|
||||
|
||||
free_irq(pci_irq_vector(pdev, 1), hisi_hba);
|
||||
free_irq(pci_irq_vector(pdev, 2), hisi_hba);
|
||||
free_irq(pci_irq_vector(pdev, 11), hisi_hba);
|
||||
for (i = 0; i < hisi_hba->queue_count; i++) {
|
||||
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user