diff options
author | John Garry <john.garry@huawei.com> | 2016-01-25 13:47:20 -0500 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2016-02-23 21:27:02 -0500 |
commit | 6f2ff1a1311e618836a8d1b8a3a6ca4af8509820 (patch) | |
tree | 890f26a2dd499b3e78f828c43e9bbf6a7eb5952b /drivers/scsi | |
parent | 85b2c3c040ccb15109bb286139b03ce8817b2c7c (diff) |
hisi_sas: add v2 path to send ATA command
Signed-off-by: John Garry <john.garry@huawei.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas.h | 4 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_main.c | 8 | ||||
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 162 |
3 files changed, 174 insertions, 0 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index b2e4b26fd6c7..f00b55b241e5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/regmap.h> | 20 | #include <linux/regmap.h> |
21 | #include <scsi/sas_ata.h> | ||
21 | #include <scsi/libsas.h> | 22 | #include <scsi/libsas.h> |
22 | 23 | ||
23 | #define DRV_VERSION "v1.0" | 24 | #define DRV_VERSION "v1.0" |
@@ -35,6 +36,7 @@ | |||
35 | 36 | ||
36 | #define HISI_SAS_MAX_SSP_RESP_SZ (sizeof(struct ssp_frame_hdr) + 1024) | 37 | #define HISI_SAS_MAX_SSP_RESP_SZ (sizeof(struct ssp_frame_hdr) + 1024) |
37 | #define HISI_SAS_MAX_SMP_RESP_SZ 1028 | 38 | #define HISI_SAS_MAX_SMP_RESP_SZ 1028 |
39 | #define HISI_SAS_MAX_STP_RESP_SZ 28 | ||
38 | 40 | ||
39 | #define DEV_IS_EXPANDER(type) \ | 41 | #define DEV_IS_EXPANDER(type) \ |
40 | ((type == SAS_EDGE_EXPANDER_DEVICE) || \ | 42 | ((type == SAS_EDGE_EXPANDER_DEVICE) || \ |
@@ -135,6 +137,8 @@ struct hisi_sas_hw { | |||
135 | struct hisi_sas_tmf_task *tmf); | 137 | struct hisi_sas_tmf_task *tmf); |
136 | int (*prep_smp)(struct hisi_hba *hisi_hba, | 138 | int (*prep_smp)(struct hisi_hba *hisi_hba, |
137 | struct hisi_sas_slot *slot); | 139 | struct hisi_sas_slot *slot); |
140 | int (*prep_stp)(struct hisi_hba *hisi_hba, | ||
141 | struct hisi_sas_slot *slot); | ||
138 | int (*slot_complete)(struct hisi_hba *hisi_hba, | 142 | int (*slot_complete)(struct hisi_hba *hisi_hba, |
139 | struct hisi_sas_slot *slot, int abort); | 143 | struct hisi_sas_slot *slot, int abort); |
140 | void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no); | 144 | 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 c48df6df1ff8..406b515a54bb 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c | |||
@@ -107,6 +107,12 @@ static int hisi_sas_task_prep_ssp(struct hisi_hba *hisi_hba, | |||
107 | return hisi_hba->hw->prep_ssp(hisi_hba, slot, is_tmf, tmf); | 107 | return hisi_hba->hw->prep_ssp(hisi_hba, slot, is_tmf, tmf); |
108 | } | 108 | } |
109 | 109 | ||
110 | static int hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba, | ||
111 | struct hisi_sas_slot *slot) | ||
112 | { | ||
113 | return hisi_hba->hw->prep_stp(hisi_hba, slot); | ||
114 | } | ||
115 | |||
110 | static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, | 116 | static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, |
111 | int is_tmf, struct hisi_sas_tmf_task *tmf, | 117 | int is_tmf, struct hisi_sas_tmf_task *tmf, |
112 | int *pass) | 118 | int *pass) |
@@ -230,6 +236,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, | |||
230 | case SAS_PROTOCOL_SATA: | 236 | case SAS_PROTOCOL_SATA: |
231 | case SAS_PROTOCOL_STP: | 237 | case SAS_PROTOCOL_STP: |
232 | case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: | 238 | case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: |
239 | rc = hisi_sas_task_prep_ata(hisi_hba, slot); | ||
240 | break; | ||
233 | default: | 241 | default: |
234 | dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n", | 242 | dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n", |
235 | task->task_proto); | 243 | task->task_proto); |
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 8b51acf9e23d..cea0b369df5c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | |||
@@ -269,6 +269,12 @@ enum { | |||
269 | #define DIR_TO_DEVICE 2 | 269 | #define DIR_TO_DEVICE 2 |
270 | #define DIR_RESERVED 3 | 270 | #define DIR_RESERVED 3 |
271 | 271 | ||
272 | #define SATA_PROTOCOL_NONDATA 0x1 | ||
273 | #define SATA_PROTOCOL_PIO 0x2 | ||
274 | #define SATA_PROTOCOL_DMA 0x4 | ||
275 | #define SATA_PROTOCOL_FPDMA 0x8 | ||
276 | #define SATA_PROTOCOL_ATAPI 0x10 | ||
277 | |||
272 | static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) | 278 | static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) |
273 | { | 279 | { |
274 | void __iomem *regs = hisi_hba->regs + off; | 280 | void __iomem *regs = hisi_hba->regs + off; |
@@ -994,6 +1000,19 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba, | |||
994 | return 0; | 1000 | return 0; |
995 | } | 1001 | } |
996 | 1002 | ||
1003 | static void sata_done_v2_hw(struct hisi_hba *hisi_hba, struct sas_task *task, | ||
1004 | struct hisi_sas_slot *slot) | ||
1005 | { | ||
1006 | struct task_status_struct *ts = &task->task_status; | ||
1007 | struct ata_task_resp *resp = (struct ata_task_resp *)ts->buf; | ||
1008 | struct dev_to_host_fis *d2h = slot->status_buffer + | ||
1009 | sizeof(struct hisi_sas_err_record); | ||
1010 | |||
1011 | resp->frame_len = sizeof(struct dev_to_host_fis); | ||
1012 | memcpy(&resp->ending_fis[0], d2h, sizeof(struct dev_to_host_fis)); | ||
1013 | |||
1014 | ts->buf_valid_size = sizeof(*resp); | ||
1015 | } | ||
997 | static int | 1016 | static int |
998 | slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, | 1017 | slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, |
999 | int abort) | 1018 | int abort) |
@@ -1070,6 +1089,11 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, | |||
1070 | case SAS_PROTOCOL_SATA: | 1089 | case SAS_PROTOCOL_SATA: |
1071 | case SAS_PROTOCOL_STP: | 1090 | case SAS_PROTOCOL_STP: |
1072 | case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: | 1091 | case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: |
1092 | { | ||
1093 | ts->stat = SAM_STAT_GOOD; | ||
1094 | sata_done_v2_hw(hisi_hba, task, slot); | ||
1095 | break; | ||
1096 | } | ||
1073 | default: | 1097 | default: |
1074 | ts->stat = SAM_STAT_CHECK_CONDITION; | 1098 | ts->stat = SAM_STAT_CHECK_CONDITION; |
1075 | break; | 1099 | break; |
@@ -1094,6 +1118,143 @@ out: | |||
1094 | return sts; | 1118 | return sts; |
1095 | } | 1119 | } |
1096 | 1120 | ||
1121 | static u8 get_ata_protocol(u8 cmd, int direction) | ||
1122 | { | ||
1123 | switch (cmd) { | ||
1124 | case ATA_CMD_FPDMA_WRITE: | ||
1125 | case ATA_CMD_FPDMA_READ: | ||
1126 | return SATA_PROTOCOL_FPDMA; | ||
1127 | |||
1128 | case ATA_CMD_ID_ATA: | ||
1129 | case ATA_CMD_PMP_READ: | ||
1130 | case ATA_CMD_READ_LOG_EXT: | ||
1131 | case ATA_CMD_PIO_READ: | ||
1132 | case ATA_CMD_PIO_READ_EXT: | ||
1133 | case ATA_CMD_PMP_WRITE: | ||
1134 | case ATA_CMD_WRITE_LOG_EXT: | ||
1135 | case ATA_CMD_PIO_WRITE: | ||
1136 | case ATA_CMD_PIO_WRITE_EXT: | ||
1137 | return SATA_PROTOCOL_PIO; | ||
1138 | |||
1139 | case ATA_CMD_READ: | ||
1140 | case ATA_CMD_READ_EXT: | ||
1141 | case ATA_CMD_READ_LOG_DMA_EXT: | ||
1142 | case ATA_CMD_WRITE: | ||
1143 | case ATA_CMD_WRITE_EXT: | ||
1144 | case ATA_CMD_WRITE_QUEUED: | ||
1145 | case ATA_CMD_WRITE_LOG_DMA_EXT: | ||
1146 | return SATA_PROTOCOL_DMA; | ||
1147 | |||
1148 | case ATA_CMD_DOWNLOAD_MICRO: | ||
1149 | case ATA_CMD_DEV_RESET: | ||
1150 | case ATA_CMD_CHK_POWER: | ||
1151 | case ATA_CMD_FLUSH: | ||
1152 | case ATA_CMD_FLUSH_EXT: | ||
1153 | case ATA_CMD_VERIFY: | ||
1154 | case ATA_CMD_VERIFY_EXT: | ||
1155 | case ATA_CMD_SET_FEATURES: | ||
1156 | case ATA_CMD_STANDBY: | ||
1157 | case ATA_CMD_STANDBYNOW1: | ||
1158 | return SATA_PROTOCOL_NONDATA; | ||
1159 | default: | ||
1160 | if (direction == DMA_NONE) | ||
1161 | return SATA_PROTOCOL_NONDATA; | ||
1162 | return SATA_PROTOCOL_PIO; | ||
1163 | } | ||
1164 | } | ||
1165 | |||
1166 | static int get_ncq_tag_v2_hw(struct sas_task *task, u32 *tag) | ||
1167 | { | ||
1168 | struct ata_queued_cmd *qc = task->uldd_task; | ||
1169 | |||
1170 | if (qc) { | ||
1171 | if (qc->tf.command == ATA_CMD_FPDMA_WRITE || | ||
1172 | qc->tf.command == ATA_CMD_FPDMA_READ) { | ||
1173 | *tag = qc->tag; | ||
1174 | return 1; | ||
1175 | } | ||
1176 | } | ||
1177 | return 0; | ||
1178 | } | ||
1179 | |||
1180 | static int prep_ata_v2_hw(struct hisi_hba *hisi_hba, | ||
1181 | struct hisi_sas_slot *slot) | ||
1182 | { | ||
1183 | struct sas_task *task = slot->task; | ||
1184 | struct domain_device *device = task->dev; | ||
1185 | struct domain_device *parent_dev = device->parent; | ||
1186 | struct hisi_sas_device *sas_dev = device->lldd_dev; | ||
1187 | struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; | ||
1188 | struct hisi_sas_port *port = device->port->lldd_port; | ||
1189 | u8 *buf_cmd; | ||
1190 | int has_data = 0, rc = 0, hdr_tag = 0; | ||
1191 | u32 dw1 = 0, dw2 = 0; | ||
1192 | |||
1193 | /* create header */ | ||
1194 | /* dw0 */ | ||
1195 | hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF); | ||
1196 | if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) | ||
1197 | hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF); | ||
1198 | else | ||
1199 | hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF); | ||
1200 | |||
1201 | /* dw1 */ | ||
1202 | switch (task->data_dir) { | ||
1203 | case DMA_TO_DEVICE: | ||
1204 | has_data = 1; | ||
1205 | dw1 |= DIR_TO_DEVICE << CMD_HDR_DIR_OFF; | ||
1206 | break; | ||
1207 | case DMA_FROM_DEVICE: | ||
1208 | has_data = 1; | ||
1209 | dw1 |= DIR_TO_INI << CMD_HDR_DIR_OFF; | ||
1210 | break; | ||
1211 | default: | ||
1212 | dw1 &= ~CMD_HDR_DIR_MSK; | ||
1213 | } | ||
1214 | |||
1215 | if (0 == task->ata_task.fis.command) | ||
1216 | dw1 |= 1 << CMD_HDR_RESET_OFF; | ||
1217 | |||
1218 | dw1 |= (get_ata_protocol(task->ata_task.fis.command, task->data_dir)) | ||
1219 | << CMD_HDR_FRAME_TYPE_OFF; | ||
1220 | dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF; | ||
1221 | hdr->dw1 = cpu_to_le32(dw1); | ||
1222 | |||
1223 | /* dw2 */ | ||
1224 | if (task->ata_task.use_ncq && get_ncq_tag_v2_hw(task, &hdr_tag)) { | ||
1225 | task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); | ||
1226 | dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF; | ||
1227 | } | ||
1228 | |||
1229 | dw2 |= (HISI_SAS_MAX_STP_RESP_SZ / 4) << CMD_HDR_CFL_OFF | | ||
1230 | 2 << CMD_HDR_SG_MOD_OFF; | ||
1231 | hdr->dw2 = cpu_to_le32(dw2); | ||
1232 | |||
1233 | /* dw3 */ | ||
1234 | hdr->transfer_tags = cpu_to_le32(slot->idx); | ||
1235 | |||
1236 | if (has_data) { | ||
1237 | rc = prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter, | ||
1238 | slot->n_elem); | ||
1239 | if (rc) | ||
1240 | return rc; | ||
1241 | } | ||
1242 | |||
1243 | |||
1244 | hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len); | ||
1245 | hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma); | ||
1246 | hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma); | ||
1247 | |||
1248 | buf_cmd = slot->command_table; | ||
1249 | |||
1250 | if (likely(!task->ata_task.device_control_reg_update)) | ||
1251 | task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */ | ||
1252 | /* fill in command FIS */ | ||
1253 | memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis)); | ||
1254 | |||
1255 | return 0; | ||
1256 | } | ||
1257 | |||
1097 | static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) | 1258 | static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) |
1098 | { | 1259 | { |
1099 | int i, res = 0; | 1260 | int i, res = 0; |
@@ -1559,6 +1720,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = { | |||
1559 | .free_device = free_device_v2_hw, | 1720 | .free_device = free_device_v2_hw, |
1560 | .prep_smp = prep_smp_v2_hw, | 1721 | .prep_smp = prep_smp_v2_hw, |
1561 | .prep_ssp = prep_ssp_v2_hw, | 1722 | .prep_ssp = prep_ssp_v2_hw, |
1723 | .prep_stp = prep_ata_v2_hw, | ||
1562 | .get_free_slot = get_free_slot_v2_hw, | 1724 | .get_free_slot = get_free_slot_v2_hw, |
1563 | .start_delivery = start_delivery_v2_hw, | 1725 | .start_delivery = start_delivery_v2_hw, |
1564 | .slot_complete = slot_complete_v2_hw, | 1726 | .slot_complete = slot_complete_v2_hw, |