aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Garry <john.garry@huawei.com>2016-08-24 07:05:47 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2016-08-25 22:38:53 -0400
commit441c27401470c417cf4a33ab9c17bcefdf1ecca3 (patch)
tree010221d4afff074a893c9e577514b28a16bfbcc3
parent108c8670df99dd689494c0ba981b5e82c863caf2 (diff)
scsi: hisi_sas: add internal abort main code
Add main code for internal abort functionality. The internal abort features allows the host controller to abort commands which are still active in the controller but have not yet been sent to the slave device. Typically a command only spends a relatively short time in the controller when compared to the amount of the time after it is sent to the slave device. Two modes of internal abort are supported: - device - individual command For device, when the internal abort is issued all commands in the host for that device are aborted. For a single command, only that command is aborted if it is still in the host. In HW the internal abort command is executed similar to any other sort of command, like SSP. Signed-off-by: John Garry <john.garry@huawei.com> Reviewed-by: Hannes Reinecke <hare@suse.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas.h8
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c163
2 files changed, 171 insertions, 0 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 4731d3241323..83113600721c 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -56,6 +56,11 @@ enum dev_status {
56 HISI_SAS_DEV_EH, 56 HISI_SAS_DEV_EH,
57}; 57};
58 58
59enum {
60 HISI_SAS_INT_ABT_CMD = 0,
61 HISI_SAS_INT_ABT_DEV = 1,
62};
63
59enum hisi_sas_dev_type { 64enum hisi_sas_dev_type {
60 HISI_SAS_DEV_TYPE_STP = 0, 65 HISI_SAS_DEV_TYPE_STP = 0,
61 HISI_SAS_DEV_TYPE_SSP, 66 HISI_SAS_DEV_TYPE_SSP,
@@ -146,6 +151,9 @@ struct hisi_sas_hw {
146 struct hisi_sas_slot *slot); 151 struct hisi_sas_slot *slot);
147 int (*prep_stp)(struct hisi_hba *hisi_hba, 152 int (*prep_stp)(struct hisi_hba *hisi_hba,
148 struct hisi_sas_slot *slot); 153 struct hisi_sas_slot *slot);
154 int (*prep_abort)(struct hisi_hba *hisi_hba,
155 struct hisi_sas_slot *slot,
156 int device_id, int abort_flag, int tag_to_abort);
149 int (*slot_complete)(struct hisi_hba *hisi_hba, 157 int (*slot_complete)(struct hisi_hba *hisi_hba,
150 struct hisi_sas_slot *slot, int abort); 158 struct hisi_sas_slot *slot, int abort);
151 void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no); 159 void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 18dd5ea2c721..763c6c58e4b9 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -17,6 +17,10 @@
17 17
18static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, 18static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
19 u8 *lun, struct hisi_sas_tmf_task *tmf); 19 u8 *lun, struct hisi_sas_tmf_task *tmf);
20static int
21hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
22 struct domain_device *device,
23 int abort_flag, int tag);
20 24
21static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device) 25static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
22{ 26{
@@ -116,6 +120,14 @@ static int hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba,
116 return hisi_hba->hw->prep_stp(hisi_hba, slot); 120 return hisi_hba->hw->prep_stp(hisi_hba, slot);
117} 121}
118 122
123static int hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba,
124 struct hisi_sas_slot *slot,
125 int device_id, int abort_flag, int tag_to_abort)
126{
127 return hisi_hba->hw->prep_abort(hisi_hba, slot,
128 device_id, abort_flag, tag_to_abort);
129}
130
119/* 131/*
120 * This function will issue an abort TMF regardless of whether the 132 * This function will issue an abort TMF regardless of whether the
121 * task is in the sdev or not. Then it will do the task complete 133 * task is in the sdev or not. Then it will do the task complete
@@ -954,6 +966,157 @@ static int hisi_sas_query_task(struct sas_task *task)
954 return rc; 966 return rc;
955} 967}
956 968
969static int
970hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id,
971 struct sas_task *task, int abort_flag,
972 int task_tag)
973{
974 struct domain_device *device = task->dev;
975 struct hisi_sas_device *sas_dev = device->lldd_dev;
976 struct device *dev = &hisi_hba->pdev->dev;
977 struct hisi_sas_port *port;
978 struct hisi_sas_slot *slot;
979 struct hisi_sas_cmd_hdr *cmd_hdr_base;
980 int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
981
982 if (!device->port)
983 return -1;
984
985 port = device->port->lldd_port;
986
987 /* simply get a slot and send abort command */
988 rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
989 if (rc)
990 goto err_out;
991 rc = hisi_hba->hw->get_free_slot(hisi_hba, &dlvry_queue,
992 &dlvry_queue_slot);
993 if (rc)
994 goto err_out_tag;
995
996 slot = &hisi_hba->slot_info[slot_idx];
997 memset(slot, 0, sizeof(struct hisi_sas_slot));
998
999 slot->idx = slot_idx;
1000 slot->n_elem = n_elem;
1001 slot->dlvry_queue = dlvry_queue;
1002 slot->dlvry_queue_slot = dlvry_queue_slot;
1003 cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
1004 slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot];
1005 slot->task = task;
1006 slot->port = port;
1007 task->lldd_task = slot;
1008
1009 memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
1010
1011 rc = hisi_sas_task_prep_abort(hisi_hba, slot, device_id,
1012 abort_flag, task_tag);
1013 if (rc)
1014 goto err_out_tag;
1015
1016 /* Port structure is static for the HBA, so
1017 * even if the port is deformed it is ok
1018 * to reference.
1019 */
1020 list_add_tail(&slot->entry, &port->list);
1021 spin_lock(&task->task_state_lock);
1022 task->task_state_flags |= SAS_TASK_AT_INITIATOR;
1023 spin_unlock(&task->task_state_lock);
1024
1025 hisi_hba->slot_prep = slot;
1026
1027 sas_dev->running_req++;
1028 /* send abort command to our chip */
1029 hisi_hba->hw->start_delivery(hisi_hba);
1030
1031 return 0;
1032
1033err_out_tag:
1034 hisi_sas_slot_index_free(hisi_hba, slot_idx);
1035err_out:
1036 dev_err(dev, "internal abort task prep: failed[%d]!\n", rc);
1037
1038 return rc;
1039}
1040
1041/**
1042 * hisi_sas_internal_task_abort -- execute an internal
1043 * abort command for single IO command or a device
1044 * @hisi_hba: host controller struct
1045 * @device: domain device
1046 * @abort_flag: mode of operation, device or single IO
1047 * @tag: tag of IO to be aborted (only relevant to single
1048 * IO mode)
1049 */
1050static int
1051hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
1052 struct domain_device *device,
1053 int abort_flag, int tag)
1054{
1055 struct sas_task *task;
1056 struct hisi_sas_device *sas_dev = device->lldd_dev;
1057 struct device *dev = &hisi_hba->pdev->dev;
1058 int res;
1059 unsigned long flags;
1060
1061 if (!hisi_hba->hw->prep_abort)
1062 return -EOPNOTSUPP;
1063
1064 task = sas_alloc_slow_task(GFP_KERNEL);
1065 if (!task)
1066 return -ENOMEM;
1067
1068 task->dev = device;
1069 task->task_proto = device->tproto;
1070 task->task_done = hisi_sas_task_done;
1071 task->slow_task->timer.data = (unsigned long)task;
1072 task->slow_task->timer.function = hisi_sas_tmf_timedout;
1073 task->slow_task->timer.expires = jiffies + 20*HZ;
1074 add_timer(&task->slow_task->timer);
1075
1076 /* Lock as we are alloc'ing a slot, which cannot be interrupted */
1077 spin_lock_irqsave(&hisi_hba->lock, flags);
1078 res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id,
1079 task, abort_flag, tag);
1080 spin_unlock_irqrestore(&hisi_hba->lock, flags);
1081 if (res) {
1082 del_timer(&task->slow_task->timer);
1083 dev_err(dev, "internal task abort: executing internal task failed: %d\n",
1084 res);
1085 goto exit;
1086 }
1087 wait_for_completion(&task->slow_task->completion);
1088 res = TMF_RESP_FUNC_FAILED;
1089
1090 if (task->task_status.resp == SAS_TASK_COMPLETE &&
1091 task->task_status.stat == TMF_RESP_FUNC_COMPLETE) {
1092 res = TMF_RESP_FUNC_COMPLETE;
1093 goto exit;
1094 }
1095
1096 /* TMF timed out, return direct. */
1097 if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
1098 if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
1099 dev_err(dev, "internal task abort: timeout.\n");
1100 if (task->lldd_task) {
1101 struct hisi_sas_slot *slot = task->lldd_task;
1102
1103 hisi_sas_slot_task_free(hisi_hba, task, slot);
1104 }
1105 }
1106 }
1107
1108exit:
1109 dev_info(dev, "internal task abort: task to dev %016llx task=%p "
1110 "resp: 0x%x sts 0x%x\n",
1111 SAS_ADDR(device->sas_addr),
1112 task,
1113 task->task_status.resp, /* 0 is complete, -1 is undelivered */
1114 task->task_status.stat);
1115 sas_free_task(task);
1116
1117 return res;
1118}
1119
957static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy) 1120static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy)
958{ 1121{
959 hisi_sas_port_notify_formed(sas_phy); 1122 hisi_sas_port_notify_formed(sas_phy);