diff options
author | Dolev Raviv <draviv@codeaurora.org> | 2014-06-29 02:40:18 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-07-25 17:17:01 -0400 |
commit | c6d4a83177d1c45ec42d65ff48d85fb5b74cb526 (patch) | |
tree | d39430d5f4f216915c14fb5eb26f6e3b9f7ecd7a /drivers/scsi/ufs/ufshcd.c | |
parent | d44a5f98bb49b2c15348fa65cee73df4a157bfbf (diff) |
ufs: device query status and size check
Check query response status before copying the response.
Add descriptor query response size check, before copying it to buffer.
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>
Diffstat (limited to 'drivers/scsi/ufs/ufshcd.c')
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 49 |
1 files changed, 32 insertions, 17 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index ed533f43f231..f3768ec25c2f 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c | |||
@@ -446,30 +446,34 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp) | |||
446 | * @lrb - pointer to local reference block | 446 | * @lrb - pointer to local reference block |
447 | */ | 447 | */ |
448 | static | 448 | static |
449 | void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) | 449 | int ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) |
450 | { | 450 | { |
451 | struct ufs_query_res *query_res = &hba->dev_cmd.query.response; | 451 | struct ufs_query_res *query_res = &hba->dev_cmd.query.response; |
452 | 452 | ||
453 | /* Get the UPIU response */ | ||
454 | query_res->response = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr) >> | ||
455 | UPIU_RSP_CODE_OFFSET; | ||
456 | |||
457 | memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr, QUERY_OSF_SIZE); | 453 | memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr, QUERY_OSF_SIZE); |
458 | 454 | ||
459 | |||
460 | /* Get the descriptor */ | 455 | /* Get the descriptor */ |
461 | if (lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) { | 456 | if (lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) { |
462 | u8 *descp = (u8 *)lrbp->ucd_rsp_ptr + | 457 | u8 *descp = (u8 *)lrbp->ucd_rsp_ptr + |
463 | GENERAL_UPIU_REQUEST_SIZE; | 458 | GENERAL_UPIU_REQUEST_SIZE; |
464 | u16 len; | 459 | u16 resp_len; |
460 | u16 buf_len; | ||
465 | 461 | ||
466 | /* data segment length */ | 462 | /* data segment length */ |
467 | len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) & | 463 | resp_len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) & |
468 | MASK_QUERY_DATA_SEG_LEN; | 464 | MASK_QUERY_DATA_SEG_LEN; |
469 | 465 | buf_len = hba->dev_cmd.query.request.upiu_req.length; | |
470 | memcpy(hba->dev_cmd.query.descriptor, descp, | 466 | if (likely(buf_len >= resp_len)) { |
471 | min_t(u16, len, QUERY_DESC_MAX_SIZE)); | 467 | memcpy(hba->dev_cmd.query.descriptor, descp, resp_len); |
468 | } else { | ||
469 | dev_warn(hba->dev, | ||
470 | "%s: Response size is bigger than buffer", | ||
471 | __func__); | ||
472 | return -EINVAL; | ||
473 | } | ||
472 | } | 474 | } |
475 | |||
476 | return 0; | ||
473 | } | 477 | } |
474 | 478 | ||
475 | /** | 479 | /** |
@@ -797,11 +801,9 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, | |||
797 | QUERY_OSF_SIZE); | 801 | QUERY_OSF_SIZE); |
798 | 802 | ||
799 | /* Copy the Descriptor */ | 803 | /* Copy the Descriptor */ |
800 | if ((len > 0) && (query->request.upiu_req.opcode == | 804 | if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) |
801 | UPIU_QUERY_OPCODE_WRITE_DESC)) { | 805 | memcpy(descp, query->descriptor, len); |
802 | memcpy(descp, query->descriptor, | 806 | |
803 | min_t(u16, len, QUERY_DESC_MAX_SIZE)); | ||
804 | } | ||
805 | } | 807 | } |
806 | 808 | ||
807 | static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp) | 809 | static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp) |
@@ -980,6 +982,17 @@ ufshcd_clear_cmd(struct ufs_hba *hba, int tag) | |||
980 | return err; | 982 | return err; |
981 | } | 983 | } |
982 | 984 | ||
985 | static int | ||
986 | ufshcd_check_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) | ||
987 | { | ||
988 | struct ufs_query_res *query_res = &hba->dev_cmd.query.response; | ||
989 | |||
990 | /* Get the UPIU response */ | ||
991 | query_res->response = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr) >> | ||
992 | UPIU_RSP_CODE_OFFSET; | ||
993 | return query_res->response; | ||
994 | } | ||
995 | |||
983 | /** | 996 | /** |
984 | * ufshcd_dev_cmd_completion() - handles device management command responses | 997 | * ufshcd_dev_cmd_completion() - handles device management command responses |
985 | * @hba: per adapter instance | 998 | * @hba: per adapter instance |
@@ -1002,7 +1015,9 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) | |||
1002 | } | 1015 | } |
1003 | break; | 1016 | break; |
1004 | case UPIU_TRANSACTION_QUERY_RSP: | 1017 | case UPIU_TRANSACTION_QUERY_RSP: |
1005 | ufshcd_copy_query_response(hba, lrbp); | 1018 | err = ufshcd_check_query_response(hba, lrbp); |
1019 | if (!err) | ||
1020 | err = ufshcd_copy_query_response(hba, lrbp); | ||
1006 | break; | 1021 | break; |
1007 | case UPIU_TRANSACTION_REJECT_UPIU: | 1022 | case UPIU_TRANSACTION_REJECT_UPIU: |
1008 | /* TODO: handle Reject UPIU Response */ | 1023 | /* TODO: handle Reject UPIU Response */ |