Commit 14497328 authored by Yaniv Gardi's avatar Yaniv Gardi Committed by Martin K. Petersen

scsi: ufs: verify command tag validity

A race condition appear to exist between request completion when
scsi_done() is called to end the request and set the tag back to -1 (at
blk_queue_end_tag() scsi_end_request), and scsi layer error handling
which aborts the command and reuses it to request sense data. Sending
the request sense is done with tag which was set to -1 and so it is
invalid.  Assert command tag passed from scsi layer is valid.
Reviewed-by: default avatarSubhash Jadavani <subhashj@codeaurora.org>
Reviewed-by: default avatarDolev Raviv <draviv@codeaurora.org>
Signed-off-by: default avatarGilad Broner <gbroner@codeaurora.org>
Signed-off-by: default avatarYaniv Gardi <ygardi@codeaurora.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 51047266
...@@ -190,6 +190,10 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba, ...@@ -190,6 +190,10 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *desired_pwr_mode); struct ufs_pa_layer_attr *desired_pwr_mode);
static int ufshcd_change_power_mode(struct ufs_hba *hba, static int ufshcd_change_power_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *pwr_mode); struct ufs_pa_layer_attr *pwr_mode);
static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
{
return tag >= 0 && tag < hba->nutrs;
}
static inline int ufshcd_enable_irq(struct ufs_hba *hba) static inline int ufshcd_enable_irq(struct ufs_hba *hba)
{ {
...@@ -1309,6 +1313,12 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) ...@@ -1309,6 +1313,12 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
hba = shost_priv(host); hba = shost_priv(host);
tag = cmd->request->tag; tag = cmd->request->tag;
if (!ufshcd_valid_tag(hba, tag)) {
dev_err(hba->dev,
"%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p",
__func__, tag, cmd, cmd->request);
BUG();
}
spin_lock_irqsave(hba->host->host_lock, flags); spin_lock_irqsave(hba->host->host_lock, flags);
switch (hba->ufshcd_state) { switch (hba->ufshcd_state) {
...@@ -3861,13 +3871,23 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) ...@@ -3861,13 +3871,23 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
host = cmd->device->host; host = cmd->device->host;
hba = shost_priv(host); hba = shost_priv(host);
tag = cmd->request->tag; tag = cmd->request->tag;
if (!ufshcd_valid_tag(hba, tag)) {
dev_err(hba->dev,
"%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p",
__func__, tag, cmd, cmd->request);
BUG();
}
ufshcd_hold(hba, false); ufshcd_hold(hba, false);
reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
/* If command is already aborted/completed, return SUCCESS */ /* If command is already aborted/completed, return SUCCESS */
if (!(test_bit(tag, &hba->outstanding_reqs))) if (!(test_bit(tag, &hba->outstanding_reqs))) {
dev_err(hba->dev,
"%s: cmd at tag %d already completed, outstanding=0x%lx, doorbell=0x%x\n",
__func__, tag, hba->outstanding_reqs, reg);
goto out; goto out;
}
reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
if (!(reg & (1 << tag))) { if (!(reg & (1 << tag))) {
dev_err(hba->dev, dev_err(hba->dev,
"%s: cmd was completed, but without a notifying intr, tag = %d", "%s: cmd was completed, but without a notifying intr, tag = %d",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment