From a89f6fea7190b93229e19829b63f207bbac1071b Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 24 May 2018 23:06:58 -0700 Subject: [PATCH] scsi: ufs: Disallow SECURITY_PROTOCOL_IN without _OUT This merged the following fix: 6a317b49c98c ("scsi: ufs: revise commit ecd2676bd513 ("disallow SECURITY_PROTOCOL_IN without _OUT")") If we allow this, Hynix will give timeout due to spec violation. The latest Hynix controller gives error instead of timeout. Bug: 113580864 Bug: 79898356 Bug: 109850759 Bug: 117682499 Bug: 112560467 Change-Id: Ie7820a9604e4c7bc4cc530acf41bb5bb72f33d5b Signed-off-by: Jaegeuk Kim Signed-off-by: Randall Huang --- drivers/scsi/ufs/ufshcd.c | 24 +++++++++++++++++++++--- drivers/scsi/ufs/ufshcd.h | 2 ++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 0d31d95c521c..4ab365b30dcc 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3099,7 +3099,19 @@ static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba) static inline int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) { - int ret = 0; + if (hba->lrb[task_tag].cmd) { + u8 opcode = (u8)(*hba->lrb[task_tag].cmd->cmnd); + + if (opcode == SECURITY_PROTOCOL_OUT && hba->security_in) { + hba->security_in--; + } else if (opcode == SECURITY_PROTOCOL_IN) { + if (hba->security_in) { + WARN_ON(1); + return -EINVAL; + } + hba->security_in++; + } + } hba->lrb[task_tag].issue_time_stamp = ktime_get(); hba->lrb[task_tag].complete_time_stamp = ktime_set(0, 0); @@ -3111,7 +3123,7 @@ int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) ufshcd_cond_add_cmd_trace(hba, task_tag, hba->lrb[task_tag].cmd ? "scsi_send" : "dev_cmd_send"); ufshcd_update_tag_stats(hba, task_tag); - return ret; + return 0; } /** @@ -3959,7 +3971,13 @@ send_orig_cmd: ufshcd_vops_pm_qos_req_end(hba, cmd->request, true); dev_err(hba->dev, "%s: failed sending command, %d\n", __func__, err); - err = DID_ERROR; + if (err == -EINVAL) { + set_host_byte(cmd, DID_ERROR); + if (has_read_lock) + ufshcd_put_read_lock(hba); + cmd->scsi_done(cmd); + return 0; + } goto out; } diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 4a3d71e974f6..6a80afed85bc 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -996,6 +996,8 @@ struct ufs_hba { /* Number of requests aborts */ int req_abort_count; + u32 security_in; + /* Number of lanes available (1 or 2) for Rx/Tx */ u32 lanes_per_direction;