diff options
Diffstat (limited to 'drivers/scsi/hisi_sas')
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas.h | 14 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_main.c | 319 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 23 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 21 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 290 |
5 files changed, 357 insertions, 310 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 7052a5d45f7f..6c7d2e201abe 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -16,6 +16,7 @@ #include <linux/clk.h> #include <linux/dmapool.h> #include <linux/iopoll.h> +#include <linux/lcm.h> #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of_address.h> @@ -199,17 +200,17 @@ struct hisi_sas_slot { int dlvry_queue_slot; int cmplt_queue; int cmplt_queue_slot; - int idx; int abort; int ready; - void *buf; - dma_addr_t buf_dma; void *cmd_hdr; dma_addr_t cmd_hdr_dma; - struct work_struct abort_slot; struct timer_list internal_abort_timer; bool is_internal; struct hisi_sas_tmf_task *tmf; + /* Do not reorder/change members after here */ + void *buf; + dma_addr_t buf_dma; + int idx; }; struct hisi_sas_hw { @@ -277,6 +278,7 @@ struct hisi_hba { int n_phy; spinlock_t lock; + struct semaphore sem; struct timer_list timer; struct workqueue_struct *wq; @@ -298,7 +300,6 @@ struct hisi_hba { int queue_count; - struct dma_pool *buffer_pool; struct hisi_sas_device devices[HISI_SAS_MAX_DEVICES]; struct hisi_sas_cmd_hdr *cmd_hdr[HISI_SAS_MAX_QUEUES]; dma_addr_t cmd_hdr_dma[HISI_SAS_MAX_QUEUES]; @@ -319,6 +320,7 @@ struct hisi_hba { const struct hisi_sas_hw *hw; /* Low level hw interface */ unsigned long sata_dev_bitmap[BITS_TO_LONGS(HISI_SAS_MAX_DEVICES)]; struct work_struct rst_work; + u32 phy_state; }; /* Generic HW DMA host memory structures */ @@ -479,4 +481,6 @@ extern bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy, enum hisi_sas_phy_event event); extern void hisi_sas_release_tasks(struct hisi_hba *hisi_hba); extern u8 hisi_sas_get_prog_phy_linkrate_mask(enum sas_linkrate max); +extern void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba); +extern void hisi_sas_controller_reset_done(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 6f562974f8f6..a4e2e6aa9a6b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -242,20 +242,16 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, task->data_dir); } - if (slot->buf) - dma_pool_free(hisi_hba->buffer_pool, slot->buf, slot->buf_dma); spin_lock_irqsave(&dq->lock, flags); list_del_init(&slot->entry); spin_unlock_irqrestore(&dq->lock, flags); - slot->buf = NULL; - slot->task = NULL; - slot->port = NULL; + + memset(slot, 0, offsetof(struct hisi_sas_slot, buf)); + spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_index_free(hisi_hba, slot->idx); spin_unlock_irqrestore(&hisi_hba->lock, flags); - - /* slot memory is fully zeroed when it is reused */ } EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free); @@ -285,40 +281,6 @@ static void hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba, device_id, abort_flag, tag_to_abort); } -/* - * This function will issue an abort TMF regardless of whether the - * task is in the sdev or not. Then it will do the task complete - * cleanup and callbacks. - */ -static void hisi_sas_slot_abort(struct work_struct *work) -{ - struct hisi_sas_slot *abort_slot = - container_of(work, struct hisi_sas_slot, abort_slot); - struct sas_task *task = abort_slot->task; - struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev); - struct scsi_cmnd *cmnd = task->uldd_task; - struct hisi_sas_tmf_task tmf_task; - struct scsi_lun lun; - struct device *dev = hisi_hba->dev; - int tag = abort_slot->idx; - - if (!(task->task_proto & SAS_PROTOCOL_SSP)) { - dev_err(dev, "cannot abort slot for non-ssp task\n"); - goto out; - } - - int_to_scsilun(cmnd->device->lun, &lun); - tmf_task.tmf = TMF_ABORT_TASK; - tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag); - - hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, &tmf_task); -out: - /* Do cleanup for this task */ - hisi_sas_slot_task_free(hisi_hba, task, abort_slot); - if (task->task_done) - task->task_done(task); -} - static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq **dq_pointer, bool is_tmf, struct hisi_sas_tmf_task *tmf, @@ -334,8 +296,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct device *dev = hisi_hba->dev; int dlvry_queue_slot, dlvry_queue, rc, slot_idx; int n_elem = 0, n_elem_req = 0, n_elem_resp = 0; - unsigned long flags, flags_dq; struct hisi_sas_dq *dq; + unsigned long flags; int wr_q_index; if (!sas_port) { @@ -430,30 +392,22 @@ static int hisi_sas_task_prep(struct sas_task *task, goto err_out_dma_unmap; slot = &hisi_hba->slot_info[slot_idx]; - memset(slot, 0, sizeof(struct hisi_sas_slot)); - - slot->buf = dma_pool_alloc(hisi_hba->buffer_pool, - GFP_ATOMIC, &slot->buf_dma); - if (!slot->buf) { - rc = -ENOMEM; - goto err_out_tag; - } - spin_lock_irqsave(&dq->lock, flags_dq); + spin_lock_irqsave(&dq->lock, flags); wr_q_index = hisi_hba->hw->get_free_slot(hisi_hba, dq); if (wr_q_index < 0) { - spin_unlock_irqrestore(&dq->lock, flags_dq); + spin_unlock_irqrestore(&dq->lock, flags); rc = -EAGAIN; - goto err_out_buf; + goto err_out_tag; } list_add_tail(&slot->delivery, &dq->list); - spin_unlock_irqrestore(&dq->lock, flags_dq); + list_add_tail(&slot->entry, &sas_dev->list); + spin_unlock_irqrestore(&dq->lock, flags); dlvry_queue = dq->id; dlvry_queue_slot = wr_q_index; - slot->idx = slot_idx; slot->n_elem = n_elem; slot->dlvry_queue = dlvry_queue; slot->dlvry_queue_slot = dlvry_queue_slot; @@ -464,7 +418,6 @@ static int hisi_sas_task_prep(struct sas_task *task, slot->tmf = tmf; slot->is_internal = is_tmf; task->lldd_task = slot; - INIT_WORK(&slot->abort_slot, hisi_sas_slot_abort); memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr)); memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ); @@ -488,21 +441,15 @@ static int hisi_sas_task_prep(struct sas_task *task, break; } - spin_lock_irqsave(&dq->lock, flags); - list_add_tail(&slot->entry, &sas_dev->list); - spin_unlock_irqrestore(&dq->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); ++(*pass); - slot->ready = 1; + WRITE_ONCE(slot->ready, 1); return 0; -err_out_buf: - dma_pool_free(hisi_hba->buffer_pool, slot->buf, - slot->buf_dma); err_out_tag: spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_index_free(hisi_hba, slot_idx); @@ -536,8 +483,13 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, struct device *dev = hisi_hba->dev; struct hisi_sas_dq *dq = NULL; - if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) - return -EINVAL; + if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) { + if (in_softirq()) + return -EINVAL; + + down(&hisi_hba->sem); + up(&hisi_hba->sem); + } /* protect task_prep and start_delivery sequence */ rc = hisi_sas_task_prep(task, &dq, is_tmf, tmf, &pass); @@ -819,6 +771,8 @@ static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no) for (i = 0; i < HISI_PHYES_NUM; i++) INIT_WORK(&phy->works[i], hisi_sas_phye_fns[i]); + + spin_lock_init(&phy->lock); } static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy) @@ -862,7 +816,6 @@ static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, struct sas_task hisi_sas_slot_task_free(hisi_hba, task, slot); } -/* hisi_hba.lock should be locked */ static void hisi_sas_release_task(struct hisi_hba *hisi_hba, struct domain_device *device) { @@ -914,7 +867,9 @@ static void hisi_sas_dev_gone(struct domain_device *device) hisi_sas_dereg_device(hisi_hba, device); + down(&hisi_hba->sem); hisi_hba->hw->clear_itct(hisi_hba, sas_dev); + up(&hisi_hba->sem); device->lldd_dev = NULL; } @@ -1351,21 +1306,12 @@ static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba) } } -static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) +void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba) { - struct device *dev = hisi_hba->dev; struct Scsi_Host *shost = hisi_hba->shost; - u32 old_state, state; - int rc; - - if (!hisi_hba->hw->soft_reset) - return -1; - if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) - return -1; - - dev_info(dev, "controller resetting...\n"); - old_state = hisi_hba->hw->get_phys_state(hisi_hba); + down(&hisi_hba->sem); + hisi_hba->phy_state = hisi_hba->hw->get_phys_state(hisi_hba); scsi_block_requests(shost); hisi_hba->hw->wait_cmds_complete_timeout(hisi_hba, 100, 5000); @@ -1374,34 +1320,61 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) del_timer_sync(&hisi_hba->timer); set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); - rc = hisi_hba->hw->soft_reset(hisi_hba); - if (rc) { - dev_warn(dev, "controller reset failed (%d)\n", rc); - clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); - scsi_unblock_requests(shost); - goto out; - } +} +EXPORT_SYMBOL_GPL(hisi_sas_controller_reset_prepare); - clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); +void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba) +{ + struct Scsi_Host *shost = hisi_hba->shost; + u32 state; /* Init and wait for PHYs to come up and all libsas event finished. */ hisi_hba->hw->phys_init(hisi_hba); msleep(1000); hisi_sas_refresh_port_id(hisi_hba); + clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); + up(&hisi_hba->sem); if (hisi_hba->reject_stp_links_msk) hisi_sas_terminate_stp_reject(hisi_hba); hisi_sas_reset_init_all_devices(hisi_hba); scsi_unblock_requests(shost); + clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); state = hisi_hba->hw->get_phys_state(hisi_hba); - hisi_sas_rescan_topology(hisi_hba, old_state, state); - dev_info(dev, "controller reset complete\n"); + hisi_sas_rescan_topology(hisi_hba, hisi_hba->phy_state, state); +} +EXPORT_SYMBOL_GPL(hisi_sas_controller_reset_done); -out: - clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); +static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) +{ + struct device *dev = hisi_hba->dev; + struct Scsi_Host *shost = hisi_hba->shost; + int rc; - return rc; + if (!hisi_hba->hw->soft_reset) + return -1; + + if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) + return -1; + + dev_info(dev, "controller resetting...\n"); + hisi_sas_controller_reset_prepare(hisi_hba); + + rc = hisi_hba->hw->soft_reset(hisi_hba); + if (rc) { + dev_warn(dev, "controller reset failed (%d)\n", rc); + clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); + up(&hisi_hba->sem); + scsi_unblock_requests(shost); + clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); + return rc; + } + + hisi_sas_controller_reset_done(hisi_hba); + dev_info(dev, "controller reset complete\n"); + + return 0; } static int hisi_sas_abort_task(struct sas_task *task) @@ -1644,14 +1617,32 @@ out: static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha) { struct hisi_hba *hisi_hba = sas_ha->lldd_ha; + struct device *dev = hisi_hba->dev; HISI_SAS_DECLARE_RST_WORK_ON_STACK(r); + int rc, i; queue_work(hisi_hba->wq, &r.work); wait_for_completion(r.completion); - if (r.done) - return TMF_RESP_FUNC_COMPLETE; + if (!r.done) + return TMF_RESP_FUNC_FAILED; + + for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { + struct hisi_sas_device *sas_dev = &hisi_hba->devices[i]; + struct domain_device *device = sas_dev->sas_device; - return TMF_RESP_FUNC_FAILED; + if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device || + DEV_IS_EXPANDER(device->dev_type)) + continue; + + rc = hisi_sas_debug_I_T_nexus_reset(device); + if (rc != TMF_RESP_FUNC_COMPLETE) + dev_info(dev, "clear nexus ha: for device[%d] rc=%d\n", + sas_dev->device_id, rc); + } + + hisi_sas_release_tasks(hisi_hba); + + return TMF_RESP_FUNC_COMPLETE; } static int hisi_sas_query_task(struct sas_task *task) @@ -1723,21 +1714,13 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, spin_unlock_irqrestore(&hisi_hba->lock, flags); slot = &hisi_hba->slot_info[slot_idx]; - memset(slot, 0, sizeof(struct hisi_sas_slot)); - - slot->buf = dma_pool_alloc(hisi_hba->buffer_pool, - GFP_ATOMIC, &slot->buf_dma); - if (!slot->buf) { - rc = -ENOMEM; - goto err_out_tag; - } spin_lock_irqsave(&dq->lock, flags_dq); wr_q_index = hisi_hba->hw->get_free_slot(hisi_hba, dq); if (wr_q_index < 0) { spin_unlock_irqrestore(&dq->lock, flags_dq); rc = -EAGAIN; - goto err_out_buf; + goto err_out_tag; } list_add_tail(&slot->delivery, &dq->list); spin_unlock_irqrestore(&dq->lock, flags_dq); @@ -1745,7 +1728,6 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, dlvry_queue = dq->id; dlvry_queue_slot = wr_q_index; - slot->idx = slot_idx; slot->n_elem = n_elem; slot->dlvry_queue = dlvry_queue; slot->dlvry_queue_slot = dlvry_queue_slot; @@ -1767,7 +1749,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, task->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock_irqrestore(&task->task_state_lock, flags); - slot->ready = 1; + WRITE_ONCE(slot->ready, 1); /* send abort command to the chip */ spin_lock_irqsave(&dq->lock, flags); list_add_tail(&slot->entry, &sas_dev->list); @@ -1776,9 +1758,6 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, return 0; -err_out_buf: - dma_pool_free(hisi_hba->buffer_pool, slot->buf, - slot->buf_dma); err_out_tag: spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_index_free(hisi_hba, slot_idx); @@ -1919,7 +1898,8 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy) } else { struct hisi_sas_port *port = phy->port; - if (phy->in_reset) { + if (test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags) || + phy->in_reset) { dev_info(dev, "ignore flutter phy%d down\n", phy_no); return; } @@ -2014,8 +1994,11 @@ EXPORT_SYMBOL_GPL(hisi_sas_init_mem); int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) { struct device *dev = hisi_hba->dev; - int i, s, max_command_entries = hisi_hba->hw->max_command_entries; + int i, j, s, max_command_entries = hisi_hba->hw->max_command_entries; + int max_command_entries_ru, sz_slot_buf_ru; + int blk_cnt, slots_per_blk; + sema_init(&hisi_hba->sem, 1); spin_lock_init(&hisi_hba->lock); for (i = 0; i < hisi_hba->n_phy; i++) { hisi_sas_phy_init(hisi_hba, i); @@ -2045,29 +2028,27 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) /* Delivery queue */ s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; - hisi_hba->cmd_hdr[i] = dma_alloc_coherent(dev, s, - &hisi_hba->cmd_hdr_dma[i], GFP_KERNEL); + hisi_hba->cmd_hdr[i] = dmam_alloc_coherent(dev, s, + &hisi_hba->cmd_hdr_dma[i], + GFP_KERNEL); if (!hisi_hba->cmd_hdr[i]) goto err_out; /* Completion queue */ s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; - hisi_hba->complete_hdr[i] = dma_alloc_coherent(dev, s, - &hisi_hba->complete_hdr_dma[i], GFP_KERNEL); + hisi_hba->complete_hdr[i] = dmam_alloc_coherent(dev, s, + &hisi_hba->complete_hdr_dma[i], + GFP_KERNEL); if (!hisi_hba->complete_hdr[i]) goto err_out; } - s = sizeof(struct hisi_sas_slot_buf_table); - hisi_hba->buffer_pool = dma_pool_create("dma_buffer", dev, s, 16, 0); - if (!hisi_hba->buffer_pool) - goto err_out; - s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct); - hisi_hba->itct = dma_zalloc_coherent(dev, s, &hisi_hba->itct_dma, - GFP_KERNEL); + hisi_hba->itct = dmam_alloc_coherent(dev, s, &hisi_hba->itct_dma, + GFP_KERNEL); if (!hisi_hba->itct) goto err_out; + memset(hisi_hba->itct, 0, s); hisi_hba->slot_info = devm_kcalloc(dev, max_command_entries, sizeof(struct hisi_sas_slot), @@ -2075,15 +2056,45 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) if (!hisi_hba->slot_info) goto err_out; + /* roundup to avoid overly large block size */ + max_command_entries_ru = roundup(max_command_entries, 64); + sz_slot_buf_ru = roundup(sizeof(struct hisi_sas_slot_buf_table), 64); + s = lcm(max_command_entries_ru, sz_slot_buf_ru); + blk_cnt = (max_command_entries_ru * sz_slot_buf_ru) / s; + slots_per_blk = s / sz_slot_buf_ru; + for (i = 0; i < blk_cnt; i++) { + struct hisi_sas_slot_buf_table *buf; + dma_addr_t buf_dma; + int slot_index = i * slots_per_blk; + + buf = dmam_alloc_coherent(dev, s, &buf_dma, GFP_KERNEL); + if (!buf) + goto err_out; + memset(buf, 0, s); + + for (j = 0; j < slots_per_blk; j++, slot_index++) { + struct hisi_sas_slot *slot; + + slot = &hisi_hba->slot_info[slot_index]; + slot->buf = buf; + slot->buf_dma = buf_dma; + slot->idx = slot_index; + + buf++; + buf_dma += sizeof(*buf); + } + } + s = max_command_entries * sizeof(struct hisi_sas_iost); - hisi_hba->iost = dma_alloc_coherent(dev, s, &hisi_hba->iost_dma, - GFP_KERNEL); + hisi_hba->iost = dmam_alloc_coherent(dev, s, &hisi_hba->iost_dma, + GFP_KERNEL); if (!hisi_hba->iost) goto err_out; s = max_command_entries * sizeof(struct hisi_sas_breakpoint); - hisi_hba->breakpoint = dma_alloc_coherent(dev, s, - &hisi_hba->breakpoint_dma, GFP_KERNEL); + hisi_hba->breakpoint = dmam_alloc_coherent(dev, s, + &hisi_hba->breakpoint_dma, + GFP_KERNEL); if (!hisi_hba->breakpoint) goto err_out; @@ -2094,14 +2105,16 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) goto err_out; s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS; - hisi_hba->initial_fis = dma_alloc_coherent(dev, s, - &hisi_hba->initial_fis_dma, GFP_KERNEL); + hisi_hba->initial_fis = dmam_alloc_coherent(dev, s, + &hisi_hba->initial_fis_dma, + GFP_KERNEL); if (!hisi_hba->initial_fis) goto err_out; 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); + hisi_hba->sata_breakpoint = dmam_alloc_coherent(dev, s, + &hisi_hba->sata_breakpoint_dma, + GFP_KERNEL); if (!hisi_hba->sata_breakpoint) goto err_out; hisi_sas_init_mem(hisi_hba); @@ -2122,54 +2135,6 @@ EXPORT_SYMBOL_GPL(hisi_sas_alloc); void hisi_sas_free(struct hisi_hba *hisi_hba) { - struct device *dev = hisi_hba->dev; - int i, s, max_command_entries = hisi_hba->hw->max_command_entries; - - for (i = 0; i < hisi_hba->queue_count; i++) { - s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; - if (hisi_hba->cmd_hdr[i]) - dma_free_coherent(dev, s, - hisi_hba->cmd_hdr[i], - hisi_hba->cmd_hdr_dma[i]); - - s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; - if (hisi_hba->complete_hdr[i]) - dma_free_coherent(dev, s, - hisi_hba->complete_hdr[i], - hisi_hba->complete_hdr_dma[i]); - } - - dma_pool_destroy(hisi_hba->buffer_pool); - - s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct); - if (hisi_hba->itct) - dma_free_coherent(dev, s, - hisi_hba->itct, hisi_hba->itct_dma); - - s = max_command_entries * sizeof(struct hisi_sas_iost); - if (hisi_hba->iost) - dma_free_coherent(dev, s, - hisi_hba->iost, hisi_hba->iost_dma); - - s = max_command_entries * sizeof(struct hisi_sas_breakpoint); - if (hisi_hba->breakpoint) - dma_free_coherent(dev, s, - hisi_hba->breakpoint, - hisi_hba->breakpoint_dma); - - - s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS; - if (hisi_hba->initial_fis) - dma_free_coherent(dev, s, - hisi_hba->initial_fis, - hisi_hba->initial_fis_dma); - - 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, - hisi_hba->sata_breakpoint_dma); - if (hisi_hba->wq) destroy_workqueue(hisi_hba->wq); } diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 89ab18c1959c..8f60f0e04599 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -903,23 +903,28 @@ get_free_slot_v1_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq) static void start_delivery_v1_hw(struct hisi_sas_dq *dq) { struct hisi_hba *hisi_hba = dq->hisi_hba; - struct hisi_sas_slot *s, *s1; + struct hisi_sas_slot *s, *s1, *s2 = NULL; struct list_head *dq_list; int dlvry_queue = dq->id; - int wp, count = 0; + int wp; dq_list = &dq->list; list_for_each_entry_safe(s, s1, &dq->list, delivery) { if (!s->ready) break; - count++; - wp = (s->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS; + s2 = s; list_del(&s->delivery); } - if (!count) + if (!s2) return; + /* + * Ensure that memories for slots built on other CPUs is observed. + */ + smp_rmb(); + wp = (s2->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS; + hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), wp); } @@ -1296,11 +1301,8 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba, !(cmplt_hdr_data & CMPLT_HDR_RSPNS_XFRD_MSK)) { slot_err_v1_hw(hisi_hba, task, slot); - if (unlikely(slot->abort)) { - queue_work(hisi_hba->wq, &slot->abort_slot); - /* immediately return and do not complete */ + if (unlikely(slot->abort)) return ts->stat; - } goto out; } @@ -1469,7 +1471,8 @@ static irqreturn_t int_bcast_v1_hw(int irq, void *p) goto end; } - sha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); + if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) + sha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); end: hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 213c530e63f2..9c5c5a601332 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1665,23 +1665,28 @@ get_free_slot_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq) static void start_delivery_v2_hw(struct hisi_sas_dq *dq) { struct hisi_hba *hisi_hba = dq->hisi_hba; - struct hisi_sas_slot *s, *s1; + struct hisi_sas_slot *s, *s1, *s2 = NULL; struct list_head *dq_list; int dlvry_queue = dq->id; - int wp, count = 0; + int wp; dq_list = &dq->list; list_for_each_entry_safe(s, s1, &dq->list, delivery) { if (!s->ready) break; - count++; - wp = (s->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS; + s2 = s; list_del(&s->delivery); } - if (!count) + if (!s2) return; + /* + * Ensure that memories for slots built on other CPUs is observed. + */ + smp_rmb(); + wp = (s2->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS; + hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), wp); } @@ -2840,7 +2845,8 @@ static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba) 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) + if ((bcast_status & RX_BCAST_CHG_MSK) && + !test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_SL_RX_BCST_ACK_MSK); @@ -3234,8 +3240,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p) 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); + hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); res = IRQ_NONE; goto end; } diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 9f1e2d03f914..08b503e274b8 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -51,7 +51,6 @@ #define CFG_ABT_SET_IPTT_DONE 0xd8 #define CFG_ABT_SET_IPTT_DONE_OFF 0 #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 @@ -121,6 +120,8 @@ #define PHY_CFG_ENA_MSK (0x1 << PHY_CFG_ENA_OFF) #define PHY_CFG_DC_OPT_OFF 2 #define PHY_CFG_DC_OPT_MSK (0x1 << PHY_CFG_DC_OPT_OFF) +#define PHY_CFG_PHY_RST_OFF 3 +#define PHY_CFG_PHY_RST_MSK (0x1 << PHY_CFG_PHY_RST_OFF) #define PROG_PHY_LINK_RATE (PORT_BASE + 0x8) #define PHY_CTRL (PORT_BASE + 0x14) #define PHY_CTRL_RESET_OFF 0 @@ -131,6 +132,9 @@ #define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF) #define SL_CTA_OFF 17 #define SL_CTA_MSK (0x1 << SL_CTA_OFF) +#define RX_PRIMS_STATUS (PORT_BASE + 0x98) +#define RX_BCAST_CHG_OFF 1 +#define RX_BCAST_CHG_MSK (0x1 << RX_BCAST_CHG_OFF) #define TX_ID_DWORD0 (PORT_BASE + 0x9c) #define TX_ID_DWORD1 (PORT_BASE + 0xa0) #define TX_ID_DWORD2 (PORT_BASE + 0xa4) @@ -206,6 +210,8 @@ #define AXI_MASTER_CFG_BASE (0x5000) #define AM_CTRL_GLOBAL (0x0) +#define AM_CTRL_SHUTDOWN_REQ_OFF 0 +#define AM_CTRL_SHUTDOWN_REQ_MSK (0x1 << AM_CTRL_SHUTDOWN_REQ_OFF) #define AM_CURR_TRANS_RETURN (0x150) #define AM_CFG_MAX_TRANS (0x5010) @@ -425,7 +431,6 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) (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); hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x1); hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x1); @@ -486,6 +491,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, i, SL_RX_BCAST_CHK_MSK, 0x0); hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x1); hisi_sas_phy_write32(hisi_hba, i, STP_LINK_TIMER, 0x7f7a120); + hisi_sas_phy_write32(hisi_hba, i, CON_CFG_DRIVER, 0x2a0a01); /* used for 12G negotiate */ hisi_sas_phy_write32(hisi_hba, i, COARSETUNE_TIME, 0x1e); @@ -758,15 +764,25 @@ static void enable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG); cfg |= PHY_CFG_ENA_MSK; + cfg &= ~PHY_CFG_PHY_RST_MSK; hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); } static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) { u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG); + u32 state; cfg &= ~PHY_CFG_ENA_MSK; hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); + + mdelay(50); + + state = hisi_sas_read32(hisi_hba, PHY_STATE); + if (state & BIT(phy_no)) { + cfg |= PHY_CFG_PHY_RST_MSK; + hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); + } } static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) @@ -866,23 +882,28 @@ get_free_slot_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq) static void start_delivery_v3_hw(struct hisi_sas_dq *dq) { struct hisi_hba *hisi_hba = dq->hisi_hba; - struct hisi_sas_slot *s, *s1; + struct hisi_sas_slot *s, *s1, *s2 = NULL; struct list_head *dq_list; int dlvry_queue = dq->id; - int wp, count = 0; + int wp; dq_list = &dq->list; list_for_each_entry_safe(s, s1, &dq->list, delivery) { if (!s->ready) break; - count++; - wp = (s->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS; + s2 = s; list_del(&s->delivery); } - if (!count) + if (!s2) return; + /* + * Ensure that memories for slots built on other CPUs is observed. + */ + smp_rmb(); + wp = (s2->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS; + hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), wp); } @@ -1170,6 +1191,16 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) dev_info(dev, "phyup: phy%d link_rate=%d(sata)\n", phy_no, link_rate); initial_fis = &hisi_hba->initial_fis[phy_no]; fis = &initial_fis->fis; + + /* 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); + hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); + res = IRQ_NONE; + goto end; + } + sas_phy->oob_mode = SATA_OOB_MODE; attached_sas_addr[0] = 0x50; attached_sas_addr[7] = phy_no; @@ -1256,9 +1287,13 @@ static irqreturn_t phy_bcast_v3_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); - sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); + bcast_status = hisi_sas_phy_read32(hisi_hba, phy_no, RX_PRIMS_STATUS); + if ((bcast_status & RX_BCAST_CHG_MSK) && + !test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) + sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); 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); @@ -1327,11 +1362,77 @@ static const struct hisi_sas_hw_error port_axi_error[] = { }, }; -static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p) +static void handle_chl_int1_v3_hw(struct hisi_hba *hisi_hba, int phy_no) { - struct hisi_hba *hisi_hba = p; + u32 irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT1); + u32 irq_msk = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT1_MSK); struct device *dev = hisi_hba->dev; + int i; + + irq_value &= ~irq_msk; + if (!irq_value) + return; + + for (i = 0; i < ARRAY_SIZE(port_axi_error); i++) { + const struct hisi_sas_hw_error *error = &port_axi_error[i]; + + if (!(irq_value & error->irq_msk)) + continue; + + dev_err(dev, "%s error (phy%d 0x%x) found!\n", + error->msg, phy_no, irq_value); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); + } + + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT1, irq_value); +} + +static void handle_chl_int2_v3_hw(struct hisi_hba *hisi_hba, int phy_no) +{ + u32 irq_msk = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2_MSK); + u32 irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2); + struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct pci_dev *pci_dev = hisi_hba->pci_dev; + struct device *dev = hisi_hba->dev; + + irq_value &= ~irq_msk; + if (!irq_value) + return; + + if (irq_value & 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); + } + + if (irq_value & BIT(CHL_INT2_STP_LINK_TIMEOUT_OFF)) { + u32 reg_value = hisi_sas_phy_read32(hisi_hba, phy_no, + STP_LINK_TIMEOUT_STATE); + + dev_warn(dev, "phy%d stp link timeout (0x%x)\n", + phy_no, reg_value); + if (reg_value & BIT(4)) + hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); + } + + if ((irq_value & BIT(CHL_INT2_RX_INVLD_DW_OFF)) && + (pci_dev->revision == 0x20)) { + u32 reg_value; + int rc; + + rc = hisi_sas_read32_poll_timeout_atomic( + HILINK_ERR_DFX, reg_value, + !((reg_value >> 8) & BIT(phy_no)), + 1000, 10000); + if (rc) + hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); + } + + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2, irq_value); +} + +static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p) +{ + struct hisi_hba *hisi_hba = p; u32 irq_msk; int phy_no = 0; @@ -1341,84 +1442,12 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p) while (irq_msk) { 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); - u32 irq_msk1 = hisi_sas_phy_read32(hisi_hba, phy_no, - CHL_INT1_MSK); - u32 irq_msk2 = hisi_sas_phy_read32(hisi_hba, phy_no, - CHL_INT2_MSK); - - irq_value1 &= ~irq_msk1; - irq_value2 &= ~irq_msk2; - - if ((irq_msk & (4 << (phy_no * 4))) && - 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_err(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); - } - if (irq_msk & (8 << (phy_no * 4)) && irq_value2) { - struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; + if (irq_msk & (4 << (phy_no * 4))) + handle_chl_int1_v3_hw(hisi_hba, 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); - - } - - if (irq_value2 & BIT(CHL_INT2_STP_LINK_TIMEOUT_OFF)) { - u32 reg_value = hisi_sas_phy_read32(hisi_hba, - phy_no, STP_LINK_TIMEOUT_STATE); - - dev_warn(dev, "phy%d stp link timeout (0x%x)\n", - phy_no, reg_value); - if (reg_value & BIT(4)) - hisi_sas_notify_phy_event(phy, - HISI_PHYE_LINK_RESET); - } - - hisi_sas_phy_write32(hisi_hba, phy_no, - CHL_INT2, irq_value2); - - if ((irq_value2 & BIT(CHL_INT2_RX_INVLD_DW_OFF)) && - (pci_dev->revision == 0x20)) { - u32 reg_value; - int rc; - - rc = hisi_sas_read32_poll_timeout_atomic( - HILINK_ERR_DFX, reg_value, - !((reg_value >> 8) & BIT(phy_no)), - 1000, 10000); - if (rc) { - disable_phy_v3_hw(hisi_hba, phy_no); - hisi_sas_phy_write32(hisi_hba, phy_no, - CHL_INT2, - BIT(CHL_INT2_RX_INVLD_DW_OFF)); - hisi_sas_phy_read32(hisi_hba, phy_no, - ERR_CNT_INVLD_DW); - mdelay(1); - enable_phy_v3_hw(hisi_hba, phy_no); - } - } - } + if (irq_msk & (8 << (phy_no * 4))) + handle_chl_int2_v3_hw(hisi_hba, phy_no); if (irq_msk & (2 << (phy_no * 4)) && irq_value0) { hisi_sas_phy_write32(hisi_hba, phy_no, @@ -1964,11 +1993,11 @@ static void phy_get_events_v3_hw(struct hisi_hba *hisi_hba, int phy_no) } -static int soft_reset_v3_hw(struct hisi_hba *hisi_hba) +static int disable_host_v3_hw(struct hisi_hba *hisi_hba) { struct device *dev = hisi_hba->dev; + u32 status, reg_val; int rc; - u32 status; interrupt_disable_v3_hw(hisi_hba); hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0); @@ -1978,14 +2007,32 @@ static int soft_reset_v3_hw(struct hisi_hba *hisi_hba) mdelay(10); - hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE + AM_CTRL_GLOBAL, 0x1); + reg_val = hisi_sas_read32(hisi_hba, AXI_MASTER_CFG_BASE + + AM_CTRL_GLOBAL); + reg_val |= AM_CTRL_SHUTDOWN_REQ_MSK; + hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE + + AM_CTRL_GLOBAL, reg_val); /* wait until bus idle */ rc = hisi_sas_read32_poll_timeout(AXI_MASTER_CFG_BASE + AM_CURR_TRANS_RETURN, status, status == 0x3, 10, 100); if (rc) { - dev_err(dev, "axi bus is not idle, rc = %d\n", rc); + dev_err(dev, "axi bus is not idle, rc=%d\n", rc); + return rc; + } + + return 0; +} + +static int soft_reset_v3_hw(struct hisi_hba *hisi_hba) +{ + struct device *dev = hisi_hba->dev; + int rc; + + rc = disable_host_v3_hw(hisi_hba); + if (rc) { + dev_err(dev, "soft reset: disable host failed rc=%d\n", rc); return rc; } @@ -2433,6 +2480,41 @@ static pci_ers_result_t hisi_sas_slot_reset_v3_hw(struct pci_dev *pdev) return PCI_ERS_RESULT_DISCONNECT; } +static void hisi_sas_reset_prepare_v3_hw(struct pci_dev *pdev) +{ + struct sas_ha_struct *sha = pci_get_drvdata(pdev); + struct hisi_hba *hisi_hba = sha->lldd_ha; + struct device *dev = hisi_hba->dev; + int rc; + + dev_info(dev, "FLR prepare\n"); + set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); + hisi_sas_controller_reset_prepare(hisi_hba); + + rc = disable_host_v3_hw(hisi_hba); + if (rc) + dev_err(dev, "FLR: disable host failed rc=%d\n", rc); +} + +static void hisi_sas_reset_done_v3_hw(struct pci_dev *pdev) +{ + struct sas_ha_struct *sha = pci_get_drvdata(pdev); + struct hisi_hba *hisi_hba = sha->lldd_ha; + struct device *dev = hisi_hba->dev; + int rc; + + hisi_sas_init_mem(hisi_hba); + + rc = hw_init_v3_hw(hisi_hba); + if (rc) { + dev_err(dev, "FLR: hw init failed rc=%d\n", rc); + return; + } + + hisi_sas_controller_reset_done(hisi_hba); + dev_info(dev, "FLR done\n"); +} + enum { /* instances of the controller */ hip08, @@ -2444,38 +2526,24 @@ static int hisi_sas_v3_suspend(struct pci_dev *pdev, pm_message_t state) struct hisi_hba *hisi_hba = sha->lldd_ha; struct device *dev = hisi_hba->dev; struct Scsi_Host *shost = hisi_hba->shost; - u32 device_state, status; + u32 device_state; int rc; - u32 reg_val; if (!pdev->pm_cap) { dev_err(dev, "PCI PM not supported\n"); return -ENODEV; } - set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); + if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) + return -1; + scsi_block_requests(shost); set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); flush_workqueue(hisi_hba->wq); - /* disable DQ/PHY/bus */ - 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); - reg_val = hisi_sas_read32(hisi_hba, AXI_MASTER_CFG_BASE + - AM_CTRL_GLOBAL); - reg_val |= 0x1; - hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE + - AM_CTRL_GLOBAL, reg_val); - - /* wait until bus idle */ - rc = hisi_sas_read32_poll_timeout(AXI_MASTER_CFG_BASE + - AM_CURR_TRANS_RETURN, status, - status == 0x3, 10, 100); + rc = disable_host_v3_hw(hisi_hba); if (rc) { - dev_err(dev, "axi bus is not idle, rc = %d\n", rc); + dev_err(dev, "PM suspend: disable host failed rc=%d\n", rc); clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); scsi_unblock_requests(shost); @@ -2538,6 +2606,8 @@ static const struct pci_error_handlers hisi_sas_err_handler = { .error_detected = hisi_sas_error_detected_v3_hw, .mmio_enabled = hisi_sas_mmio_enabled_v3_hw, .slot_reset = hisi_sas_slot_reset_v3_hw, + .reset_prepare = hisi_sas_reset_prepare_v3_hw, + .reset_done = hisi_sas_reset_done_v3_hw, }; static struct pci_driver sas_v3_pci_driver = { |