summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorflyingnosky <flyingnosky@163.com>2015-11-05 21:21:18 +0800
committerflyingnosky <flyingnosky@163.com>2015-11-06 10:01:34 +0800
commit0491d5569066ae6ae21544bd5774f80c29e33a3c (patch)
treeeea45d02afc2c05fdace121138f10ff20c4f47f5
parentfe83387e19b88a97b8c0b40ecc5627b1e8a25afd (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.h35
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_init.c2
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c534
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v1_hw.c28
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v2_hw.c554
-rw-r--r--drivers/scsi/hisi_sas/serdes.c3
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)
{