aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ufs/ufshcd.c
diff options
context:
space:
mode:
authorDolev Raviv <draviv@codeaurora.org>2014-06-29 02:40:18 -0400
committerChristoph Hellwig <hch@lst.de>2014-07-25 17:17:01 -0400
commitc6d4a83177d1c45ec42d65ff48d85fb5b74cb526 (patch)
treed39430d5f4f216915c14fb5eb26f6e3b9f7ecd7a /drivers/scsi/ufs/ufshcd.c
parentd44a5f98bb49b2c15348fa65cee73df4a157bfbf (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.c49
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 */
448static 448static
449void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) 449int 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
807static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp) 809static 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
985static int
986ufshcd_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 */