diff options
Diffstat (limited to 'drivers/scsi/hisi_sas/hisi_sas_main.c')
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_main.c | 689 |
1 files changed, 188 insertions, 501 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index ebf5ec38891b..461ef8a76c4c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -10,12 +10,6 @@ #define DEV_IS_GONE(dev) \ ((!dev) || (dev->dev_type == SAS_PHY_UNUSED)) -static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, - u8 *lun, struct hisi_sas_tmf_task *tmf); -static int -hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, - struct domain_device *device, - int abort_flag, int tag, bool rst_to_recover); static int hisi_sas_softreset_ata_disk(struct domain_device *device); static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, void *funcdata); @@ -23,6 +17,10 @@ static void hisi_sas_release_task(struct hisi_hba *hisi_hba, struct domain_device *device); static void hisi_sas_dev_gone(struct domain_device *device); +struct hisi_sas_internal_abort_data { + bool rst_ha_timeout; /* reset the HA for timeout */ +}; + u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction) { switch (fis->command) { @@ -265,11 +263,9 @@ static void hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba, } static void hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba, - struct hisi_sas_internal_abort *abort, - struct hisi_sas_slot *slot, int device_id) + struct hisi_sas_slot *slot) { - hisi_hba->hw->prep_abort(hisi_hba, slot, - device_id, abort->flag, abort->tag); + hisi_hba->hw->prep_abort(hisi_hba, slot); } static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba, @@ -399,13 +395,11 @@ static void hisi_sas_task_deliver(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, struct hisi_sas_dq *dq, - struct hisi_sas_device *sas_dev, - struct hisi_sas_internal_abort *abort) + struct hisi_sas_device *sas_dev) { struct hisi_sas_cmd_hdr *cmd_hdr_base; int dlvry_queue_slot, dlvry_queue; struct sas_task *task = slot->task; - unsigned long flags; int wr_q_index; spin_lock(&dq->lock); @@ -442,25 +436,17 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba, break; case SAS_PROTOCOL_SATA: case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: + case SAS_PROTOCOL_STP_ALL: hisi_sas_task_prep_ata(hisi_hba, slot); break; - case SAS_PROTOCOL_NONE: - if (abort) { - hisi_sas_task_prep_abort(hisi_hba, abort, slot, sas_dev->device_id); - break; - } + case SAS_PROTOCOL_INTERNAL_ABORT: + hisi_sas_task_prep_abort(hisi_hba, slot); + break; fallthrough; default: - dev_err(hisi_hba->dev, "task prep: unknown/unsupported proto (0x%x)\n", - task->task_proto); - break; + return; } - spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock_irqrestore(&task->task_state_lock, flags); - WRITE_ONCE(slot->ready, 1); spin_lock(&dq->lock); @@ -468,13 +454,13 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba, spin_unlock(&dq->lock); } -static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, - struct hisi_sas_tmf_task *tmf) +static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) { int n_elem = 0, n_elem_dif = 0, n_elem_req = 0; struct domain_device *device = task->dev; struct asd_sas_port *sas_port = device->port; struct hisi_sas_device *sas_dev = device->lldd_dev; + bool internal_abort = sas_is_internal_abort(task); struct scsi_cmnd *scmd = NULL; struct hisi_sas_dq *dq = NULL; struct hisi_sas_port *port; @@ -492,7 +478,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, * libsas will use dev->port, should * not call task_done for sata */ - if (device->dev_type != SAS_SATA_DEV) + if (device->dev_type != SAS_SATA_DEV && !internal_abort) task->task_done(task); return -ECOMM; } @@ -500,59 +486,85 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, hisi_hba = dev_to_hisi_hba(device); dev = hisi_hba->dev; - if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) { - if (!gfpflags_allow_blocking(gfp_flags)) - return -EINVAL; + switch (task->task_proto) { + case SAS_PROTOCOL_SSP: + case SAS_PROTOCOL_SMP: + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: + case SAS_PROTOCOL_STP_ALL: + if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) { + if (!gfpflags_allow_blocking(gfp_flags)) + return -EINVAL; - down(&hisi_hba->sem); - up(&hisi_hba->sem); - } + down(&hisi_hba->sem); + up(&hisi_hba->sem); + } - if (DEV_IS_GONE(sas_dev)) { - if (sas_dev) - dev_info(dev, "task prep: device %d not ready\n", - sas_dev->device_id); - else - dev_info(dev, "task prep: device %016llx not ready\n", - SAS_ADDR(device->sas_addr)); + if (DEV_IS_GONE(sas_dev)) { + if (sas_dev) + dev_info(dev, "task prep: device %d not ready\n", + sas_dev->device_id); + else + dev_info(dev, "task prep: device %016llx not ready\n", + SAS_ADDR(device->sas_addr)); - return -ECOMM; - } + return -ECOMM; + } - if (task->uldd_task) { - struct ata_queued_cmd *qc; + port = to_hisi_sas_port(sas_port); + if (!port->port_attached) { + dev_info(dev, "task prep: %s port%d not attach device\n", + dev_is_sata(device) ? "SATA/STP" : "SAS", + device->port->id); - if (dev_is_sata(device)) { - qc = task->uldd_task; - scmd = qc->scsicmd; - } else { - scmd = task->uldd_task; + return -ECOMM; } - } - if (scmd) { - unsigned int dq_index; - u32 blk_tag; + if (task->uldd_task) { + struct ata_queued_cmd *qc; - blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); - dq_index = blk_mq_unique_tag_to_hwq(blk_tag); - dq = &hisi_hba->dq[dq_index]; - } else { - struct Scsi_Host *shost = hisi_hba->shost; - struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; - int queue = qmap->mq_map[raw_smp_processor_id()]; + if (dev_is_sata(device)) { + qc = task->uldd_task; + scmd = qc->scsicmd; + } else { + scmd = task->uldd_task; + } + } - dq = &hisi_hba->dq[queue]; - } + if (scmd) { + unsigned int dq_index; + u32 blk_tag; - port = to_hisi_sas_port(sas_port); - if (port && !port->port_attached) { - dev_info(dev, "task prep: %s port%d not attach device\n", - (dev_is_sata(device)) ? - "SATA/STP" : "SAS", - device->port->id); + blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); + dq_index = blk_mq_unique_tag_to_hwq(blk_tag); + dq = &hisi_hba->dq[dq_index]; + } else { + struct Scsi_Host *shost = hisi_hba->shost; + struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; + int queue = qmap->mq_map[raw_smp_processor_id()]; - return -ECOMM; + dq = &hisi_hba->dq[queue]; + } + break; + case SAS_PROTOCOL_INTERNAL_ABORT: + if (!hisi_hba->hw->prep_abort) + return TMF_RESP_FUNC_FAILED; + + if (test_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags)) + return -EIO; + + hisi_hba = dev_to_hisi_hba(device); + + if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) + return -EINVAL; + + port = to_hisi_sas_port(sas_port); + dq = &hisi_hba->dq[task->abort_task.qid]; + break; + default: + dev_err(hisi_hba->dev, "task prep: unknown/unsupported proto (0x%x)\n", + task->task_proto); + return -EINVAL; } rc = hisi_sas_dma_map(hisi_hba, task, &n_elem, @@ -566,7 +578,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, goto err_out_dma_unmap; } - if (hisi_hba->hw->slot_index_alloc) + if (!internal_abort && hisi_hba->hw->slot_index_alloc) rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device); else rc = hisi_sas_slot_index_alloc(hisi_hba, scmd); @@ -580,11 +592,11 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, slot->task = task; slot->port = port; - slot->tmf = tmf; - slot->is_internal = tmf; + slot->tmf = task->tmf; + slot->is_internal = !!task->tmf || internal_abort; /* protect task_prep and start_delivery sequence */ - hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL); + hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev); return 0; @@ -672,12 +684,30 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device) return sas_dev; } +static void hisi_sas_tmf_aborted(struct sas_task *task) +{ + struct hisi_sas_slot *slot = task->lldd_task; + struct domain_device *device = task->dev; + struct hisi_sas_device *sas_dev = device->lldd_dev; + struct hisi_hba *hisi_hba = sas_dev->hisi_hba; + + if (slot) { + struct hisi_sas_cq *cq = + &hisi_hba->cq[slot->dlvry_queue]; + /* + * sync irq to avoid free'ing task + * before using task in IO completion + */ + synchronize_irq(cq->irq_no); + slot->task = NULL; + } +} + #define HISI_SAS_DISK_RECOVER_CNT 3 static int hisi_sas_init_device(struct domain_device *device) { int rc = TMF_RESP_FUNC_COMPLETE; struct scsi_lun lun; - struct hisi_sas_tmf_task tmf_task; int retry = HISI_SAS_DISK_RECOVER_CNT; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct device *dev = hisi_hba->dev; @@ -687,10 +717,8 @@ static int hisi_sas_init_device(struct domain_device *device) case SAS_END_DEVICE: int_to_scsilun(0, &lun); - tmf_task.tmf = TMF_CLEAR_TASK_SET; while (retry-- > 0) { - rc = hisi_sas_debug_issue_ssp_tmf(device, lun.scsi_lun, - &tmf_task); + rc = sas_clear_task_set(device, lun.scsi_lun); if (rc == TMF_RESP_FUNC_COMPLETE) { hisi_sas_release_task(hisi_hba, device); break; @@ -1035,8 +1063,7 @@ static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, struct sas_task ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_ABORTED_TASK; spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags &= - ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); + task->task_state_flags &= ~SAS_TASK_STATE_PENDING; if (!slot->is_internal && task->task_proto != SAS_PROTOCOL_SMP) task->task_state_flags |= SAS_TASK_STATE_DONE; spin_unlock_irqrestore(&task->task_state_lock, flags); @@ -1081,6 +1108,29 @@ static void hisi_sas_dereg_device(struct hisi_hba *hisi_hba, hisi_hba->hw->dereg_device(hisi_hba, device); } +static int +hisi_sas_internal_task_abort_dev(struct hisi_sas_device *sas_dev, + bool rst_ha_timeout) +{ + struct hisi_sas_internal_abort_data data = { rst_ha_timeout }; + struct domain_device *device = sas_dev->sas_device; + struct hisi_hba *hisi_hba = sas_dev->hisi_hba; + int i, rc; + + for (i = 0; i < hisi_hba->cq_nvecs; i++) { + struct hisi_sas_cq *cq = &hisi_hba->cq[i]; + const struct cpumask *mask = cq->irq_mask; + + if (mask && !cpumask_intersects(cpu_online_mask, mask)) + continue; + rc = sas_execute_internal_abort_dev(device, i, &data); + if (rc) + return rc; + } + + return 0; +} + static void hisi_sas_dev_gone(struct domain_device *device) { struct hisi_sas_device *sas_dev = device->lldd_dev; @@ -1093,8 +1143,7 @@ static void hisi_sas_dev_gone(struct domain_device *device) down(&hisi_hba->sem); if (!test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) { - hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, 0, true); + hisi_sas_internal_task_abort_dev(sas_dev, true); hisi_sas_dereg_device(hisi_hba, device); @@ -1112,11 +1161,6 @@ static void hisi_sas_dev_gone(struct domain_device *device) up(&hisi_hba->sem); } -static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) -{ - return hisi_sas_task_exec(task, gfp_flags, NULL); -} - static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no, struct sas_phy_linkrates *r) { @@ -1199,7 +1243,8 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, goto out; } - if (sts && !wait_for_completion_timeout(&completion, 2 * HZ)) { + if (sts && !wait_for_completion_timeout(&completion, + HISI_SAS_WAIT_PHYUP_TIMEOUT)) { dev_warn(dev, "phy%d wait phyup timed out for func %d\n", phy_no, func); if (phy->in_reset) @@ -1213,147 +1258,6 @@ out: return ret; } -static void hisi_sas_task_done(struct sas_task *task) -{ - del_timer_sync(&task->slow_task->timer); - complete(&task->slow_task->completion); -} - -static void hisi_sas_tmf_timedout(struct timer_list *t) -{ - struct sas_task_slow *slow = from_timer(slow, t, timer); - struct sas_task *task = slow->task; - unsigned long flags; - bool is_completed = true; - - spin_lock_irqsave(&task->task_state_lock, flags); - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - task->task_state_flags |= SAS_TASK_STATE_ABORTED; - is_completed = false; - } - spin_unlock_irqrestore(&task->task_state_lock, flags); - - if (!is_completed) - complete(&task->slow_task->completion); -} - -#define TASK_TIMEOUT (20 * HZ) -#define TASK_RETRY 3 -#define INTERNAL_ABORT_TIMEOUT (6 * HZ) -static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, - void *parameter, u32 para_len, - struct hisi_sas_tmf_task *tmf) -{ - struct hisi_sas_device *sas_dev = device->lldd_dev; - struct hisi_hba *hisi_hba = sas_dev->hisi_hba; - struct device *dev = hisi_hba->dev; - struct sas_task *task; - int res, retry; - - for (retry = 0; retry < TASK_RETRY; retry++) { - task = sas_alloc_slow_task(GFP_KERNEL); - if (!task) - return -ENOMEM; - - task->dev = device; - task->task_proto = device->tproto; - - if (dev_is_sata(device)) { - task->ata_task.device_control_reg_update = 1; - memcpy(&task->ata_task.fis, parameter, para_len); - } else { - memcpy(&task->ssp_task, parameter, para_len); - } - task->task_done = hisi_sas_task_done; - - task->slow_task->timer.function = hisi_sas_tmf_timedout; - task->slow_task->timer.expires = jiffies + TASK_TIMEOUT; - add_timer(&task->slow_task->timer); - - res = hisi_sas_task_exec(task, GFP_KERNEL, tmf); - if (res) { - del_timer_sync(&task->slow_task->timer); - dev_err(dev, "abort tmf: executing internal task failed: %d\n", - res); - goto ex_err; - } - - wait_for_completion(&task->slow_task->completion); - res = TMF_RESP_FUNC_FAILED; - /* Even TMF timed out, return direct. */ - if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - struct hisi_sas_slot *slot = task->lldd_task; - - dev_err(dev, "abort tmf: TMF task timeout and not done\n"); - if (slot) { - struct hisi_sas_cq *cq = - &hisi_hba->cq[slot->dlvry_queue]; - /* - * sync irq to avoid free'ing task - * before using task in IO completion - */ - synchronize_irq(cq->irq_no); - slot->task = NULL; - } - - goto ex_err; - } else - dev_err(dev, "abort tmf: TMF task timeout\n"); - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == TMF_RESP_FUNC_COMPLETE) { - res = TMF_RESP_FUNC_COMPLETE; - break; - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == TMF_RESP_FUNC_SUCC) { - res = TMF_RESP_FUNC_SUCC; - break; - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_DATA_UNDERRUN) { - /* no error, but return the number of bytes of - * underrun - */ - dev_warn(dev, "abort tmf: task to dev %016llx resp: 0x%x sts 0x%x underrun\n", - SAS_ADDR(device->sas_addr), - task->task_status.resp, - task->task_status.stat); - res = task->task_status.residual; - break; - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_DATA_OVERRUN) { - dev_warn(dev, "abort tmf: blocked task error\n"); - res = -EMSGSIZE; - break; - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_OPEN_REJECT) { - dev_warn(dev, "abort tmf: open reject failed\n"); - res = -EIO; - } else { - dev_warn(dev, "abort tmf: task to dev %016llx resp: 0x%x status 0x%x\n", - SAS_ADDR(device->sas_addr), - task->task_status.resp, - task->task_status.stat); - } - sas_free_task(task); - task = NULL; - } -ex_err: - if (retry == TASK_RETRY) - dev_warn(dev, "abort tmf: executing internal task failed!\n"); - sas_free_task(task); - return res; -} - static void hisi_sas_fill_ata_reset_cmd(struct ata_device *dev, bool reset, int pmp, u8 *fis) { @@ -1376,14 +1280,12 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device) int rc = TMF_RESP_FUNC_FAILED; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct device *dev = hisi_hba->dev; - int s = sizeof(struct host_to_dev_fis); - struct hisi_sas_tmf_task tmf = {}; ata_for_each_link(link, ap, EDGE) { int pmp = sata_srst_pmp(link); hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis); - rc = hisi_sas_exec_internal_tmf_task(device, fis, s, &tmf); + rc = sas_execute_ata_cmd(device, fis, -1); if (rc != TMF_RESP_FUNC_COMPLETE) break; } @@ -1393,8 +1295,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device) int pmp = sata_srst_pmp(link); hisi_sas_fill_ata_reset_cmd(link->device, 0, pmp, fis); - rc = hisi_sas_exec_internal_tmf_task(device, fis, - s, &tmf); + rc = sas_execute_ata_cmd(device, fis, -1); if (rc != TMF_RESP_FUNC_COMPLETE) dev_err(dev, "ata disk %016llx de-reset failed\n", SAS_ADDR(device->sas_addr)); @@ -1410,20 +1311,6 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device) return rc; } -static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, - u8 *lun, struct hisi_sas_tmf_task *tmf) -{ - struct sas_ssp_task ssp_task; - - if (!(device->tproto & SAS_PROTOCOL_SSP)) - return TMF_RESP_FUNC_ESUPP; - - memcpy(ssp_task.LUN, lun, 8); - - return hisi_sas_exec_internal_tmf_task(device, &ssp_task, - sizeof(ssp_task), tmf); -} - static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba) { u32 state = hisi_hba->hw->get_phys_state(hisi_hba); @@ -1518,10 +1405,8 @@ static void hisi_sas_send_ata_reset_each_phy(struct hisi_hba *hisi_hba, struct asd_sas_port *sas_port, struct domain_device *device) { - struct hisi_sas_tmf_task tmf_task = { .force_phy = 1 }; struct ata_port *ap = device->sata_dev.ap; struct device *dev = hisi_hba->dev; - int s = sizeof(struct host_to_dev_fis); int rc = TMF_RESP_FUNC_FAILED; struct ata_link *link; u8 fis[20] = {0}; @@ -1534,10 +1419,8 @@ static void hisi_sas_send_ata_reset_each_phy(struct hisi_hba *hisi_hba, ata_for_each_link(link, ap, EDGE) { int pmp = sata_srst_pmp(link); - tmf_task.phy_id = i; hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis); - rc = hisi_sas_exec_internal_tmf_task(device, fis, s, - &tmf_task); + rc = sas_execute_ata_cmd(device, fis, i); if (rc != TMF_RESP_FUNC_COMPLETE) { dev_err(dev, "phy%d ata reset failed rc=%d\n", i, rc); @@ -1559,9 +1442,7 @@ static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba) if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device) continue; - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, 0, - false); + rc = hisi_sas_internal_task_abort_dev(sas_dev, false); if (rc < 0) dev_err(dev, "STP reject: abort dev failed %d\n", rc); } @@ -1669,8 +1550,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) static int hisi_sas_abort_task(struct sas_task *task) { - struct scsi_lun lun; - struct hisi_sas_tmf_task tmf_task; + struct hisi_sas_internal_abort_data internal_abort_data = { false }; struct domain_device *device = task->dev; struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba; @@ -1705,21 +1585,13 @@ static int hisi_sas_abort_task(struct sas_task *task) spin_unlock_irqrestore(&task->task_state_lock, flags); if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { - struct scsi_cmnd *cmnd = task->uldd_task; struct hisi_sas_slot *slot = task->lldd_task; u16 tag = slot->idx; int rc2; - int_to_scsilun(cmnd->device->lun, &lun); - tmf_task.tmf = TMF_ABORT_TASK; - tmf_task.tag_of_task_to_be_managed = tag; - - rc = hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, - &tmf_task); - - rc2 = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_CMD, tag, - false); + rc = sas_abort_task(task, tag); + rc2 = sas_execute_internal_abort_single(device, tag, + slot->dlvry_queue, &internal_abort_data); if (rc2 < 0) { dev_err(dev, "abort task: internal abort (%d)\n", rc2); return TMF_RESP_FUNC_FAILED; @@ -1739,9 +1611,7 @@ static int hisi_sas_abort_task(struct sas_task *task) } else if (task->task_proto & SAS_PROTOCOL_SATA || task->task_proto & SAS_PROTOCOL_STP) { if (task->dev->dev_type == SAS_SATA_DEV) { - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, - 0, false); + rc = hisi_sas_internal_task_abort_dev(sas_dev, false); if (rc < 0) { dev_err(dev, "abort task: internal abort failed\n"); goto out; @@ -1755,9 +1625,9 @@ static int hisi_sas_abort_task(struct sas_task *task) u32 tag = slot->idx; struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue]; - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_CMD, tag, - false); + rc = sas_execute_internal_abort_single(device, + tag, slot->dlvry_queue, + &internal_abort_data); if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) && task->lldd_task) { /* @@ -1777,41 +1647,25 @@ out: static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun) { + struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct device *dev = hisi_hba->dev; - struct hisi_sas_tmf_task tmf_task; int rc; - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, 0, false); + rc = hisi_sas_internal_task_abort_dev(sas_dev, false); if (rc < 0) { dev_err(dev, "abort task set: internal abort rc=%d\n", rc); return TMF_RESP_FUNC_FAILED; } hisi_sas_dereg_device(hisi_hba, device); - tmf_task.tmf = TMF_ABORT_TASK_SET; - rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task); - + rc = sas_abort_task_set(device, lun); if (rc == TMF_RESP_FUNC_COMPLETE) hisi_sas_release_task(hisi_hba, device); return rc; } -static int hisi_sas_clear_aca(struct domain_device *device, u8 *lun) -{ - struct hisi_sas_tmf_task tmf_task; - int rc; - - tmf_task.tmf = TMF_CLEAR_ACA; - rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task); - - return rc; -} - -#define I_T_NEXUS_RESET_PHYUP_TIMEOUT (2 * HZ) - static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) { struct sas_phy *local_phy = sas_get_local_phy(device); @@ -1871,12 +1725,12 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) static int hisi_sas_I_T_nexus_reset(struct domain_device *device) { + struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct device *dev = hisi_hba->dev; int rc; - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, 0, false); + rc = hisi_sas_internal_task_abort_dev(sas_dev, false); if (rc < 0) { dev_err(dev, "I_T nexus reset: internal abort (%d)\n", rc); return TMF_RESP_FUNC_FAILED; @@ -1924,8 +1778,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) int rc = TMF_RESP_FUNC_FAILED; /* Clear internal IO and then lu reset */ - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, 0, false); + rc = hisi_sas_internal_task_abort_dev(sas_dev, false); if (rc < 0) { dev_err(dev, "lu_reset: internal abort failed\n"); goto out; @@ -1943,9 +1796,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) hisi_sas_release_task(hisi_hba, device); sas_put_local_phy(phy); } else { - struct hisi_sas_tmf_task tmf_task = { .tmf = TMF_LU_RESET }; - - rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task); + rc = sas_lu_reset(device, lun); if (rc == TMF_RESP_FUNC_COMPLETE) hisi_sas_release_task(hisi_hba, device); } @@ -2000,23 +1851,13 @@ static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha) static int hisi_sas_query_task(struct sas_task *task) { - struct scsi_lun lun; - struct hisi_sas_tmf_task tmf_task; int rc = TMF_RESP_FUNC_FAILED; if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { - struct scsi_cmnd *cmnd = task->uldd_task; - struct domain_device *device = task->dev; struct hisi_sas_slot *slot = task->lldd_task; u32 tag = slot->idx; - int_to_scsilun(cmnd->device->lun, &lun); - tmf_task.tmf = TMF_QUERY_TASK; - tmf_task.tag_of_task_to_be_managed = tag; - - rc = hisi_sas_debug_issue_ssp_tmf(device, - lun.scsi_lun, - &tmf_task); + rc = sas_query_task(task, tag); switch (rc) { /* The task is still in Lun, release it then */ case TMF_RESP_FUNC_SUCC: @@ -2032,203 +1873,48 @@ static int hisi_sas_query_task(struct sas_task *task) return rc; } -static int -hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, - struct hisi_sas_internal_abort *abort, - struct sas_task *task, - struct hisi_sas_dq *dq) +static bool hisi_sas_internal_abort_timeout(struct sas_task *task, + void *data) { struct domain_device *device = task->dev; - struct hisi_sas_device *sas_dev = device->lldd_dev; - struct device *dev = hisi_hba->dev; - struct hisi_sas_port *port; - struct asd_sas_port *sas_port = device->port; - struct hisi_sas_slot *slot; - int slot_idx; - - if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) - return -EINVAL; - - if (!device->port) - return -1; - - port = to_hisi_sas_port(sas_port); - - /* simply get a slot and send abort command */ - slot_idx = hisi_sas_slot_index_alloc(hisi_hba, NULL); - if (slot_idx < 0) - goto err_out; - - slot = &hisi_hba->slot_info[slot_idx]; - slot->n_elem = 0; - slot->task = task; - slot->port = port; - slot->is_internal = true; - - hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort); - - return 0; - -err_out: - dev_err(dev, "internal abort task prep: failed[%d]!\n", slot_idx); - - return slot_idx; -} - -/** - * _hisi_sas_internal_task_abort -- execute an internal - * abort command for single IO command or a device - * @hisi_hba: host controller struct - * @device: domain device - * @abort_flag: mode of operation, device or single IO - * @tag: tag of IO to be aborted (only relevant to single - * IO mode) - * @dq: delivery queue for this internal abort command - * @rst_to_recover: If rst_to_recover set, queue a controller - * reset if an internal abort times out. - */ -static int -_hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, - struct domain_device *device, int abort_flag, - int tag, struct hisi_sas_dq *dq, bool rst_to_recover) -{ - struct sas_task *task; - struct hisi_sas_device *sas_dev = device->lldd_dev; - struct hisi_sas_internal_abort abort = { - .flag = abort_flag, - .tag = tag, - }; - struct device *dev = hisi_hba->dev; - int res; - /* - * The interface is not realized means this HW don't support internal - * abort, or don't need to do internal abort. Then here, we return - * TMF_RESP_FUNC_FAILED and let other steps go on, which depends that - * the internal abort has been executed and returned CQ. - */ - if (!hisi_hba->hw->prep_abort) - return TMF_RESP_FUNC_FAILED; - - if (test_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags)) - return -EIO; - - task = sas_alloc_slow_task(GFP_KERNEL); - if (!task) - return -ENOMEM; - - task->dev = device; - task->task_proto = SAS_PROTOCOL_NONE; - task->task_done = hisi_sas_task_done; - task->slow_task->timer.function = hisi_sas_tmf_timedout; - task->slow_task->timer.expires = jiffies + INTERNAL_ABORT_TIMEOUT; - add_timer(&task->slow_task->timer); - - res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id, - &abort, task, dq); - if (res) { - del_timer_sync(&task->slow_task->timer); - dev_err(dev, "internal task abort: executing internal task failed: %d\n", - res); - goto exit; - } - wait_for_completion(&task->slow_task->completion); - res = TMF_RESP_FUNC_FAILED; - - /* Internal abort timed out */ - if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) - queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); - - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - struct hisi_sas_slot *slot = task->lldd_task; - - set_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags); - - if (slot) { - struct hisi_sas_cq *cq = - &hisi_hba->cq[slot->dlvry_queue]; - /* - * sync irq to avoid free'ing task - * before using task in IO completion - */ - synchronize_irq(cq->irq_no); - slot->task = NULL; - } - - if (rst_to_recover) { - dev_err(dev, "internal task abort: timeout and not done. Queuing reset.\n"); - queue_work(hisi_hba->wq, &hisi_hba->rst_work); - } else { - dev_err(dev, "internal task abort: timeout and not done.\n"); - } - - res = -EIO; - goto exit; - } else - dev_err(dev, "internal task abort: timeout.\n"); - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == TMF_RESP_FUNC_COMPLETE) { - res = TMF_RESP_FUNC_COMPLETE; - goto exit; - } + struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); + struct hisi_sas_internal_abort_data *timeout = data; - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == TMF_RESP_FUNC_SUCC) { - res = TMF_RESP_FUNC_SUCC; - goto exit; - } + if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) + queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); -exit: - dev_dbg(dev, "internal task abort: task to dev %016llx task=%pK resp: 0x%x sts 0x%x\n", - SAS_ADDR(device->sas_addr), task, - task->task_status.resp, /* 0 is complete, -1 is undelivered */ - task->task_status.stat); - sas_free_task(task); + if (task->task_state_flags & SAS_TASK_STATE_DONE) { + pr_err("Internal abort: timeout %016llx\n", + SAS_ADDR(device->sas_addr)); + } else { + struct hisi_sas_slot *slot = task->lldd_task; - return res; -} + set_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags); -static int -hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, - struct domain_device *device, - int abort_flag, int tag, bool rst_to_recover) -{ - struct hisi_sas_slot *slot; - struct device *dev = hisi_hba->dev; - struct hisi_sas_dq *dq; - int i, rc; + if (slot) { + struct hisi_sas_cq *cq = + &hisi_hba->cq[slot->dlvry_queue]; + /* + * sync irq to avoid free'ing task + * before using task in IO completion + */ + synchronize_irq(cq->irq_no); + slot->task = NULL; + } - switch (abort_flag) { - case HISI_SAS_INT_ABT_CMD: - slot = &hisi_hba->slot_info[tag]; - dq = &hisi_hba->dq[slot->dlvry_queue]; - return _hisi_sas_internal_task_abort(hisi_hba, device, - abort_flag, tag, dq, - rst_to_recover); - case HISI_SAS_INT_ABT_DEV: - for (i = 0; i < hisi_hba->cq_nvecs; i++) { - struct hisi_sas_cq *cq = &hisi_hba->cq[i]; - const struct cpumask *mask = cq->irq_mask; - - if (mask && !cpumask_intersects(cpu_online_mask, mask)) - continue; - dq = &hisi_hba->dq[i]; - rc = _hisi_sas_internal_task_abort(hisi_hba, device, - abort_flag, tag, - dq, rst_to_recover); - if (rc) - return rc; + if (timeout->rst_ha_timeout) { + pr_err("Internal abort: timeout and not done %016llx. Queuing reset.\n", + SAS_ADDR(device->sas_addr)); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); + } else { + pr_err("Internal abort: timeout and not done %016llx.\n", + SAS_ADDR(device->sas_addr)); } - break; - default: - dev_err(dev, "Unrecognised internal abort flag (%d)\n", - abort_flag); - return -EINVAL; + + return true; } - return 0; + return false; } static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy) @@ -2339,13 +2025,14 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { .lldd_control_phy = hisi_sas_control_phy, .lldd_abort_task = hisi_sas_abort_task, .lldd_abort_task_set = hisi_sas_abort_task_set, - .lldd_clear_aca = hisi_sas_clear_aca, .lldd_I_T_nexus_reset = hisi_sas_I_T_nexus_reset, .lldd_lu_reset = hisi_sas_lu_reset, .lldd_query_task = hisi_sas_query_task, .lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha, .lldd_port_formed = hisi_sas_port_formed, .lldd_write_gpio = hisi_sas_write_gpio, + .lldd_tmf_aborted = hisi_sas_tmf_aborted, + .lldd_abort_timeout = hisi_sas_internal_abort_timeout, }; void hisi_sas_init_mem(struct hisi_hba *hisi_hba) |