diff options
Diffstat (limited to 'drivers/scsi/hisi_sas')
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas.h | 13 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_main.c | 50 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 2 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 259 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 257 |
5 files changed, 369 insertions, 212 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 15692ea05ced..83357b0367d8 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -29,7 +29,7 @@ #define HISI_SAS_MAX_PHYS 9 #define HISI_SAS_MAX_QUEUES 32 #define HISI_SAS_QUEUE_SLOTS 512 -#define HISI_SAS_MAX_ITCT_ENTRIES 2048 +#define HISI_SAS_MAX_ITCT_ENTRIES 1024 #define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES #define HISI_SAS_RESET_BIT 0 #define HISI_SAS_REJECT_CMD_BIT 1 @@ -96,6 +96,7 @@ struct hisi_sas_hw_error { int shift; const char *msg; int reg; + const struct hisi_sas_hw_error *sub; }; struct hisi_sas_phy { @@ -197,7 +198,7 @@ struct hisi_sas_hw { int (*slot_complete)(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot); void (*phys_init)(struct hisi_hba *hisi_hba); - void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no); + void (*phy_start)(struct hisi_hba *hisi_hba, int phy_no); void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no); void (*phy_hard_reset)(struct hisi_hba *hisi_hba, int phy_no); void (*get_events)(struct hisi_hba *hisi_hba, int phy_no); @@ -341,7 +342,11 @@ struct hisi_sas_initial_fis { }; struct hisi_sas_breakpoint { - u8 data[128]; /*io128 byte*/ + u8 data[128]; +}; + +struct hisi_sas_sata_breakpoint { + struct hisi_sas_breakpoint tag[32]; }; struct hisi_sas_sge { @@ -419,4 +424,6 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, struct hisi_sas_slot *slot); extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba); +extern void hisi_sas_rst_work_handler(struct work_struct *work); +extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba); #endif diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 37c838be4757..5f503cb09508 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -185,13 +185,16 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, struct domain_device *device = task->dev; struct hisi_sas_device *sas_dev = device->lldd_dev; + if (!task->lldd_task) + return; + + task->lldd_task = NULL; + if (!sas_protocol_ata(task->task_proto)) if (slot->n_elem) dma_unmap_sg(dev, task->scatter, slot->n_elem, task->data_dir); - task->lldd_task = NULL; - if (sas_dev) atomic64_dec(&sas_dev->running_req); } @@ -199,8 +202,8 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, if (slot->buf) dma_pool_free(hisi_hba->buffer_pool, slot->buf, slot->buf_dma); - list_del_init(&slot->entry); + slot->buf = NULL; slot->task = NULL; slot->port = NULL; hisi_sas_slot_index_free(hisi_hba, slot->idx); @@ -401,7 +404,9 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq goto err_out_buf; } + spin_lock_irqsave(&hisi_hba->lock, flags); list_add_tail(&slot->entry, &sas_dev->list); + spin_unlock_irqrestore(&hisi_hba->lock, flags); spin_lock_irqsave(&task->task_state_lock, flags); task->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock_irqrestore(&task->task_state_lock, flags); @@ -505,9 +510,10 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device) { struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct hisi_sas_device *sas_dev = NULL; + unsigned long flags; int i; - spin_lock(&hisi_hba->lock); + spin_lock_irqsave(&hisi_hba->lock, flags); for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) { int queue = i % hisi_hba->queue_count; @@ -524,7 +530,7 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device) break; } } - spin_unlock(&hisi_hba->lock); + spin_unlock_irqrestore(&hisi_hba->lock, flags); return sas_dev; } @@ -761,7 +767,7 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, case PHY_FUNC_LINK_RESET: hisi_hba->hw->phy_disable(hisi_hba, phy_no); msleep(100); - hisi_hba->hw->phy_enable(hisi_hba, phy_no); + hisi_hba->hw->phy_start(hisi_hba, phy_no); break; case PHY_FUNC_DISABLE: @@ -833,7 +839,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, } task->task_done = hisi_sas_task_done; - task->slow_task->timer.function = (TIMER_FUNC_TYPE)hisi_sas_tmf_timedout; + task->slow_task->timer.function = hisi_sas_tmf_timedout; task->slow_task->timer.expires = jiffies + TASK_TIMEOUT*HZ; add_timer(&task->slow_task->timer); @@ -1045,7 +1051,6 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) { - struct sas_ha_struct *sas_ha = &hisi_hba->sha; struct device *dev = hisi_hba->dev; struct Scsi_Host *shost = hisi_hba->shost; u32 old_state, state; @@ -1073,7 +1078,6 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) hisi_sas_release_tasks(hisi_hba); spin_unlock_irqrestore(&hisi_hba->lock, flags); - sas_ha->notify_ha_event(sas_ha, HAE_RESET); clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); /* Init and wait for PHYs to come up and all libsas event finished. */ @@ -1159,7 +1163,7 @@ static int hisi_sas_abort_task(struct sas_task *task) rc = hisi_sas_internal_task_abort(hisi_hba, device, HISI_SAS_INT_ABT_CMD, tag); - if (rc == TMF_RESP_FUNC_FAILED) { + if (rc == TMF_RESP_FUNC_FAILED && task->lldd_task) { spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_do_release_task(hisi_hba, task, slot); spin_unlock_irqrestore(&hisi_hba->lock, flags); @@ -1387,8 +1391,9 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, if (rc) goto err_out_buf; - + spin_lock_irqsave(&hisi_hba->lock, flags); list_add_tail(&slot->entry, &sas_dev->list); + spin_unlock_irqrestore(&hisi_hba->lock, flags); spin_lock_irqsave(&task->task_state_lock, flags); task->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock_irqrestore(&task->task_state_lock, flags); @@ -1446,7 +1451,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, task->dev = device; task->task_proto = device->tproto; task->task_done = hisi_sas_task_done; - task->slow_task->timer.function = (TIMER_FUNC_TYPE)hisi_sas_tmf_timedout; + task->slow_task->timer.function = hisi_sas_tmf_timedout; task->slow_task->timer.expires = jiffies + msecs_to_jiffies(110); add_timer(&task->slow_task->timer); @@ -1469,6 +1474,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, if (slot) slot->task = NULL; dev_err(dev, "internal task abort: timeout.\n"); + goto exit; } } @@ -1540,6 +1546,17 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy) } EXPORT_SYMBOL_GPL(hisi_sas_phy_down); +void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba) +{ + int i; + + for (i = 0; i < hisi_hba->queue_count; i++) { + struct hisi_sas_cq *cq = &hisi_hba->cq[i]; + + tasklet_kill(&cq->tasklet); + } +} +EXPORT_SYMBOL_GPL(hisi_sas_kill_tasklets); struct scsi_transport_template *hisi_sas_stt; EXPORT_SYMBOL_GPL(hisi_sas_stt); @@ -1608,7 +1625,7 @@ void hisi_sas_init_mem(struct hisi_hba *hisi_hba) s = max_command_entries * sizeof(struct hisi_sas_breakpoint); memset(hisi_hba->breakpoint, 0, s); - s = max_command_entries * sizeof(struct hisi_sas_breakpoint) * 2; + s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_sata_breakpoint); memset(hisi_hba->sata_breakpoint, 0, s); } EXPORT_SYMBOL_GPL(hisi_sas_init_mem); @@ -1701,7 +1718,7 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) if (!hisi_hba->initial_fis) goto err_out; - s = max_command_entries * sizeof(struct hisi_sas_breakpoint) * 2; + s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_sata_breakpoint); hisi_hba->sata_breakpoint = dma_alloc_coherent(dev, s, &hisi_hba->sata_breakpoint_dma, GFP_KERNEL); if (!hisi_hba->sata_breakpoint) @@ -1766,7 +1783,7 @@ void hisi_sas_free(struct hisi_hba *hisi_hba) hisi_hba->initial_fis, hisi_hba->initial_fis_dma); - s = max_command_entries * sizeof(struct hisi_sas_breakpoint) * 2; + s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_sata_breakpoint); if (hisi_hba->sata_breakpoint) dma_free_coherent(dev, s, hisi_hba->sata_breakpoint, @@ -1777,13 +1794,14 @@ void hisi_sas_free(struct hisi_hba *hisi_hba) } EXPORT_SYMBOL_GPL(hisi_sas_free); -static void hisi_sas_rst_work_handler(struct work_struct *work) +void hisi_sas_rst_work_handler(struct work_struct *work) { struct hisi_hba *hisi_hba = container_of(work, struct hisi_hba, rst_work); hisi_sas_controller_reset(hisi_hba); } +EXPORT_SYMBOL_GPL(hisi_sas_rst_work_handler); int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba) { diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 9385554e43a6..dc6eca8d6afd 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1857,7 +1857,7 @@ static const struct hisi_sas_hw hisi_sas_v1_hw = { .start_delivery = start_delivery_v1_hw, .slot_complete = slot_complete_v1_hw, .phys_init = phys_init_v1_hw, - .phy_enable = enable_phy_v1_hw, + .phy_start = start_phy_v1_hw, .phy_disable = disable_phy_v1_hw, .phy_hard_reset = phy_hard_reset_v1_hw, .phy_set_linkrate = phy_set_linkrate_v1_hw, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index b1f097dabd01..5d3467fd728d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -406,80 +406,70 @@ 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_acc1b_intr found: \ - Ram address is 0x%08X\n", + .msg = "hgc_dqe_acc1b_intr found: Ram address is 0x%08X\n", .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_acc1b_intr found: \ - Ram address is 0x%08X\n", + .msg = "hgc_iost_acc1b_intr found: Ram address is 0x%08X\n", .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_acc1b_intr found: \ - Ram address is 0x%08X\n", + .msg = "hgc_itct_acc1b_intr found: am address is 0x%08X\n", .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_acc1b_intr found: \ - memory address is 0x%08X\n", + .msg = "hgc_iostl_acc1b_intr found: memory address is 0x%08X\n", .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_acc1b_intr found: \ - memory address is 0x%08X\n", + .msg = "hgc_itctl_acc1b_intr found: memory address is 0x%08X\n", .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_acc1b_intr found: \ - Ram address is 0x%08X\n", + .msg = "hgc_cqe_acc1b_intr found: Ram address is 0x%08X\n", .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_acc1b_intr found: \ - memory address is 0x%08X\n", + .msg = "rxm_mem0_acc1b_intr found: memory address is 0x%08X\n", .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_acc1b_intr found: \ - memory address is 0x%08X\n", + .msg = "rxm_mem1_acc1b_intr found: memory address is 0x%08X\n", .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_acc1b_intr found: \ - memory address is 0x%08X\n", + .msg = "rxm_mem2_acc1b_intr found: memory address is 0x%08X\n", .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_acc1b_intr found: \ - memory address is 0x%08X\n", + .msg = "rxm_mem3_acc1b_intr found: memory address is 0x%08X\n", .reg = HGC_RXM_DFX_STATUS15, }, }; @@ -489,80 +479,70 @@ 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_accbad_intr (0x%x) found: \ - Ram address is 0x%08X\n", + .msg = "hgc_dqe_accbad_intr (0x%x) found: Ram address is 0x%08X\n", .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_accbad_intr (0x%x) found: \ - Ram address is 0x%08X\n", + .msg = "hgc_iost_accbad_intr (0x%x) found: Ram address is 0x%08X\n", .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_accbad_intr (0x%x) found: \ - Ram address is 0x%08X\n", + .msg = "hgc_itct_accbad_intr (0x%x) found: Ram address is 0x%08X\n", .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_accbad_intr (0x%x) found: \ - memory address is 0x%08X\n", + .msg = "hgc_iostl_accbad_intr (0x%x) found: memory address is 0x%08X\n", .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_accbad_intr (0x%x) found: \ - memory address is 0x%08X\n", + .msg = "hgc_itctl_accbad_intr (0x%x) found: memory address is 0x%08X\n", .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_accbad_intr (0x%x) found: \ - Ram address is 0x%08X\n", + .msg = "hgc_cqe_accbad_intr (0x%x) found: Ram address is 0x%08X\n", .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_accbad_intr (0x%x) found: \ - memory address is 0x%08X\n", + .msg = "rxm_mem0_accbad_intr (0x%x) found: memory address is 0x%08X\n", .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_accbad_intr (0x%x) found: \ - memory address is 0x%08X\n", + .msg = "rxm_mem1_accbad_intr (0x%x) found: memory address is 0x%08X\n", .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_accbad_intr (0x%x) found: \ - memory address is 0x%08X\n", + .msg = "rxm_mem2_accbad_intr (0x%x) found: memory address is 0x%08X\n", .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_accbad_intr (0x%x) found: \ - memory address is 0x%08X\n", + .msg = "rxm_mem3_accbad_intr (0x%x) found: memory address is 0x%08X\n", .reg = HGC_RXM_DFX_STATUS15, }, }; @@ -843,8 +823,9 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device) struct hisi_sas_device *sas_dev = NULL; int i, sata_dev = dev_is_sata(device); int sata_idx = -1; + unsigned long flags; - spin_lock(&hisi_hba->lock); + spin_lock_irqsave(&hisi_hba->lock, flags); if (sata_dev) if (!sata_index_alloc_v2_hw(hisi_hba, &sata_idx)) @@ -874,7 +855,7 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device) } out: - spin_unlock(&hisi_hba->lock); + spin_unlock_irqrestore(&hisi_hba->lock, flags); return sas_dev; } @@ -1287,7 +1268,7 @@ static void link_timeout_enable_link(struct timer_list *t) } } - hisi_hba->timer.function = (TIMER_FUNC_TYPE)link_timeout_disable_link; + hisi_hba->timer.function = link_timeout_disable_link; mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(900)); } @@ -1308,13 +1289,13 @@ static void link_timeout_disable_link(struct timer_list *t) } } - hisi_hba->timer.function = (TIMER_FUNC_TYPE)link_timeout_enable_link; + hisi_hba->timer.function = link_timeout_enable_link; mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(100)); } static void set_link_timer_quirk(struct hisi_hba *hisi_hba) { - hisi_hba->timer.function = (TIMER_FUNC_TYPE)link_timeout_disable_link; + hisi_hba->timer.function = link_timeout_disable_link; hisi_hba->timer.expires = jiffies + msecs_to_jiffies(1000); add_timer(&hisi_hba->timer); } @@ -2376,7 +2357,9 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) if (unlikely(aborted)) { ts->stat = SAS_ABORTED_TASK; + spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_task_free(hisi_hba, task, slot); + spin_unlock_irqrestore(&hisi_hba->lock, flags); return -1; } @@ -2951,25 +2934,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" }, + {}, +}; + +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" }, + {}, }; -#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 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) @@ -2977,98 +2993,47 @@ 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_warn(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); - 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); + } else { + dev_warn(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_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]; + 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, ITCT_CLR, 0); + dev_dbg(dev, "clear ITCT ok\n"); + complete(sas_dev->completion); } hisi_sas_write32(hisi_hba, ENT_INT_SRC3, irq_value); @@ -3408,6 +3373,7 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba) interrupt_disable_v2_hw(hisi_hba); hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0); + hisi_sas_kill_tasklets(hisi_hba); hisi_sas_stop_phys(hisi_hba); @@ -3458,7 +3424,7 @@ static const struct hisi_sas_hw hisi_sas_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, @@ -3491,16 +3457,11 @@ 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; - int i; if (timer_pending(&hisi_hba->timer)) del_timer(&hisi_hba->timer); - for (i = 0; i < hisi_hba->queue_count; i++) { - struct hisi_sas_cq *cq = &hisi_hba->cq[i]; - - tasklet_kill(&cq->tasklet); - } + hisi_sas_kill_tasklets(hisi_hba); return hisi_sas_remove(pdev); } diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 3f2f0baf2a5e..19b1f2ffec17 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -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 @@ -135,6 +140,7 @@ #define RX_IDAF_DWORD0 (PORT_BASE + 0xc4) #define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc) #define STP_LINK_TIMER (PORT_BASE + 0x120) +#define CON_CFG_DRIVER (PORT_BASE + 0x130) #define SAS_SSP_CON_TIMER_CFG (PORT_BASE + 0x134) #define SAS_SMP_CON_TIMER_CFG (PORT_BASE + 0x138) #define SAS_STP_CON_TIMER_CFG (PORT_BASE + 0x13c) @@ -154,6 +160,10 @@ #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_INT0_MSK (PORT_BASE + 0x1c0) #define CHL_INT1_MSK (PORT_BASE + 0x1c4) @@ -171,8 +181,11 @@ #define DMA_RX_STATUS (PORT_BASE + 0x2e8) #define DMA_RX_STATUS_BUSY_OFF 0 #define DMA_RX_STATUS_BUSY_MSK (0x1 << DMA_RX_STATUS_BUSY_OFF) +#define ERR_CNT_DWS_LOST (PORT_BASE + 0x380) +#define ERR_CNT_RESET_PROB (PORT_BASE + 0x384) +#define ERR_CNT_INVLD_DW (PORT_BASE + 0x390) +#define ERR_CNT_DISP_ERR (PORT_BASE + 0x398) -#define MAX_ITCT_HW 4096 /* max the hw can support */ #define DEFAULT_ITCT_HW 2048 /* reset value, not reprogrammed */ #if (HISI_SAS_MAX_DEVICES > DEFAULT_ITCT_HW) #error Max ITCT exceeded @@ -377,6 +390,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) /* Global registers init */ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, (u32)((1ULL << hisi_hba->queue_count) - 1)); + hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff0400); hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108); hisi_sas_write32(hisi_hba, CFG_1US_TIMER_TRSH, 0xd); hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1); @@ -388,7 +402,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 0xffffffff); hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xfefefefe); hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xfefefefe); - hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffffffff); + hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xfffe20ff); hisi_sas_write32(hisi_hba, CHNL_PHYUPDOWN_INT_MSK, 0x0); hisi_sas_write32(hisi_hba, CHNL_ENT_INT_MSK, 0x0); hisi_sas_write32(hisi_hba, HGC_COM_INT_MSK, 0x0); @@ -407,7 +421,7 @@ static void init_reg_v3_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, 0xffffffff); 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_INT1_MSK, 0xff87ffff); hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff); hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0); hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0); @@ -422,6 +436,8 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) 0xa03e8); hisi_sas_phy_write32(hisi_hba, i, STP_LINK_TIMER, 0x7f7a120); + hisi_sas_phy_write32(hisi_hba, i, CON_CFG_DRIVER, + 0x2a0a80); } for (i = 0; i < hisi_hba->queue_count; i++) { /* Delivery queue */ @@ -575,35 +591,24 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba, static void free_device_v3_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); + 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 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"); - } + wait_for_completion(sas_dev->completion); + memset(itct, 0, sizeof(struct hisi_sas_itct)); } static void dereg_device_v3_hw(struct hisi_hba *hisi_hba, @@ -755,10 +760,12 @@ static int get_wideport_bitmap_v3_hw(struct hisi_hba *hisi_hba, int port_id) { int i, bitmap = 0; u32 phy_port_num_ma = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA); + u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE); for (i = 0; i < hisi_hba->n_phy; i++) - if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id) - bitmap |= 1 << i; + if (phy_state & BIT(i)) + if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id) + bitmap |= BIT(i); return bitmap; } @@ -988,20 +995,6 @@ err_out_req: return rc; } -static int get_ncq_tag_v3_hw(struct sas_task *task, u32 *tag) -{ - struct ata_queued_cmd *qc = task->uldd_task; - - if (qc) { - if (qc->tf.command == ATA_CMD_FPDMA_WRITE || - qc->tf.command == ATA_CMD_FPDMA_READ) { - *tag = qc->tag; - return 1; - } - } - return 0; -} - static int prep_ata_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) { @@ -1050,7 +1043,7 @@ static int prep_ata_v3_hw(struct hisi_hba *hisi_hba, hdr->dw1 = cpu_to_le32(dw1); /* dw2 */ - if (task->ata_task.use_ncq && get_ncq_tag_v3_hw(task, &hdr_tag)) { + if (task->ata_task.use_ncq && hisi_sas_get_ncq_tag(task, &hdr_tag)) { task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF; } @@ -1276,6 +1269,25 @@ static irqreturn_t int_phy_up_down_bcast_v3_hw(int irq_no, void *p) return res; } +static const struct hisi_sas_hw_error port_axi_error[] = { + { + .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_v3_hw(int irq_no, void *p) { struct hisi_hba *hisi_hba = p; @@ -1301,10 +1313,19 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p) if ((irq_msk & (4 << (phy_no * 4))) && 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); + int i; + + for (i = 0; i < ARRAY_SIZE(port_axi_error); i++) { + const struct hisi_sas_hw_error *error = + &port_axi_error[i]; + + if (!(irq_value1 & error->irq_msk)) + continue; + + 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_INT1, irq_value1); @@ -1331,6 +1352,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) @@ -1414,7 +1543,9 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) ts->resp = SAS_TASK_COMPLETE; if (unlikely(aborted)) { ts->stat = SAS_ABORTED_TASK; + spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_task_free(hisi_hba, task, slot); + spin_unlock_irqrestore(&hisi_hba->lock, flags); return -1; } @@ -1629,6 +1760,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]; @@ -1656,6 +1796,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); @@ -1749,6 +1891,31 @@ static u32 get_phys_state_v3_hw(struct hisi_hba *hisi_hba) return hisi_sas_read32(hisi_hba, PHY_STATE); } +static void phy_get_events_v3_hw(struct hisi_hba *hisi_hba, int phy_no) +{ + 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 reg_value; + + /* loss dword sync */ + reg_value = hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_DWS_LOST); + sphy->loss_of_dword_sync_count += reg_value; + + /* phy reset problem */ + reg_value = hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_RESET_PROB); + sphy->phy_reset_problem_count += reg_value; + + /* invalid dword */ + reg_value = hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_INVLD_DW); + sphy->invalid_dword_count += reg_value; + + /* disparity err */ + reg_value = hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_DISP_ERR); + sphy->running_disparity_error_count += reg_value; + +} + static int soft_reset_v3_hw(struct hisi_hba *hisi_hba) { struct device *dev = hisi_hba->dev; @@ -1757,6 +1924,7 @@ static int soft_reset_v3_hw(struct hisi_hba *hisi_hba) interrupt_disable_v3_hw(hisi_hba); hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0); + hisi_sas_kill_tasklets(hisi_hba); hisi_sas_stop_phys(hisi_hba); @@ -1793,7 +1961,7 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = { .start_delivery = start_delivery_v3_hw, .slot_complete = slot_complete_v3_hw, .phys_init = phys_init_v3_hw, - .phy_enable = enable_phy_v3_hw, + .phy_start = start_phy_v3_hw, .phy_disable = disable_phy_v3_hw, .phy_hard_reset = phy_hard_reset_v3_hw, .phy_get_max_linkrate = phy_get_max_linkrate_v3_hw, @@ -1801,6 +1969,7 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = { .dereg_device = dereg_device_v3_hw, .soft_reset = soft_reset_v3_hw, .get_phys_state = get_phys_state_v3_hw, + .get_events = phy_get_events_v3_hw, }; static struct Scsi_Host * @@ -1817,6 +1986,7 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev) } hisi_hba = shost_priv(shost); + INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler); hisi_hba->hw = &hisi_sas_v3_hw; hisi_hba->pci_dev = pdev; hisi_hba->dev = dev; @@ -1960,11 +2130,11 @@ 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]; free_irq(pci_irq_vector(pdev, i+16), cq); - tasklet_kill(&cq->tasklet); } pci_free_irq_vectors(pdev); } @@ -1980,6 +2150,7 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) sas_remove_host(sha->core.shost); hisi_sas_v3_destroy_irqs(pdev, hisi_hba); + hisi_sas_kill_tasklets(hisi_hba); pci_release_regions(pdev); pci_disable_device(pdev); hisi_sas_free(hisi_hba); |