diff options
author | Dolev Raviv <draviv@codeaurora.org> | 2014-06-29 02:40:17 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-07-25 17:17:01 -0400 |
commit | d44a5f98bb49b2c15348fa65cee73df4a157bfbf (patch) | |
tree | c4ac73142a1d3d199481af1ba72b76649652b7e3 | |
parent | 6d67726bd898151e688d8729b3997ba8417c2c6b (diff) |
ufs: query descriptor API
Introduces the API for sending queries with descriptors.
A descriptor is a block or page of parameters that describe the device.
The descriptors are classified into types and can range in size
from 2 bytes through 255 bytes.
All descriptors have a length value as their first element, and a type
identification element as their second byte.
All descriptors are readable and some may be write once.
They are accessed using their type, index and selector.
Signed-off-by: Dolev Raviv <draviv@codeaurora.org>
Signed-off-by: Raviv Shvili <rshvili@codeaurora.org>
Acked-by: Santosh Y <santoshsy@gmail.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r-- | drivers/scsi/ufs/ufs.h | 17 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 139 |
2 files changed, 128 insertions, 28 deletions
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index f42d1cee652a..1545cd7877d0 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h | |||
@@ -41,7 +41,8 @@ | |||
41 | 41 | ||
42 | #define MAX_CDB_SIZE 16 | 42 | #define MAX_CDB_SIZE 16 |
43 | #define GENERAL_UPIU_REQUEST_SIZE 32 | 43 | #define GENERAL_UPIU_REQUEST_SIZE 32 |
44 | #define QUERY_DESC_MAX_SIZE 256 | 44 | #define QUERY_DESC_MAX_SIZE 255 |
45 | #define QUERY_DESC_MIN_SIZE 2 | ||
45 | #define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - \ | 46 | #define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - \ |
46 | (sizeof(struct utp_upiu_header))) | 47 | (sizeof(struct utp_upiu_header))) |
47 | 48 | ||
@@ -117,6 +118,20 @@ enum attr_idn { | |||
117 | QUERY_ATTR_IDN_EE_STATUS = 0x0E, | 118 | QUERY_ATTR_IDN_EE_STATUS = 0x0E, |
118 | }; | 119 | }; |
119 | 120 | ||
121 | /* Descriptor idn for Query requests */ | ||
122 | enum desc_idn { | ||
123 | QUERY_DESC_IDN_DEVICE = 0x0, | ||
124 | QUERY_DESC_IDN_CONFIGURAION = 0x1, | ||
125 | QUERY_DESC_IDN_UNIT = 0x2, | ||
126 | QUERY_DESC_IDN_RFU_0 = 0x3, | ||
127 | QUERY_DESC_IDN_INTERCONNECT = 0x4, | ||
128 | QUERY_DESC_IDN_STRING = 0x5, | ||
129 | QUERY_DESC_IDN_RFU_1 = 0x6, | ||
130 | QUERY_DESC_IDN_GEOMETRY = 0x7, | ||
131 | QUERY_DESC_IDN_POWER = 0x8, | ||
132 | QUERY_DESC_IDN_RFU_2 = 0x9, | ||
133 | }; | ||
134 | |||
120 | /* Exception event mask values */ | 135 | /* Exception event mask values */ |
121 | enum { | 136 | enum { |
122 | MASK_EE_STATUS = 0xFFFF, | 137 | MASK_EE_STATUS = 0xFFFF, |
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 0c2877251251..ed533f43f231 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c | |||
@@ -459,7 +459,7 @@ void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) | |||
459 | 459 | ||
460 | /* Get the descriptor */ | 460 | /* Get the descriptor */ |
461 | if (lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) { | 461 | if (lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) { |
462 | u8 *descp = (u8 *)&lrbp->ucd_rsp_ptr + | 462 | u8 *descp = (u8 *)lrbp->ucd_rsp_ptr + |
463 | GENERAL_UPIU_REQUEST_SIZE; | 463 | GENERAL_UPIU_REQUEST_SIZE; |
464 | u16 len; | 464 | u16 len; |
465 | 465 | ||
@@ -1134,6 +1134,30 @@ out_put_tag: | |||
1134 | } | 1134 | } |
1135 | 1135 | ||
1136 | /** | 1136 | /** |
1137 | * ufshcd_init_query() - init the query response and request parameters | ||
1138 | * @hba: per-adapter instance | ||
1139 | * @request: address of the request pointer to be initialized | ||
1140 | * @response: address of the response pointer to be initialized | ||
1141 | * @opcode: operation to perform | ||
1142 | * @idn: flag idn to access | ||
1143 | * @index: LU number to access | ||
1144 | * @selector: query/flag/descriptor further identification | ||
1145 | */ | ||
1146 | static inline void ufshcd_init_query(struct ufs_hba *hba, | ||
1147 | struct ufs_query_req **request, struct ufs_query_res **response, | ||
1148 | enum query_opcode opcode, u8 idn, u8 index, u8 selector) | ||
1149 | { | ||
1150 | *request = &hba->dev_cmd.query.request; | ||
1151 | *response = &hba->dev_cmd.query.response; | ||
1152 | memset(*request, 0, sizeof(struct ufs_query_req)); | ||
1153 | memset(*response, 0, sizeof(struct ufs_query_res)); | ||
1154 | (*request)->upiu_req.opcode = opcode; | ||
1155 | (*request)->upiu_req.idn = idn; | ||
1156 | (*request)->upiu_req.index = index; | ||
1157 | (*request)->upiu_req.selector = selector; | ||
1158 | } | ||
1159 | |||
1160 | /** | ||
1137 | * ufshcd_query_flag() - API function for sending flag query requests | 1161 | * ufshcd_query_flag() - API function for sending flag query requests |
1138 | * hba: per-adapter instance | 1162 | * hba: per-adapter instance |
1139 | * query_opcode: flag query to perform | 1163 | * query_opcode: flag query to perform |
@@ -1145,17 +1169,15 @@ out_put_tag: | |||
1145 | static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, | 1169 | static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, |
1146 | enum flag_idn idn, bool *flag_res) | 1170 | enum flag_idn idn, bool *flag_res) |
1147 | { | 1171 | { |
1148 | struct ufs_query_req *request; | 1172 | struct ufs_query_req *request = NULL; |
1149 | struct ufs_query_res *response; | 1173 | struct ufs_query_res *response = NULL; |
1150 | int err; | 1174 | int err, index = 0, selector = 0; |
1151 | 1175 | ||
1152 | BUG_ON(!hba); | 1176 | BUG_ON(!hba); |
1153 | 1177 | ||
1154 | mutex_lock(&hba->dev_cmd.lock); | 1178 | mutex_lock(&hba->dev_cmd.lock); |
1155 | request = &hba->dev_cmd.query.request; | 1179 | ufshcd_init_query(hba, &request, &response, opcode, idn, index, |
1156 | response = &hba->dev_cmd.query.response; | 1180 | selector); |
1157 | memset(request, 0, sizeof(struct ufs_query_req)); | ||
1158 | memset(response, 0, sizeof(struct ufs_query_res)); | ||
1159 | 1181 | ||
1160 | switch (opcode) { | 1182 | switch (opcode) { |
1161 | case UPIU_QUERY_OPCODE_SET_FLAG: | 1183 | case UPIU_QUERY_OPCODE_SET_FLAG: |
@@ -1180,12 +1202,8 @@ static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, | |||
1180 | err = -EINVAL; | 1202 | err = -EINVAL; |
1181 | goto out_unlock; | 1203 | goto out_unlock; |
1182 | } | 1204 | } |
1183 | request->upiu_req.opcode = opcode; | ||
1184 | request->upiu_req.idn = idn; | ||
1185 | 1205 | ||
1186 | /* Send query request */ | 1206 | err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); |
1187 | err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, | ||
1188 | QUERY_REQ_TIMEOUT); | ||
1189 | 1207 | ||
1190 | if (err) { | 1208 | if (err) { |
1191 | dev_err(hba->dev, | 1209 | dev_err(hba->dev, |
@@ -1217,8 +1235,8 @@ out_unlock: | |||
1217 | static int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, | 1235 | static int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, |
1218 | enum attr_idn idn, u8 index, u8 selector, u32 *attr_val) | 1236 | enum attr_idn idn, u8 index, u8 selector, u32 *attr_val) |
1219 | { | 1237 | { |
1220 | struct ufs_query_req *request; | 1238 | struct ufs_query_req *request = NULL; |
1221 | struct ufs_query_res *response; | 1239 | struct ufs_query_res *response = NULL; |
1222 | int err; | 1240 | int err; |
1223 | 1241 | ||
1224 | BUG_ON(!hba); | 1242 | BUG_ON(!hba); |
@@ -1231,10 +1249,8 @@ static int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, | |||
1231 | } | 1249 | } |
1232 | 1250 | ||
1233 | mutex_lock(&hba->dev_cmd.lock); | 1251 | mutex_lock(&hba->dev_cmd.lock); |
1234 | request = &hba->dev_cmd.query.request; | 1252 | ufshcd_init_query(hba, &request, &response, opcode, idn, index, |
1235 | response = &hba->dev_cmd.query.response; | 1253 | selector); |
1236 | memset(request, 0, sizeof(struct ufs_query_req)); | ||
1237 | memset(response, 0, sizeof(struct ufs_query_res)); | ||
1238 | 1254 | ||
1239 | switch (opcode) { | 1255 | switch (opcode) { |
1240 | case UPIU_QUERY_OPCODE_WRITE_ATTR: | 1256 | case UPIU_QUERY_OPCODE_WRITE_ATTR: |
@@ -1251,14 +1267,7 @@ static int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, | |||
1251 | goto out_unlock; | 1267 | goto out_unlock; |
1252 | } | 1268 | } |
1253 | 1269 | ||
1254 | request->upiu_req.opcode = opcode; | 1270 | err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); |
1255 | request->upiu_req.idn = idn; | ||
1256 | request->upiu_req.index = index; | ||
1257 | request->upiu_req.selector = selector; | ||
1258 | |||
1259 | /* Send query request */ | ||
1260 | err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, | ||
1261 | QUERY_REQ_TIMEOUT); | ||
1262 | 1271 | ||
1263 | if (err) { | 1272 | if (err) { |
1264 | dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, err = %d\n", | 1273 | dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, err = %d\n", |
@@ -1275,6 +1284,82 @@ out: | |||
1275 | } | 1284 | } |
1276 | 1285 | ||
1277 | /** | 1286 | /** |
1287 | * ufshcd_query_descriptor - API function for sending descriptor requests | ||
1288 | * hba: per-adapter instance | ||
1289 | * opcode: attribute opcode | ||
1290 | * idn: attribute idn to access | ||
1291 | * index: index field | ||
1292 | * selector: selector field | ||
1293 | * desc_buf: the buffer that contains the descriptor | ||
1294 | * buf_len: length parameter passed to the device | ||
1295 | * | ||
1296 | * Returns 0 for success, non-zero in case of failure. | ||
1297 | * The buf_len parameter will contain, on return, the length parameter | ||
1298 | * received on the response. | ||
1299 | */ | ||
1300 | int ufshcd_query_descriptor(struct ufs_hba *hba, | ||
1301 | enum query_opcode opcode, enum desc_idn idn, u8 index, | ||
1302 | u8 selector, u8 *desc_buf, int *buf_len) | ||
1303 | { | ||
1304 | struct ufs_query_req *request = NULL; | ||
1305 | struct ufs_query_res *response = NULL; | ||
1306 | int err; | ||
1307 | |||
1308 | BUG_ON(!hba); | ||
1309 | |||
1310 | if (!desc_buf) { | ||
1311 | dev_err(hba->dev, "%s: descriptor buffer required for opcode 0x%x\n", | ||
1312 | __func__, opcode); | ||
1313 | err = -EINVAL; | ||
1314 | goto out; | ||
1315 | } | ||
1316 | |||
1317 | if (*buf_len <= QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) { | ||
1318 | dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n", | ||
1319 | __func__, *buf_len); | ||
1320 | err = -EINVAL; | ||
1321 | goto out; | ||
1322 | } | ||
1323 | |||
1324 | mutex_lock(&hba->dev_cmd.lock); | ||
1325 | ufshcd_init_query(hba, &request, &response, opcode, idn, index, | ||
1326 | selector); | ||
1327 | hba->dev_cmd.query.descriptor = desc_buf; | ||
1328 | request->upiu_req.length = *buf_len; | ||
1329 | |||
1330 | switch (opcode) { | ||
1331 | case UPIU_QUERY_OPCODE_WRITE_DESC: | ||
1332 | request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; | ||
1333 | break; | ||
1334 | case UPIU_QUERY_OPCODE_READ_DESC: | ||
1335 | request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; | ||
1336 | break; | ||
1337 | default: | ||
1338 | dev_err(hba->dev, | ||
1339 | "%s: Expected query descriptor opcode but got = 0x%.2x\n", | ||
1340 | __func__, opcode); | ||
1341 | err = -EINVAL; | ||
1342 | goto out_unlock; | ||
1343 | } | ||
1344 | |||
1345 | err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); | ||
1346 | |||
1347 | if (err) { | ||
1348 | dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, err = %d\n", | ||
1349 | __func__, opcode, idn, err); | ||
1350 | goto out_unlock; | ||
1351 | } | ||
1352 | |||
1353 | hba->dev_cmd.query.descriptor = NULL; | ||
1354 | *buf_len = response->upiu_res.length; | ||
1355 | |||
1356 | out_unlock: | ||
1357 | mutex_unlock(&hba->dev_cmd.lock); | ||
1358 | out: | ||
1359 | return err; | ||
1360 | } | ||
1361 | |||
1362 | /** | ||
1278 | * ufshcd_memory_alloc - allocate memory for host memory space data structures | 1363 | * ufshcd_memory_alloc - allocate memory for host memory space data structures |
1279 | * @hba: per adapter instance | 1364 | * @hba: per adapter instance |
1280 | * | 1365 | * |