From 01e389737f72fb6ada37dfcf2c013535ff702d53 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 Signed-off-by: Alexander Winkowski --- 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 c3c933f1f14d..bd6a49910172 100755 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3503,7 +3503,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); @@ -3515,7 +3527,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; } /** @@ -4407,7 +4419,13 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *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 a7f722210694..88f841c6c99e 100755 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -1112,6 +1112,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;