diff options
author | flyingnosky <flyingnosky@163.com> | 2015-11-05 21:21:18 +0800 |
---|---|---|
committer | flyingnosky <flyingnosky@163.com> | 2015-11-06 10:01:34 +0800 |
commit | 0491d5569066ae6ae21544bd5774f80c29e33a3c (patch) | |
tree | eea45d02afc2c05fdace121138f10ff20c4f47f5 | |
parent | fe83387e19b88a97b8c0b40ecc5627b1e8a25afd (diff) |
hisi_sas: improve error handler for p660 and hi1610
add error handler process for p660 and hi1610
Signed-off-by:chenxiang <chenxiang66@hisilicon.com>
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas.h | 35 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_init.c | 2 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_main.c | 534 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 28 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 554 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/serdes.c | 3 |
6 files changed, 1054 insertions, 102 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index da621ac5cbf3..532d327be5ad 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -117,6 +117,13 @@ struct hisi_sas_device { u64 reserved; }; +struct hisi_sas_work { + struct work_struct work; + struct hisi_hba *hisi_hba; + void *data; + int handler; +}; + struct hisi_sas_slot { struct list_head entry; struct sas_task *task; @@ -158,6 +165,30 @@ struct hisi_sas_tei { struct hisi_hba; +/* use for abort in pm8001 */ +struct task_abort_req { + __le32 tag; + __le32 device_id; + __le32 tag_to_abort; + __le32 abort_all; + u32 reserved[11]; +} __packed; + +/* These flags used for SSP SMP & SATA Abort */ +#define ABORT_MASK 0x3 +#define ABORT_SINGLE 0x0 +#define ABORT_ALL 0x1 +#define SAS_ABORT_AND_RETRY 0x0 + +#define HISI_INTERNAL_EH_STAT 0x11 + +struct task_abort_resp { + __le32 tag; + __le32 status; + __le32 scp; + u32 reserved[12]; +} __packed; + struct hisi_sas_dispatch { int (*hw_init)(struct hisi_hba *hisi_hba); int (*phys_init)(struct hisi_hba *hisi_hba); @@ -174,6 +205,9 @@ struct hisi_sas_dispatch { struct hisi_sas_tei *tei); int (*prep_stp)(struct hisi_hba *hisi_hba, struct hisi_sas_tei *tei); + int (*prep_abort)(struct hisi_hba *hisi_hba, + struct hisi_sas_tei *tei, + struct task_abort_req *task_abort); int (*slot_complete)(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, int abort); void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no); @@ -515,6 +549,7 @@ void hisi_sas_bytes_dmaed(struct hisi_hba *hisi_hba, int phy_no); void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy, int lock); void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, struct hisi_sas_slot *slot); +int hisi_sas_handle_event(struct hisi_hba *hisi_hba, void *data, int handler); #ifdef CONFIG_DEBUG_FS int hisi_sas_debugfs_init(struct hisi_hba *hisi_hba); void hisi_sas_debugfs_free(struct hisi_hba *hisi_hba); diff --git a/drivers/scsi/hisi_sas/hisi_sas_init.c b/drivers/scsi/hisi_sas/hisi_sas_init.c index 5e27270f0f3f..9b4cf9c34c2b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_init.c +++ b/drivers/scsi/hisi_sas/hisi_sas_init.c @@ -13,6 +13,8 @@ static struct scsi_transport_template *hisi_sas_stt; +struct workqueue_struct *hisi_sas_wq; + static struct scsi_host_template hisi_sas_sht = { .module = THIS_MODULE, .name = DRV_NAME, diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index dd5d340e8d83..0d9218e456f1 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -190,6 +190,13 @@ static int hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba, return HISI_SAS_DISP->prep_stp(hisi_hba, tei); } +static int hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba, + struct hisi_sas_tei *tei, + struct task_abort_req *task_abort) +{ + return HISI_SAS_DISP->prep_abort(hisi_hba, tei, task_abort); +} + static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, int is_tmf, struct hisi_sas_tmf_task *tmf, @@ -900,11 +907,6 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *dev, break; } - pr_warn(" task to dev %016llx response: 0x%x " - "status 0x%x\n", - SAS_ADDR(dev->sas_addr), - task->task_status.resp, - task->task_status.stat); sas_free_task(task); task = NULL; } @@ -928,85 +930,6 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *dev, sizeof(ssp_task), tmf); } -int hisi_sas_abort_task(struct sas_task *task) -{ - struct scsi_lun lun; - struct hisi_sas_tmf_task tmf_task; - struct domain_device *dev = task->dev; - struct hisi_sas_device *hisi_sas_dev = (struct hisi_sas_device *)dev->lldd_dev; - struct hisi_hba *hisi_hba; - int rc = TMF_RESP_FUNC_FAILED; - unsigned long flags; - u32 tag; - - if (!hisi_sas_dev) { - pr_warn("%s Device has been removed\n", __func__); - return TMF_RESP_FUNC_FAILED; - } - - hisi_hba = dev_to_hisi_hba(task->dev); - - spin_lock_irqsave(&task->task_state_lock, flags); - if (task->task_state_flags & SAS_TASK_STATE_DONE) { - spin_unlock_irqrestore(&task->task_state_lock, flags); - rc = TMF_RESP_FUNC_COMPLETE; - goto out; - } - - spin_unlock_irqrestore(&task->task_state_lock, flags); - hisi_sas_dev->dev_status = HISI_SAS_DEV_EH; - if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { - struct scsi_cmnd *cmnd = (struct scsi_cmnd *)task->uldd_task; - - int_to_scsilun(cmnd->device->lun, &lun); - rc = hisi_sas_find_tag(hisi_hba, task, &tag); - if (rc == 0) { - dev_notice(hisi_hba->dev, - "No such tag in %s\n", __func__); - rc = TMF_RESP_FUNC_FAILED; - return rc; - } - - tmf_task.tmf = TMF_ABORT_TASK; - tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag); - - rc = hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, &tmf_task); - - /* if successful, clear the task and callback forwards.*/ - if (rc == TMF_RESP_FUNC_COMPLETE) { - if (task->lldd_task) { - struct hisi_sas_slot *slot; - - slot = &hisi_hba->slot_info - [tmf_task.tag_of_task_to_be_managed]; - spin_lock_irqsave(&hisi_hba->lock, flags); - HISI_SAS_DISP->slot_complete(hisi_hba, slot, 1); - spin_unlock_irqrestore(&hisi_hba->lock, flags); - } - } - - } else if (task->task_proto & SAS_PROTOCOL_SATA || - task->task_proto & SAS_PROTOCOL_STP) { - if (SAS_SATA_DEV == task->dev->dev_type) { - struct hisi_slot_info *slot = task->lldd_task; - - dev_notice(hisi_hba->dev, "%s hba=%p task=%p slot=%p\n", - __func__, - hisi_hba, task, slot); - task->task_state_flags |= SAS_TASK_STATE_ABORTED; - /* hisi_sas_slot_task_free(hisi_hba, task, slot, slot_idx); */ - rc = TMF_RESP_FUNC_COMPLETE; - goto out; - } - - } - -out: - if (rc != TMF_RESP_FUNC_COMPLETE) - dev_notice(hisi_hba->dev, "%s:rc = %d\n", __func__, rc); - return rc; -} - int hisi_sas_abort_task_set(struct domain_device *dev, u8 *lun) { int rc = TMF_RESP_FUNC_FAILED; @@ -1172,6 +1095,449 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy) } } +static int hisi_sas_abort_task_exec(struct hisi_hba *hisi_hba, + int device_id, + struct sas_task *cmd_task, + int flag, int task_tag) +{ + struct domain_device *dev = cmd_task->dev; + struct hisi_sas_tei tei; + struct hisi_sas_slot *slot; + struct hisi_sas_cmd_hdr *cmd_hdr_base; + struct hisi_sas_device *hisi_sas_dev = dev->lldd_dev; + struct task_abort_req task_abort; + int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; + unsigned long flags = 0; + + memset(&task_abort, 0, sizeof(task_abort)); + if (ABORT_SINGLE == (flag & ABORT_MASK)) { + task_abort.abort_all = 0; + task_abort.device_id = cpu_to_le32(device_id); + task_abort.tag_to_abort = cpu_to_le32(task_tag); + } else if (ABORT_ALL == (flag & ABORT_MASK)) { + task_abort.abort_all = cpu_to_le32(1); + task_abort.device_id = cpu_to_le32(device_id); + } + + if (!dev->port) { + struct task_status_struct *tsm = &cmd_task->task_status; + + tsm->resp = SAS_TASK_UNDELIVERED; + tsm->stat = SAS_PHY_DOWN; + + /*libasas will use dev->port, should + * not call task_done for sata + */ + if (dev->dev_type != SAS_SATA_DEV) + cmd_task->task_done(cmd_task); + return 0; + } + + /* simply get a slot and send abort command */ + spin_lock_irqsave(&hisi_hba->lock, flags); + rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + if (rc) + goto err_out; + + rc = HISI_SAS_DISP->get_free_slot(hisi_hba, + &dlvry_queue, + &dlvry_queue_slot); + if (rc) + goto err_out; + + slot = &hisi_hba->slot_info[slot_idx]; + memset(slot, 0, sizeof(struct hisi_sas_slot)); + + cmd_task->lldd_task = NULL; + /* c00308265, temporary solution may + * not good for opensource fixed to me */ + /*slot->inter_cmd_type = INTER_CMD_TYPE_ABORT;*/ + slot->idx = slot_idx; + slot->n_elem = n_elem; + slot->dlvry_queue = dlvry_queue; + slot->dlvry_queue_slot = dlvry_queue_slot; + cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue]; + slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot]; + + slot->status_buffer = dma_pool_alloc(hisi_hba->status_buffer_pool, + GFP_ATOMIC, + &slot->status_buffer_dma); + + if (!slot->status_buffer) + goto err_out; + memset(slot->status_buffer, 0, HISI_SAS_STATUS_BUF_SZ); + + slot->command_table = + dma_pool_alloc(hisi_hba->command_table_pool, GFP_ATOMIC, + &slot->command_table_dma); + if (!slot->command_table) + goto err_out; + memset(slot->command_table, 0, HISI_SAS_COMMAND_TABLE_SZ); + + tei.hdr = slot->cmd_hdr; + tei.task = cmd_task; + /* tei.n_elem = n_elem; */ + tei.port = dev->port->lldd_port; + tei.iptt = slot_idx; + tei.slot = slot; + /* abort single task or abort tasks of device */ + /*rc = hisi_sas_task_prep_abort(hisi_hba, &tei, flag,*/ + /*device_id, task_tag_to_abort);*/ + + rc = hisi_sas_task_prep_abort(hisi_hba, &tei, &task_abort); + if (rc) + goto err_out; + + slot->task = cmd_task; + slot->port = tei.port; + cmd_task->lldd_task = slot; + list_add_tail(&slot->entry, &tei.port->list); + spin_lock(&cmd_task->task_state_lock); + cmd_task->task_state_flags |= SAS_TASK_AT_INITIATOR; + spin_unlock(&cmd_task->task_state_lock); + + hisi_hba->slot_prep = slot; + + /* send abort command to our chip */ + HISI_SAS_DISP->start_delivery(hisi_hba); + + hisi_sas_dev->running_req++; + + return rc; + +err_out: + return rc; +} + +static int +hisi_sas_exec_internal_task_abort(struct hisi_hba *hisi_hba, + struct hisi_sas_device *hisi_sas_dev, + struct domain_device *dev, u32 flag, u32 tag) +{ + int res, retry; + struct sas_task *task = NULL; + + for (retry = 0; retry < 3; retry++) { + task = sas_alloc_slow_task(GFP_KERNEL); + if (!task) + return -ENOMEM; + + task->dev = dev; + task->task_proto = dev->tproto; + task->task_done = hisi_sas_task_done; + task->slow_task->timer.data = (unsigned long)task; + task->slow_task->timer.function = hisi_sas_tmf_timedout; + task->slow_task->timer.expires = jiffies + TASK_TIMEOUT*HZ; + add_timer(&task->slow_task->timer); + + res = hisi_sas_abort_task_exec(hisi_hba, + hisi_sas_dev->device_id, task, flag, tag); + + if (res) { + del_timer(&task->slow_task->timer); + pr_info("Executing internal task failed\n"); + goto ex_err; + } + wait_for_completion(&task->slow_task->completion); + res = TMF_RESP_FUNC_FAILED; + /* TMF timed out, return direct. */ + if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { + if (task->lldd_task) { + struct hisi_sas_slot *slot; + struct hisi_sas_device *hisi_sas_dev = + dev->lldd_dev; + struct hisi_hba *hisi_hba; + + slot = (struct hisi_sas_slot *) + task->lldd_task; + + if (hisi_sas_dev && + hisi_sas_dev->running_req) + hisi_sas_dev->running_req--; + hisi_hba = hisi_sas_dev->hisi_hba; + hisi_sas_slot_task_free(hisi_hba, + task, slot); + } + + pr_info("%s abort task timeout.\n", __func__); + goto ex_err; + + } + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_DATA_OVERRUN) { + pr_warn("blocked task error.\n"); + res = -EMSGSIZE; + break; + } + + pr_warn(" task to dev %016llx response: 0x%x " + "status 0x%x\n", + SAS_ADDR(dev->sas_addr), + task->task_status.resp, + task->task_status.stat); + sas_free_task(task); + task = NULL; + + } +ex_err: + BUG_ON(retry == 3 && task != NULL); + sas_free_task(task); + return res; +} + +int hisi_sas_abort_task(struct sas_task *task) +{ + struct scsi_lun lun; + struct hisi_sas_tmf_task tmf_task; + struct domain_device *dev = task->dev; + struct hisi_sas_device *hisi_sas_dev = + (struct hisi_sas_device *)dev->lldd_dev; + struct hisi_hba *hisi_hba; + int rc = TMF_RESP_FUNC_FAILED; + unsigned long flags; + u32 tag; + + if (!hisi_sas_dev) { + pr_warn("%s Device has been removed\n", __func__); + return TMF_RESP_FUNC_FAILED; + } + + hisi_hba = dev_to_hisi_hba(task->dev); + + spin_lock_irqsave(&task->task_state_lock, flags); + if (task->task_state_flags & SAS_TASK_STATE_DONE) { + spin_unlock_irqrestore(&task->task_state_lock, flags); + rc = TMF_RESP_FUNC_COMPLETE; + goto out; + } + + spin_unlock_irqrestore(&task->task_state_lock, flags); + hisi_sas_dev->dev_status = HISI_SAS_DEV_EH; + if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { + struct scsi_cmnd *cmnd = (struct scsi_cmnd *)task->uldd_task; + + int_to_scsilun(cmnd->device->lun, &lun); + rc = hisi_sas_find_tag(hisi_hba, task, &tag); + if (rc == 0) { + dev_notice(hisi_hba->dev, + "No such tag in %s\n", __func__); + rc = TMF_RESP_FUNC_FAILED; + return rc; + } + + tmf_task.tmf = TMF_ABORT_TASK; + tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag); + + rc = hisi_sas_debug_issue_ssp_tmf(task->dev, + lun.scsi_lun, &tmf_task); + + /* if successful, clear the task and callback forwards.*/ + if (rc == TMF_RESP_FUNC_COMPLETE) { + if (task->lldd_task) { + struct hisi_sas_slot *slot; + + slot = &hisi_hba->slot_info + [tmf_task.tag_of_task_to_be_managed]; + spin_lock_irqsave(&hisi_hba->lock, flags); + HISI_SAS_DISP->slot_complete(hisi_hba, slot, 1); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + } + } + + rc = hisi_sas_exec_internal_task_abort(hisi_hba, + hisi_sas_dev, dev, 0, tag); + + } else if (task->task_proto & SAS_PROTOCOL_SATA || + task->task_proto & SAS_PROTOCOL_STP) { + if (SAS_SATA_DEV == task->dev->dev_type) { + struct hisi_slot_info *slot = task->lldd_task; + + dev_notice(hisi_hba->dev, "%s hba=%p task=%p slot=%p\n", + __func__, + hisi_hba, task, slot); + task->task_state_flags |= SAS_TASK_STATE_ABORTED; + /* hisi_sas_slot_task_free(hisi_hba, + * task, slot, slot_idx); */ + rc = hisi_sas_find_tag(hisi_hba, task, &tag); + if (rc == 0) { + dev_notice(hisi_hba->dev, + "No such tag in %s\n", __func__); + rc = TMF_RESP_FUNC_FAILED; + return rc; + } + + rc = hisi_sas_exec_internal_task_abort(hisi_hba, + hisi_sas_dev, dev, 0, tag); + + goto out; + } + } else if (task->task_proto & SAS_PROTOCOL_SMP) { + /* SMP */ + rc = hisi_sas_find_tag(hisi_hba, task, &tag); + if (rc == 0) { + dev_notice(hisi_hba->dev, + "No such tag in %s\n", __func__); + rc = TMF_RESP_FUNC_FAILED; + return rc; + } + + rc = hisi_sas_exec_internal_task_abort(hisi_hba, + hisi_sas_dev, dev, 0, tag); + + goto out; + } + +out: + if (rc != TMF_RESP_FUNC_COMPLETE) + dev_notice(hisi_hba->dev, "%s:rc = %d\n", __func__, rc); + return rc; +} + +int hisi_sas_internal_abort_task(struct sas_task *task) +{ + struct scsi_lun lun; + struct hisi_sas_tmf_task tmf_task; + struct domain_device *dev = task->dev; + struct hisi_sas_device *hisi_sas_dev = + (struct hisi_sas_device *)dev->lldd_dev; + struct hisi_hba *hisi_hba; + int rc = TMF_RESP_FUNC_FAILED; + unsigned long flags; + u32 tag; + + if (!hisi_sas_dev) { + pr_warn("%s Device has been removed\n", __func__); + return TMF_RESP_FUNC_FAILED; + } + + hisi_hba = dev_to_hisi_hba(task->dev); + + spin_lock_irqsave(&task->task_state_lock, flags); + if (task->task_state_flags & SAS_TASK_STATE_DONE) { + spin_unlock_irqrestore(&task->task_state_lock, flags); + rc = TMF_RESP_FUNC_COMPLETE; + goto out; + } + + spin_unlock_irqrestore(&task->task_state_lock, flags); + hisi_sas_dev->dev_status = HISI_SAS_DEV_EH; + if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { + struct scsi_cmnd *cmnd = (struct scsi_cmnd *)task->uldd_task; + + int_to_scsilun(cmnd->device->lun, &lun); + rc = hisi_sas_find_tag(hisi_hba, task, &tag); + if (rc == 0) { + dev_notice(hisi_hba->dev, + "No such tag in %s\n", __func__); + rc = TMF_RESP_FUNC_FAILED; + return rc; + } + + tmf_task.tmf = TMF_ABORT_TASK; + tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag); + + rc = hisi_sas_debug_issue_ssp_tmf(task->dev, + lun.scsi_lun, &tmf_task); + + } else if (task->task_proto & SAS_PROTOCOL_SATA || + task->task_proto & SAS_PROTOCOL_STP) { + if (SAS_SATA_DEV == task->dev->dev_type) { + struct hisi_slot_info *slot = task->lldd_task; + + dev_notice(hisi_hba->dev, "%s hba=%p task=%p slot=%p\n", + __func__, + hisi_hba, task, slot); + task->task_state_flags |= SAS_TASK_STATE_ABORTED; + rc = hisi_sas_find_tag(hisi_hba, task, &tag); + if (rc == 0) { + dev_notice(hisi_hba->dev, + "No such tag in %s\n", __func__); + rc = TMF_RESP_FUNC_FAILED; + return rc; + } + + goto out; + } + } else if (task->task_proto & SAS_PROTOCOL_SMP) { + /* SMP */ + rc = hisi_sas_find_tag(hisi_hba, task, &tag); + if (rc == 0) { + dev_notice(hisi_hba->dev, + "No such tag in %s\n", __func__); + rc = TMF_RESP_FUNC_FAILED; + return rc; + } + + goto out; + } + +out: + if (rc != TMF_RESP_FUNC_COMPLETE) + dev_notice(hisi_hba->dev, "%s:rc = %d\n", __func__, rc); + return rc; +} + +void hisi_sas_abort_and_retry_task(struct hisi_hba *hisi_hba, + struct sas_task *task) +{ + int rc; + struct hisi_sas_slot *slot; + unsigned long flags = 0; + u32 tag; + + /* abort task */ + rc = hisi_sas_internal_abort_task(task); + if (rc == TMF_RESP_FUNC_COMPLETE) { + + rc = hisi_sas_find_tag(hisi_hba, task, &tag); + slot = &hisi_hba->slot_info[cpu_to_le16(tag)]; + + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_slot_task_free(hisi_hba, task, slot); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + hisi_sas_task_exec(task, GFP_KERNEL, NULL, 0, NULL); + } +} + +void hisi_sas_work_fn(struct work_struct *work) +{ + struct hisi_sas_work *pw = + container_of(work, struct hisi_sas_work, work); + struct sas_task *task = pw->data; + struct hisi_hba *hisi_hba = pw->hisi_hba; + + if (task == NULL) + kfree(pw); + + switch (pw->handler) { + case SAS_ABORT_AND_RETRY: + hisi_sas_abort_and_retry_task(hisi_hba, task); + } +} + +int hisi_sas_handle_event(struct hisi_hba *hisi_hba, void *data, + int handler) +{ + struct hisi_sas_work *pw; + + int ret = 0; + + pw = kmalloc(sizeof(struct hisi_sas_work), GFP_ATOMIC); + if (pw) { + pw->hisi_hba = hisi_hba; + pw->data = data; + pw->handler = handler; + INIT_WORK(&pw->work, hisi_sas_work_fn); + queue_work(hisi_hba->wq, &pw->work); + } else + ret = -ENOMEM; + + return ret; +} #ifdef CONFIG_DEBUG_FS /***************************************************** for debug fs diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 1607fada5962..e01320e9089f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1418,6 +1418,7 @@ static int prep_ssp_v1_hw(struct hisi_hba *hisi_hba, default: dw1->ssp_frame_type = 0; } + hdr->data_transfer_len = scsi_transfer_length(scsi_cmnd); } dw1->device_id = hisi_sas_dev->device_id; /* map itct entry */ @@ -1447,7 +1448,7 @@ static int prep_ssp_v1_hw(struct hisi_hba *hisi_hba, } /* dw4 */ - hdr->data_transfer_len = scsi_transfer_length(scsi_cmnd); + /*hdr->data_transfer_len = scsi_transfer_length(scsi_cmnd);*/ /* dw5 */ /* hdr->first_burst_num not set in Higgs code */ @@ -1511,6 +1512,7 @@ static void slot_err_v1_hw(struct hisi_hba *hisi_hba, { struct task_status_struct *tstat = &task->task_status; struct hisi_sas_err_record *err_record = slot->status_buffer; + int rc = -1; switch (task->task_proto) { case SAS_PROTOCOL_SSP: @@ -1589,6 +1591,18 @@ static void slot_err_v1_hw(struct hisi_hba *hisi_hba, tstat->stat = SAS_NAK_R_ERR; break; } + case TRANS_TX_CREDIT_TIMEOUT_ERR: + case TRANS_TX_CLOSE_NORMAL_ERR: + { + task->task_state_flags &= ~SAS_TASK_STATE_DONE; + rc = hisi_sas_handle_event(hisi_hba, task, + SAS_ABORT_AND_RETRY); + if (!rc) { + tstat->stat = HISI_INTERNAL_EH_STAT; + return; + } + break; + } default: { tstat->stat = SAM_STAT_CHECK_CONDITION; @@ -1711,14 +1725,12 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba, goto out; } - if (!complete_hdr->err_rcrd_xfrd) { - if (!complete_hdr->cmd_complt || !complete_hdr->rspns_xfrd) { - tstat->stat = SAS_DATA_OVERRUN; - /* j00310691 in IT we get DID_ERROR, but in sas_end_task we need to use overrun to get DID_ERROR */ - goto out; - } - } else { + if (complete_hdr->err_rcrd_xfrd && !complete_hdr->rspns_xfrd) { slot_err_v1_hw(hisi_hba, task, slot); + + if (tstat->stat == HISI_INTERNAL_EH_STAT) + return 0; + goto out; } diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 17c3bdf092cf..b2520ff0f9c0 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -166,6 +166,7 @@ #define SAS0_RESET_MSK (0x7ffff) #define SAS2_RESET_VALUE (0x1fffff) #define SAS2_RESET_MSK (0x1fffff) +#define CONTROLLER_RESET_VALUE (0x7ffff) enum { HISI_SAS_PHY_HOTPLUG_TOUT, @@ -174,6 +175,144 @@ enum { HISI_SAS_PHY_INT_NR }; +enum { + TRANS_TX_FAIL_BASE = 0x0, + TRANS_RX_FAIL_BASE = 0x100, + DMA_TX_ERR_BASE = 0x200, + SIPC_RX_ERR_BASE = 0x300, + DMA_RX_ERR_BASE = 0x400, + + /* trans tx*/ + TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS = TRANS_TX_FAIL_BASE, /* 0x0 */ + TRANS_TX_ERR_PHY_NOT_ENABLE, /* 0x1 */ + TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION, /* 0x2 */ + TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION, /* 0x3 */ + TRANS_TX_OPEN_CNX_ERR_BY_OTHER, /* 0x4 */ + RESERVED0, /* 0x5 */ + TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT, /* 0x6 */ + TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY, /* 0x7 */ + TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED, /* 0x8 */ + TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED, /* 0x9 */ + TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION, /* 0xa */ + TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD, /* 0xb */ + TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER, /* 0xc */ + TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED, /* 0xd */ + TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT, /* 0xe */ + TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION, /* 0xf */ + TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED, /* 0x10 */ + TRANS_TX_ERR_FRAME_TXED, /* 0x11 */ + TRANS_TX_ERR_WITH_BREAK_TIMEOUT, /* 0x12 */ + TRANS_TX_ERR_WITH_BREAK_REQUEST, /* 0x13 */ + TRANS_TX_ERR_WITH_BREAK_RECEVIED, /* 0x14 */ + TRANS_TX_ERR_WITH_CLOSE_TIMEOUT, /* 0x15 */ + TRANS_TX_ERR_WITH_CLOSE_NORMAL, /* 0x16 */ + TRANS_TX_ERR_WITH_CLOSE_PHYDISALE, /* 0x17 */ + TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x18 */ + TRANS_TX_ERR_WITH_CLOSE_COMINIT, /* 0x19 */ + TRANS_TX_ERR_WITH_NAK_RECEVIED, /* 0x1a */ + TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT, /* 0x1b */ + /*IO_TX_ERR_WITH_R_ERR_RECEVIED, [> 0x1c <]*/ + TRANS_TX_ERR_WITH_CREDIT_TIMEOUT, /* 0x1c */ + /*IO_RX_ERR_WITH_SATA_DEVICE_LOST*/ + TRANS_TX_ERR_WITH_IPTT_CONFLICT, /* 0x1d */ + TRANS_TX_ERR_WITH_OPEN_BY_DES_OR_OTHERS, /* 0x1e */ + /*IO_TX_ERR_WITH_SYNC_RXD, [> 0x1e <]*/ + TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT, /* 0x1f */ + + /* trans rx */ + TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x100 */ + TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, /* 0x101 */ + TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, /* 0x102 */ + /*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x102 <]*/ + TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, /* 0x103 */ + TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, /* 0x104 */ + TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, /* 0x105 */ + /*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x105 <]*/ + TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, /* 0x106 */ + TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, /* 0x107 */ + TRANS_RX_ERR_WITH_BREAK_TIMEOUT, /* 0x108 */ + TRANS_RX_ERR_WITH_BREAK_REQUEST, /* 0x109 */ + TRANS_RX_ERR_WITH_BREAK_RECEVIED, /* 0x10a */ + RESERVED1, /* 0x10b */ + TRANS_RX_ERR_WITH_CLOSE_NORMAL, /* 0x10c */ + TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE, /* 0x10d */ + TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x10e */ + TRANS_RX_ERR_WITH_CLOSE_COMINIT, /* 0x10f */ + TRANS_RX_ERR_WITH_DATA_LEN0, /* 0x110 */ + TRANS_RX_ERR_WITH_BAD_HASH, /* 0x111 */ + /*IO_RX_ERR_WITH_FIS_TOO_SHORT, [> 0x111 <]*/ + TRANS_RX_XRDY_WLEN_ZERO_ERR, /* 0x112 */ + /*IO_RX_ERR_WITH_FIS_TOO_LONG, [> 0x112 <]*/ + TRANS_RX_SSP_FRM_LEN_ERR, /* 0x113 */ + /*IO_RX_ERR_WITH_SATA_DEVICE_LOST, [> 0x113 <]*/ + RESERVED2, /* 0x114 */ + RESERVED3, /* 0x115 */ + RESERVED4, /* 0x116 */ + RESERVED5, /* 0x117 */ + TRANS_RX_ERR_WITH_BAD_FRM_TYPE, /* 0x118 */ + TRANS_RX_SMP_FRM_LEN_ERR, /* 0x119 */ + TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x11a */ + RESERVED6, /* 0x11b */ + RESERVED7, /* 0x11c */ + RESERVED8, /* 0x11d */ + RESERVED9, /* 0x11e */ + TRANS_RX_R_ERR, /* 0x11f */ + + /* dma tx */ + DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x200 */ + DMA_TX_DIF_APP_ERR, /* 0x201 */ + DMA_TX_DIF_RPP_ERR, /* 0x202 */ + DMA_TX_DATA_SGL_OVERFLOW, /* 0x203 */ + DMA_TX_DIF_SGL_OVERFLOW, /* 0x204 */ + DMA_TX_UNEXP_XFER_ERR, /* 0x205 */ + DMA_TX_UNEXP_RETRANS_ERR, /* 0x206 */ + DMA_TX_XFER_LEN_OVERFLOW, /* 0x207 */ + DMA_TX_XFER_OFFSET_ERR, /* 0x208 */ + DMA_TX_RAM_ECC_ERR, /* 0x209 */ + DMA_TX_DIF_LEN_ALIGN_ERR, /* 0x20a */ + + /* sipc rx */ + SIPC_RX_FIS_STATUS_ERR_BIT_VLD = SIPC_RX_ERR_BASE, /* 0x300 */ + SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR, /* 0x301 */ + SIPC_RX_FIS_STATUS_BSY_BIT_ERR, /* 0x302 */ + SIPC_RX_WRSETUP_LEN_ODD_ERR, /* 0x303 */ + SIPC_RX_WRSETUP_LEN_ZERO_ERR, /* 0x304 */ + SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR, /* 0x305 */ + SIPC_RX_NCQ_WRSETUP_OFFSET_ERR, /* 0x306 */ + SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR, /* 0x307 */ + SIPC_RX_SATA_UNEXP_FIS_ERR, /* 0x308 */ + SIPC_RX_WRSETUP_ESTATUS_ERR, /* 0x309 */ + SIPC_RX_DATA_UNDERFLOW_ERR, /* 0x30a */ + + /* dma rx */ + DMA_RX_DIF_CRC_ERR = DMA_RX_ERR_BASE, /* 0x400 */ + DMA_RX_DIF_APP_ERR, /* 0x401 */ + DMA_RX_DIF_RPP_ERR, /* 0x402 */ + DMA_RX_DATA_SGL_OVERFLOW, /* 0x403 */ + DMA_RX_DIF_SGL_OVERFLOW, /* 0x404 */ + DMA_RX_DATA_LEN_OVERFLOW, /* 0x405 */ + DMA_RX_DATA_LEN_UNDERFLOW, /* 0x406 */ + DMA_RX_DATA_OFFSET_ERR, /* 0x407 */ + RESERVED10, /* 0x408 */ + DMA_RX_SATA_FRAME_TYPE_ERR, /* 0x409 */ + DMA_RX_RESP_BUF_OVERFLOW, /* 0x40a */ + DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x40b */ + DMA_RX_UNEXP_NORM_RESP_ERR, /* 0x40c */ + DMA_RX_UNEXP_RDFRAME_ERR, /* 0x40d */ + DMA_RX_PIO_DATA_LEN_ERR, /* 0x40e */ + DMA_RX_RDSETUP_STATUS_ERR, /* 0x40f */ + DMA_RX_RDSETUP_STATUS_DRQ_ERR, /* 0x410 */ + DMA_RX_RDSETUP_STATUS_BSY_ERR, /* 0x411 */ + DMA_RX_RDSETUP_LEN_ODD_ERR, /* 0x412 */ + DMA_RX_RDSETUP_LEN_ZERO_ERR, /* 0x413 */ + DMA_RX_RDSETUP_LEN_OVER_ERR, /* 0x414 */ + DMA_RX_RDSETUP_OFFSET_ERR, /* 0x415 */ + DMA_RX_RDSETUP_ACTIVE_ERR, /* 0x416 */ + DMA_RX_RDSETUP_ESTATUS_ERR, /* 0x417 */ + DMA_RX_RAM_ECC_ERR, /* 0x418 */ + DMA_RX_UNKNOWN_FRM_ERR, /* 0x419 */ +}; + #define HISI_SAS_PHY_MAX_INT_NR (HISI_SAS_PHY_INT_NR * HISI_SAS_MAX_PHYS) #define HISI_SAS_CQ_MAX_INT_NR (HISI_SAS_MAX_QUEUES) #define HISI_SAS_FATAL_INT_NR (2) @@ -216,6 +355,21 @@ struct hisi_sas_cmd_hdr_dw2_v2_hw { u32 rsvd:5; }; +struct hisi_sas_err_record_v2_hw { + /* dw0 */ + u32 trans_tx_fail_type; + + /* dw1 */ + u32 trans_rx_fail_type; + + /* dw2 */ + u32 dma_tx_err_type:16; + u32 sipc_rx_err_type:16; + + /* dw3 */ + u32 dma_rx_err_type; +} __packed; + #ifdef SAS_DIF struct protect_iu_v2_hw { /* dw0 */ @@ -252,6 +406,7 @@ struct protect_iu_v2_hw { #define SATA_PROTOCOL_FPDMA 0x8 #define SATA_PROTOCOL_ATAPI 0x10 +#define CMPL_STATUS_ABORTED 0x2 /* Completion queue header */ struct hisi_sas_complete_hdr_v2_hw { /* dw0 */ @@ -500,7 +655,6 @@ static int free_device_v2_hw(struct hisi_hba *hisi_hba, if (ENT_INT_SRC3_ITC_INT_MSK & reg_val) { hisi_sas_write32(hisi_hba, ENT_INT_SRC3, ENT_INT_SRC3_ITC_INT_MSK); } - /* clear the itct int*/ for (i = 0; i < 2; i++) { /* clear the itct table*/ @@ -656,8 +810,8 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1); hisi_sas_write32(hisi_hba, HGC_ERR_STAT_EN, 0x1); hisi_sas_write32(hisi_hba, HGC_GET_ITV_TIME, 0x1); - hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1); - hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x1); + hisi_sas_write32(hisi_hba, INT_COAL_EN, 0xc); + hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x186a0); hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x1); hisi_sas_write32(hisi_hba, ENT_INT_COAL_TIME, 0x1); hisi_sas_write32(hisi_hba, ENT_INT_COAL_CNT, 0x1); @@ -1162,7 +1316,10 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba, dw0->force_phy = 0; /* do not force ordering in phy */ dw0->port = sas_port->id; /* double-check */ /* hdr->sata_reg_set not applicable to smp */ - dw0->priority = 0; /* ordinary priority */ + if (is_tmf) + dw0->priority = 1; + else + dw0->priority = 0; /* ordinary priority */ dw0->cmd = 1; /* ssp */ /* dw1 */ @@ -1190,12 +1347,18 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba, /*l00293075 must be 0, or hw will return error*/ dw1->dir = 0; } + hdr->data_transfer_len = scsi_transfer_length(scsi_cmnd); } dw1->device_id = hisi_sas_dev->device_id; /* map itct entry */ /* dw2 */ - dw2->cmd_frame_len = (sizeof(struct ssp_command_iu) + + if (is_tmf) { + dw2->cmd_frame_len = (sizeof(struct ssp_task_iu) + + sizeof(struct ssp_frame_hdr) + 3) / 4; + } else { + dw2->cmd_frame_len = (sizeof(struct ssp_command_iu) + sizeof(struct ssp_frame_hdr) + 3) / 4; + } /* hdr->leave_affil_open only applicable to stp */ dw2->max_resp_frame_len = HISI_SAS_MAX_SSP_RESP_SZ/4; dw2->sg_mode = 2; /* see Higgs_DQGlobalConfig */ @@ -1213,7 +1376,7 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba, } /* dw4 */ - hdr->data_transfer_len = scsi_transfer_length(scsi_cmnd); + /*hdr->data_transfer_len = scsi_transfer_length(scsi_cmnd);*/ /* dw5 */ /* hdr->first_burst_num not set in Higgs code */ @@ -1244,6 +1407,7 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba, /* fill in IU for TASK and Command Frame */ if (task->ssp_task.enable_first_burst) { fburst = (1 << 7); + dw2->first_burst = 1; pr_warn("%s fburst enabled: edit hdr?\n", __func__); } @@ -1299,6 +1463,298 @@ static int sata_done_v2_hw(struct hisi_hba *hisi_hba, struct sas_task *task, return stat; } + +/* by default, task resp is complete */ +static void slot_err_v2_hw(struct hisi_hba *hisi_hba, + struct sas_task *task, + struct hisi_sas_slot *slot) +{ + struct task_status_struct *tstat = &task->task_status; + struct hisi_sas_err_record_v2_hw *err_record = slot->status_buffer; + + int error = -1; + int rc = -1; + + error = ffs(err_record->trans_tx_fail_type) + - 1 + TRANS_TX_FAIL_BASE; + + /* we need to abort task when we get this error. + * This error means ,there may has an IO in drive + */ + + if (error == TRANS_TX_ERR_FRAME_TXED) { + task->task_state_flags &= ~SAS_TASK_STATE_DONE; + rc = hisi_sas_handle_event(hisi_hba, task, SAS_ABORT_AND_RETRY); + if (!rc) { + tstat->stat = HISI_INTERNAL_EH_STAT; + return; + } + } + + if (err_record->dma_rx_err_type) { + /* dma rx err */ + error = ffs(err_record->dma_rx_err_type) + - 1 + DMA_RX_ERR_BASE; + } else if (err_record->sipc_rx_err_type) { + /* sipc rx err */ + error = ffs(err_record->sipc_rx_err_type) + - 1 + SIPC_RX_ERR_BASE; + } else if (err_record->dma_tx_err_type) { + /* dma tx err */ + error = ffs(err_record->dma_tx_err_type) + - 1 + DMA_TX_ERR_BASE; + } else if (err_record->trans_rx_fail_type) { + /* trans rx err */ + error = ffs(err_record->trans_rx_fail_type) + - 1 + TRANS_RX_FAIL_BASE; + } else if (err_record->trans_tx_fail_type) { + /* trans tx err */ + error = ffs(err_record->trans_tx_fail_type) + - 1 + TRANS_TX_FAIL_BASE; + } + + switch (task->task_proto) { + case SAS_PROTOCOL_SSP: + { + switch (error) { + case TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION: + { + tstat->stat = SAS_OPEN_REJECT; + tstat->open_rej_reason = SAS_OREJ_NO_DEST; + break; + } + case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED: + { + tstat->stat = SAS_OPEN_REJECT; + tstat->open_rej_reason = SAS_OREJ_PATH_BLOCKED; + break; + } + case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED: + { + tstat->stat = SAS_OPEN_REJECT; + tstat->open_rej_reason = SAS_OREJ_EPROTO; + break; + } + case TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED: + { + tstat->stat = SAS_OPEN_REJECT; + tstat->open_rej_reason = SAS_OREJ_CONN_RATE; + break; + } + case TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION: + { + tstat->stat = SAS_OPEN_REJECT; + tstat->open_rej_reason = SAS_OREJ_BAD_DEST; + break; + } + case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD: + { + tstat->stat = SAS_OPEN_REJECT; + tstat->open_rej_reason = SAS_OREJ_RSVD_RETRY; + break; + } + case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION: + { + tstat->stat = SAS_OPEN_REJECT; + tstat->open_rej_reason = SAS_OREJ_WRONG_DEST; + break; + } + case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION: + { + tstat->stat = SAS_OPEN_REJECT; + tstat->open_rej_reason = SAS_OREJ_UNKNOWN; + break; + } + case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER: + { + /* not sure */ + tstat->stat = SAS_DEV_NO_RESPONSE; + break; + } + case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE: + { + tstat->stat = SAS_TASK_UNDELIVERED; + tstat->stat = SAS_PHY_DOWN; + break; + } + case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT: + { + /* from aic94xx */ + tstat->resp = SAS_TASK_UNDELIVERED; + tstat->stat = SAS_OPEN_TO; + break; + } + case DMA_RX_DATA_LEN_OVERFLOW: + { + tstat->stat = SAS_DATA_OVERRUN; + tstat->residual = 0; + break; + } + case DMA_RX_DATA_LEN_UNDERFLOW: + case SIPC_RX_DATA_UNDERFLOW_ERR: + { + /* dw0 has the residual */ + tstat->residual = err_record->trans_tx_fail_type; + tstat->stat = SAS_DATA_UNDERRUN; + break; + } + case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS: + case TRANS_TX_ERR_PHY_NOT_ENABLE: + case TRANS_TX_OPEN_CNX_ERR_BY_OTHER: + case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT: + case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED: + case TRANS_TX_ERR_WITH_BREAK_TIMEOUT: + case TRANS_TX_ERR_WITH_BREAK_REQUEST: + case TRANS_TX_ERR_WITH_BREAK_RECEVIED: + case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT: + case TRANS_TX_ERR_WITH_CLOSE_NORMAL: + case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT: + case TRANS_TX_ERR_WITH_CLOSE_COMINIT: + case TRANS_TX_ERR_WITH_NAK_RECEVIED: + case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT: + case TRANS_TX_ERR_WITH_IPTT_CONFLICT: + case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT: + case TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR: + case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR: + case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM: + case TRANS_RX_ERR_WITH_BREAK_TIMEOUT: + case TRANS_RX_ERR_WITH_BREAK_REQUEST: + case TRANS_RX_ERR_WITH_BREAK_RECEVIED: + case TRANS_RX_ERR_WITH_CLOSE_NORMAL: + case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT: + case TRANS_RX_ERR_WITH_CLOSE_COMINIT: + case TRANS_RX_ERR_WITH_DATA_LEN0: + case TRANS_RX_ERR_WITH_BAD_HASH: + case TRANS_RX_XRDY_WLEN_ZERO_ERR: + case TRANS_RX_SSP_FRM_LEN_ERR: + case TRANS_RX_ERR_WITH_BAD_FRM_TYPE: + case DMA_TX_UNEXP_XFER_ERR: + case DMA_TX_UNEXP_RETRANS_ERR: + case DMA_TX_XFER_LEN_OVERFLOW: + case DMA_TX_XFER_OFFSET_ERR: + case DMA_RX_DATA_OFFSET_ERR: + case DMA_RX_UNEXP_NORM_RESP_ERR: + case DMA_RX_UNEXP_RDFRAME_ERR: + case DMA_RX_UNKNOWN_FRM_ERR: + { + tstat->stat = SAS_OPEN_REJECT; + tstat->open_rej_reason = SAS_OREJ_UNKNOWN; + break; + } + default: + break; + } + } + break; + case SAS_PROTOCOL_SMP: + tstat->stat = SAM_STAT_CHECK_CONDITION; + break; + + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: + case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: + { + switch (error) { + case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER: + case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED: + case TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION: + { + tstat->resp = SAS_TASK_UNDELIVERED; + tstat->stat = SAS_DEV_NO_RESPONSE; + break; + } + case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED: + case TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED: + case TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION: + case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD: + case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION: + case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION: + case TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY: + { + tstat->stat = SAS_OPEN_REJECT; + break; + } + case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT: + { + tstat->stat = SAS_OPEN_TO; + break; + } + case DMA_RX_DATA_LEN_OVERFLOW: + { + tstat->stat = SAS_DATA_OVERRUN; + break; + } + case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS: + case TRANS_TX_ERR_PHY_NOT_ENABLE: + case TRANS_TX_OPEN_CNX_ERR_BY_OTHER: + case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT: + case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED: + case TRANS_TX_ERR_WITH_BREAK_TIMEOUT: + case TRANS_TX_ERR_WITH_BREAK_REQUEST: + case TRANS_TX_ERR_WITH_BREAK_RECEVIED: + case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT: + case TRANS_TX_ERR_WITH_CLOSE_NORMAL: + case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT: + case TRANS_TX_ERR_WITH_CLOSE_COMINIT: + case TRANS_TX_ERR_WITH_NAK_RECEVIED: + case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT: + case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT: + case TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT: + case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR: + case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM: + /*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x102 <]*/ + case TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR: + case TRANS_RX_ERR_WITH_RXFIS_CRC_ERR: + case TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN: + /*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x105 <]*/ + case TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP: + case TRANS_RX_ERR_WITH_CLOSE_NORMAL: + case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE: + case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT: + case TRANS_RX_ERR_WITH_CLOSE_COMINIT: + case TRANS_RX_ERR_WITH_DATA_LEN0: + case TRANS_RX_ERR_WITH_BAD_HASH: + /*IO_RX_ERR_WITH_FIS_TOO_SHORT, [> 0x111 <]*/ + case TRANS_RX_XRDY_WLEN_ZERO_ERR: + /*IO_RX_ERR_WITH_FIS_TOO_LONG, [> 0x112 <]*/ + case TRANS_RX_SSP_FRM_LEN_ERR: + /*IO_RX_ERR_WITH_SATA_DEVICE_LOST, [> 0x113 <]*/ + case SIPC_RX_FIS_STATUS_ERR_BIT_VLD: + case SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR: + case SIPC_RX_FIS_STATUS_BSY_BIT_ERR: + case SIPC_RX_WRSETUP_LEN_ODD_ERR: + case SIPC_RX_WRSETUP_LEN_ZERO_ERR: + case SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR: + case SIPC_RX_SATA_UNEXP_FIS_ERR: + case DMA_RX_SATA_FRAME_TYPE_ERR: + case DMA_RX_UNEXP_RDFRAME_ERR: + case DMA_RX_PIO_DATA_LEN_ERR: + case DMA_RX_RDSETUP_STATUS_ERR: + case DMA_RX_RDSETUP_STATUS_DRQ_ERR: + case DMA_RX_RDSETUP_STATUS_BSY_ERR: + case DMA_RX_RDSETUP_LEN_ODD_ERR: + case DMA_RX_RDSETUP_LEN_ZERO_ERR: + case DMA_RX_RDSETUP_LEN_OVER_ERR: + case DMA_RX_RDSETUP_OFFSET_ERR: + case DMA_RX_RDSETUP_ACTIVE_ERR: + case DMA_RX_RDSETUP_ESTATUS_ERR: + case DMA_RX_UNKNOWN_FRM_ERR: + { + tstat->stat = SAS_OPEN_REJECT; + break; + } + default: + break; + } + /*hisi_sas_sata_done_fail(task, slot);*/ + task->ata_task.use_ncq = 0; + } + break; + default: + break; + } +} + static int slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, int flags) { @@ -1311,9 +1767,11 @@ static int slot_complete_v2_hw(struct hisi_hba *hisi_hba, (struct hisi_sas_complete_hdr_v2_hw *) hisi_hba->complete_hdr[slot->cmplt_queue]; struct hisi_sas_complete_hdr_v2_hw *complete_hdr; + u32 aborted; complete_hdr = &complete_queue[slot->cmplt_queue_slot]; + /*dump_cq(complete_hdr);*/ if (unlikely(!task || !task->lldd_task || !task->dev)) @@ -1323,13 +1781,26 @@ static int slot_complete_v2_hw(struct hisi_hba *hisi_hba, dev = task->dev; hisi_sas_dev = dev->lldd_dev; + spin_lock(&task->task_state_lock); task->task_state_flags &= ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); task->task_state_flags |= SAS_TASK_STATE_DONE; + aborted = (task->task_state_flags & SAS_TASK_STATE_ABORTED) + | (complete_hdr->cmpl_status == CMPL_STATUS_ABORTED); + spin_unlock(&task->task_state_lock); memset(tstat, 0, sizeof(*tstat)); tstat->resp = SAS_TASK_COMPLETE; + if (unlikely(aborted)) { + tstat->stat = SAS_ABORTED_TASK; + if (hisi_sas_dev && hisi_sas_dev->running_req) + hisi_sas_dev->running_req--; + + hisi_sas_slot_task_free(hisi_hba, task, slot); + return -1; + } + /* when no device attaching, go ahead and complete by error handling */ if (unlikely(!hisi_sas_dev || flags)) { if (!hisi_sas_dev) @@ -1339,12 +1810,15 @@ static int slot_complete_v2_hw(struct hisi_hba *hisi_hba, goto out; } - if (complete_hdr->err_rcrd_xfrd) { + if (complete_hdr->err_rcrd_xfrd && !complete_hdr->rspns_xfrd) { dev_dbg(hisi_hba->dev, "%s slot %d has error info 0x%x\n", __func__, slot->cmplt_queue_slot, complete_hdr->err_rcrd_xfrd); - /* tstat->stat = hisi_sas_slot_err(hisi_hba, task, slot); fixme j00310691 */ - tstat->resp = SAS_TASK_COMPLETE; + + slot_err_v2_hw(hisi_hba, task, slot); + /* we will do abort & retry, this io should drop directly */ + if (tstat->stat == HISI_INTERNAL_EH_STAT) + return 0; goto out; } @@ -1590,6 +2064,67 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba, return 0; } +static int prep_abort_hw_v2(struct hisi_hba *hisi_hba, + struct hisi_sas_tei *tei, + struct task_abort_req *task_abort) + /*int abort_flag,*/ + /*struct hisi_sas_device *dev_to_abort,*/ + /*int tag_to_abort)*/ +{ + struct sas_task *task = tei->task; + struct domain_device *dev = task->dev; + struct hisi_sas_device *hisi_sas_dev = dev->lldd_dev; + struct hisi_sas_device *hisi_dev; + struct hisi_sas_cmd_hdr *hdr = tei->hdr; + struct asd_sas_port *sas_port = dev->port; + int port_id; + + struct hisi_sas_cmd_hdr_dw0_v2_hw *dw0 = + (struct hisi_sas_cmd_hdr_dw0_v2_hw *)&hdr->dw0; + struct hisi_sas_cmd_hdr_dw1_v2_hw *dw1 = + (struct hisi_sas_cmd_hdr_dw1_v2_hw *)&hdr->dw1; + + /* check whether abort a single task or abort device tasks */ + /*if (!abort_flag)*/ + /*hisi_dev = hisi_sas_dev;*/ + /*else*/ + /*hisi_dev = dev_to_abort;*/ + + /*sas_port = dev->port;*/ + + /* c00308265, get hw wide port id */ + /*port_id = hisi_get_hw_wide_port_id_by_sas_port(sas_port);*/ + /*if (unlikely(port_id == -1))*/ + /*return -1;*/ + + /* create header */ + /* dw0 */ + dw0->cmd = 5; /* abort command */ + dw0->priority = 1; + dw0->force_phy = 0; + /*dw0->port = port_id;*/ + dw0->port = sas_port->id; /* double-check */ + + if (dev->dev_type == SAS_SATA_DEV) + dw0->abort_device_type = 1; + else + dw0->abort_device_type = 0; + + dw0->abort_flag = task_abort->abort_all; + + /*dw1->device_id = hisi_dev->device_id;*/ + dw1->device_id = task_abort->device_id; + + hdr->iptt = tei->iptt; + hdr->tptt = 0; + + if (!task_abort->abort_all) + /*hdr->abort_iptt = tag_to_abort;*/ + hdr->abort_iptt = task_abort->tag_to_abort; + + return 0; +} + static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) { int i, res = 0; @@ -2213,6 +2748,7 @@ const struct hisi_sas_dispatch hisi_sas_dispatch_v2_hw = { .prep_ssp = prep_ssp_v2_hw, .prep_smp = prep_smp_v2_hw, .prep_stp = prep_ata_v2_hw, + .prep_abort = prep_abort_hw_v2, .slot_complete = slot_complete_v2_hw, .phy_enable = enable_phy_v2_hw, .phy_disable = disable_phy_v2_hw, diff --git a/drivers/scsi/hisi_sas/serdes.c b/drivers/scsi/hisi_sas/serdes.c index 0872fe4f2ef4..a4d8668c481b 100644 --- a/drivers/scsi/hisi_sas/serdes.c +++ b/drivers/scsi/hisi_sas/serdes.c @@ -1313,7 +1313,6 @@ unsigned int HRD_SubPcieInit(void) return OS_SUCCESS; } - /***************************************************************************** : HRD_SubPcieExit : SUB PCIE CRG @@ -1344,6 +1343,7 @@ static void HRD_SubPcieExit(void) iounmap((void *)sub_pcie_base_addr_slavecpu); } #endif + static unsigned long long HRD_CommonSubPcieGetBase(unsigned int node) { /* node=0 */ @@ -1353,6 +1353,7 @@ static unsigned long long HRD_CommonSubPcieGetBase(unsigned int node) return sub_pcie_base_addr_slavecpu; } + static inline unsigned int SYSTEM_REG_READ(unsigned int node, unsigned long long pRegBase) { |