Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+22 −2
Original line number Diff line number Diff line
@@ -190,6 +190,10 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
		struct ufs_pa_layer_attr *desired_pwr_mode);
static int ufshcd_change_power_mode(struct ufs_hba *hba,
			     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)
{
@@ -1309,6 +1313,12 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
	hba = shost_priv(host);

	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);
	switch (hba->ufshcd_state) {
@@ -3861,13 +3871,23 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
	host = cmd->device->host;
	hba = shost_priv(host);
	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);
	reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
	/* 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;
	}

	reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
	if (!(reg & (1 << tag))) {
		dev_err(hba->dev,
		"%s: cmd was completed, but without a notifying intr, tag = %d",